Skip to content

Hexagonal architecture

The platform follows strict hexagonal architecture (ports and adapters). This is what keeps the domain testable and lets you extend the platform without forking it.

┌─────────────────────────────────────────┐
│ User Interfaces │
│ (CLI, Web UI, REST API) │
└──────────────┬──────────────────────────┘
┌──────────────▼──────────────────────────┐
│ Application Layer │
│ (Use cases, services, orchestration) │
└──────────────┬──────────────────────────┘
┌──────────────▼──────────────────────────┐
│ Domain Layer │
│ (Entities, Ports / Interfaces) │
└──────────────┬──────────────────────────┘
┌──────────────▼──────────────────────────┐
│ Infrastructure Layer │
│ (Adapters: DB, API, file system) │
└─────────────────────────────────────────┘

Where things live

  • Ports (interfaces) live in packages/platform-domain/**/ports/. The domain package is infrastructure-free — no drizzle-orm, pg-boss, fs, or http imports.
  • Adapters (concrete implementations) live in apps/api/**/adapters/.

For example, the job runtime defines IJobRepository, IJobRunner, and IWorkflowStep as ports; DrizzleJobRepository, PgBossJobRunner, and the concrete steps are adapters.

The extension surface

The ports are the extension surface. You extend the platform by implementing one:

Implement……to add
IWorkflowStep / BaseWorkflowStepa new pipeline step
IExportTargeta new export destination
ISourceReadera new ingestion source
ILlmClienta new LLM provider

See Extend the platform for a worked example.