- node-pg-migrate + pg: baseline migration (extensions, app_meta) with working down - src/infrastructure/db fail-fast pool and typed query helper - docker-compose: postgres:16-alpine + redis:7-alpine with one-command up - table naming convention <module>_<table> documented in README - integration tests (6) against real PostgreSQL; strict identifier validation for test DDL after security-gate hardening round - deps justified in spec/tech.md; all gates approved; verify.sh green
MercadoDeVida backend — modular monolith skeleton
TypeScript + Fastify modular monolith. Simple code, clear modules, small changes, no magic.
Requirements
- Node.js >= 22
- npm
Commands
npm install # install dependencies
npm run build # compile to dist/
npm start # run compiled server (PORT, HOST env vars)
npm test # vitest unit tests (no database needed)
npm run typecheck # tsc --noEmit
npm run lint # eslint + prettier check
npm run lint:boundaries # module boundary check
Database (local dev)
cp .env.example .env # once
npm run docker:up # start PostgreSQL 16 + Redis 7
npm run db:up # apply migrations
npm run db:status # list applied migrations
npm run db:down # revert last migration
npm run test:integration # integration tests (need TEST_DATABASE_URL from .env)
npm run docker:down # stop services (add -v to wipe volumes)
Table naming convention
<module>_<table> e.g. catalog_products, inventory_stock, orders_orders
- Every table is prefixed with its owning module.
- A module never queries tables without its own prefix; data flows through module interfaces.
- Migrations are immutable once merged: fixes ship as new migrations.
- No schema change without migration.
Layout
src/
├── app/ # composition root (only place that wires modules)
├── infrastructure/ # http server entrypoint (later: db, redis, providers)
├── modules/ # business modules, one folder each
│ └── health/ # exemplar module: public API only via index.ts
└── shared/ # cross-cutting helpers (error envelope)
Module rules
- A module exposes its public API only through its
index.ts. - Files inside a module may import: own subtree,
src/shared, Node builtins, npm packages. - Code outside modules (app/infrastructure) may import a module only via its
index.ts. npm run lint:boundariesenforces these rules.