# MercadoDeVida backend — modular monolith skeleton TypeScript + Fastify modular monolith. Simple code, clear modules, small changes, no magic. ## Requirements - Node.js >= 22 - npm ## Commands ```bash 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 ``` ## HTTP contract - Every response carries an `x-request-id` header (propagated from a safe incoming `x-request-id`, or a fresh UUID). Every JSON log line for a request carries the same id. - Errors always use one envelope: `{ "error": { "statusCode", "code", "message", "details?" }, "requestId" }` Codes: `NOT_FOUND`, `VALIDATION_ERROR`, `BAD_REQUEST`/Fastify 4xx codes, `INTERNAL_ERROR`. 5xx messages are always generic; stack traces stay in server logs only. - Input validation is explicit per route: `parseJson(schema, body)` (zod) in the handler. - Log level via `LOG_LEVEL` env var (default `info`); logs are JSON only. ## Database (local dev) ```bash 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 ```text _ 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 ```text 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:boundaries` enforces these rules.