Jahangir Nabin
← All projects

Event-Driven Content Platform for a Global Automotive Client

The platform behind the chatbot: a .NET 9 modular monolith of 11 services with transactional-outbox messaging into Kafka, an admin panel, and a mobile BFF, delivered under my team leadership.

Role:
Team lead and primary engineer: content platform, admin panel (backend and frontend), and sole author of the mobile BFF
Period:
2025 – 2026, Brain Station 23
  • .NET 9
  • PostgreSQL 17
  • Kafka
  • MassTransit
  • Keycloak
  • React/Next.js
  • Redis
  • Quartz
  • Testcontainers
11
Bounded services
4,300+
Backend test methods
4
Delivery surfaces

Context

A global automotive client needed one platform to manage vehicle content (manuals, guides, notifications) and deliver it consistently to every surface a driver touches: an administration panel for content teams, a mobile app, and the AI chatbot that answers questions from that content. This case study covers the platform side; the retrieval system has its own case study.

Architecture

Surfaces
Admin panel (Next.js/React)
Mobile BFF (.NET 9)
Companion mobile app
AI chatbot (consumer)
Platform
Modular monolith, 11 services
Keycloak OIDC
REST APIs
Messaging
Transactional outbox
LISTEN/NOTIFY push
Quartz sweep fallback
MassTransit → Kafka
Data & Quality
PostgreSQL 17
Redis
Testcontainers
Architecture tests
SonarQube CI

Key decisions

Modular monolith over microservices. Eleven bounded services in one deployable: service boundaries are real, enforced by automated architecture tests that fail the build on illegal imports, but there's no distributed-system tax on a team of this size. The seams exist for the day extraction is worth it.

Messages that cannot be lost. Content changes publish through a transactional outbox: the event commits in the same PostgreSQL transaction as the data, then PostgreSQL LISTEN/NOTIFY pushes it to the dispatcher with a Quartz sweep as the fallback for anything missed. MassTransit carries it into Kafka. A crashed process or a dropped connection delays a message; it never silently loses one.

One identity provider for every surface. Keycloak OIDC fronts the admin panel, the BFF, and service-to-service calls. No per-app auth reinvention, and operator access is centrally revocable.

A BFF, not a general API, for mobile. The mobile app talks to a dedicated .NET 9 backend-for-frontend that aggregates and shapes platform data per screen, so mobile releases stop being hostage to platform API changes.

Quality gates that bite. 4,300+ backend test methods, including Testcontainers-backed integration suites and the architecture-boundary checks, with SonarQube on CI, plus a live contract test proving the content platform's output matches what the chatbot's ingestion expects.

Latest additions (Sep – Oct 2026)

  • Website sources for the chatbot. A new domain for brand and vehicle URLs, with a host allow-list, crawl runs and a "Run crawl now" button. It feeds the chatbot's labelled web index and is running on the dev server.
  • Each brand picks its AI. OpenAI, Anthropic or Gemini per brand, with per-1M-token prices in the dropdown. The admin can see whether the chatbot accepted the choice.
  • Analytics that answer "what does AI cost us?" Active users with a drill-down, and an estimated AI cost covering chat, weather tips and content embedding. Plus sortable question grids, per-variant ratings and feedback filters.
  • Safer admin work. Smart delete for brands and regions created by mistake, dealer-locator links per region, and support-handoff settings with a verified recipient.
  • Privacy operations. A GDPR erasure runbook across every service, and legal pages in 4 languages.

Results

The platform feeds four surfaces from one source of truth, with content changes propagating through the outbox-to-Kafka pipeline and every service behind a single identity provider. The admin panel ships content-team workflows end to end, and the companion mobile app is delivered through the BFF under my team leadership.

What I'd do differently

Build outbox observability sooner: dispatch lag, dead-letter visibility, and replay tooling. The pattern guarantees delivery, but operating it confidently requires seeing it, and we added that instrumentation later than we should have.