Infrastructure

The monorepo is wired together by Docker Compose and a small set of root scripts. The goal is that one command brings up every service — each with its own database and Redis — reproducibly.

Docker Compose

stackr generates three compose files:

FilePurpose
docker-compose.ymlLocal development — every service backend + its own Postgres and Redis
docker-compose.test.ymlEphemeral databases for the component and e2e test profiles
docker-compose.prod.ymlProduction overlay, applied on top of the base file
npm run docker:dev    # docker compose up -d
npm run docker:prod   # base + prod overlay

Setup

npm run setup (run once after generating) installs dependencies in every workspace, generates .env files, and offers to reset stale Docker volumes left over from a previous run.

Ports

Ports are allocated deterministically so committed scripts and CI stay reproducible:

PortAssignment
8888 / 3333Auth backend / admin dashboard (fixed)
8080, 8081, 8082, …Base backends (contiguous)
3000, 3001, 3002, …Base web frontends (contiguous)
+10000Test profile offset (db 15432+, redis 16379+, app 18080+)

Credentials

At init, stackr generates strong random credentials — a 24-character database password per service and a 64-character hex BETTER_AUTH_SECRET — and writes them into a root .env plus per-service backend/.env. A committed .env.example carries placeholders. The real .env files are git-ignored.

Regeneration without clobbering your edits

When you run stackr add service, stackr must touch files you may have hand-edited — docker-compose.yml, the ORM schema, each backend/package.json. It does this with an additive AST merge, not text templating or marker comments:

  • TypeScript files are merged with ts-morph,
  • Prisma schema with @mrleebo/prisma-ast,
  • Docker Compose YAML with a source-preserving parser.

New blocks are appended; your existing services, comments, and formatting are preserved. The whole operation is staged in a tempdir, dry-run validated, and committed atomically — if anything fails, the project is left byte-identical.

Why this matters

Older versions regenerated compose with marker-comment blocks. The current model is a true additive merge: there are no magic comment fences to preserve, and your customizations survive every stackr add service.

Root scripts

ScriptWhat it does
setupInstall deps, generate .env, reset stale volumes
docker:dev / docker:prodBring the stack up (dev or prod overlay)
test / test:e2eComponent tests / cross-service e2e tests
lint:sgRun the ast-grep convention rules (ast-grep scan)
check:auth-tablesEnforce the auth-table boundary on Prisma schemas

The last two are part of the context harness — they keep the architecture's invariants enforceable in CI, not just documented.