Skip to main content

Running the backend

The same image and codebase expose three production entrypoints plus a CLI.

ProcessEntrynpm/yarn scriptRole
APIsrc/main.tsyarn start:api / yarn devHTTP, Swagger when not production, WebSocket adapter
Workersrc/main.worker.tsyarn start:workerBull processors and OutboxDispatcherService
Schedulersrc/main.scheduler.tsyarn start:schedulerCron ticks that enqueue work or run maintenance
CLIsrc/cli.tsyarn seed:demonestjs-command

Production equivalents: yarn start:prod, yarn start:worker:prod, yarn start:scheduler:prod (node dist/main, dist/main.worker, dist/main.scheduler).

docker-compose.yml runs API, worker, and scheduler from one image with different commands. Compose comments require yarn migrate:deploy before the API health check can pass. Containers force APP_LOG_LEVEL default info even if .env says debug.

What each process loads​

AppModule imports CoreModule, the five area modules, and IntegrationsModule. WorkerModule also imports OutboxDispatchModule. The dispatcher is not loaded by the API module.

EventEmitterModule is registered from common infrastructure, which both API and worker import. A listener runs only in the process that loaded its module. Outbox handlers must be loaded by the worker. An in-process emit on the API is invisible to a worker-only listener.

PartitionMaintenanceService is loaded from the worker module, so its cron runs on the worker, not on the scheduler process.

Scheduler replica count

AI_CONTEXT.md says the scheduler must stay single-replica. Whether the deploy workflow enforces that was not confirmed. See Open questions.

Health​

GET /health is version-neutral and public. Prometheus metrics are at /metrics and bypass the JWT guard. Confirm a network policy so /metrics is not public. That policy is unknown from the application code alone.