Architecture
At a high level, ForgeStack is a monorepo with a Next.js frontend and one or more NestJS backend services, all sitting behind a single Caddy reverse proxy. The frontend handles the UI; the backend owns the business logic and the data. Services don't call each other directly. Instead they talk through events on Kafka, which keeps them decoupled and lets you split one service into several as the system grows.
The pieces
- Frontend — an easily extendable Next.js app that comes with a landing page, docs, auth flows and a simple dashboard. See Frontend.
- Backend services — NestJS services that hold the business logic. A service is split into isolated bounded contexts, and how the code inside is organized is covered in the Backend section.
- Kafka — the event broker. Bounded contexts (and services) talk to each other by publishing and consuming events here, never by calling directly.
- Databases — MongoDB for storage and Redis for caching (PostgreSQL coming soon). See Databases.
- Observability — Prometheus, Loki, Tempo and Grafana collect metrics, logs and traces from every service out of the box. See Monitoring.
- Caddy — the single entry point. It terminates TLS and routes each hostname to the right service. See Deployment.
Bounded contexts are separate systems
The most important idea to internalize: a bounded context is its own little system. The fact that several of them might live inside the same NestJS service right now is just a deployment detail. They don't share code, they don't share a database, and they never call into each other directly.
Why go to that trouble? Because it means you can pull any context out into its own microservice the day it needs to scale on its own, and nothing else has to change. The other contexts were already treating it as a remote system, so "remote" is just where it actually lives now.
Contexts talk to each other only by publishing integration events to Kafka — versioned, serializable messages that act as a public contract, with no domain internals leaking across the boundary. ForgeStack also keeps this reliable with a transactional outbox and an idempotent inbox. All of that, and the distinction between integration events and the in-process domain events used within a context, is covered in Event-Driven Architecture.
Where to go next
- Project Structure — the concrete folder layout and shared libraries.
- Backend — how the code inside a service is organized (DDD, CQRS, layers).
- Databases — the datastores and how they're wired.
- Monitoring — metrics, logs and traces in Grafana.