Skip to main content

Architecture overview

Constellation is a Turborepo monorepo of independent modules (apps) sitting on top of shared platform packages. Each module owns its own database schema and exposes a Zod-validated HTTP API.

System context (C4 L1)

The platform sits between two human-facing audiences (developers / operators using a browser, AI coding agents using MCP) and a small set of external systems.

Containers (C4 L2)

Inside the platform boundary, three Next.js apps share a single Postgres instance (schema-per-module) and an object store. The Directory app serves as the root zone and rewrites /catalog/* and /projects/* to the sub-zone apps. A separate MCP server exposes the Project Tracker REST API to agents over stdio. The docs site (this site) is its own Vercel project.

Source layout

apps/
directory/ → identity, orgs, users, roles (schema: identity)
catalog/ → PIM, CPQ, supplier offers (schema: catalog)
project-tracker/ → programmes, projects, tasks (schema: projects)
docs/ → this site (Docusaurus)

packages/
platform/auth-core → JWT, clearance, permission types
platform/auth-next → Next.js auth + tenant middleware
platform/db → tenant-scoped Prisma, RLS helpers
platform/events → outbox event publishing
platform/audit → transactional audit helper
platform/jobs → job queue abstraction
platform/storage → S3 / MinIO adapter
platform/ai-core → AI primitives (provider abstraction)
platform/ai-embeddings → AI primitives (embedding APIs)
platform/ai-rag → AI primitives (retrieval-augmented generation)
contracts/ → shared Zod schemas + types
ui/ → shared React components

Apps never import from other apps. Cross-module communication happens via events (append-only contracts) and typed service contracts exposed by each module.

Core invariants

Each invariant has a stable anchor on the Rules & invariants page — link to those when reviewing or citing a rule, not to this summary.

  • module-isolation — Single Postgres, schema-per-module. RLS enforces tenant isolation at the database layer.
  • tenant-context — Every query runs under app.tenant_id. Set transaction-locally by withTenantContext() in the tools layer; routes pre-validate the membership via withTenantAuth before any tool runs.
  • no-any — Zod schemas define the wire format; TypeScript types derive via z.infer.
  • events-append-only — Domain events are the public contract between modules. Naming follows event-naming.
  • audit-critical — Use auditCritical() from @constellation-platform/audit for mutations that must be forensically replayable.
  • no-cross-app-imports — Apps never import from other apps; cross-module communication via events + typed contracts only.

Full specs

The canonical architecture documents: