Files
mercadodevida/project/README.md
rikrdo 41f144d7bd feat(F-003): HTTP foundation with request context and error envelope
- request_id generated or sanitized-propagated on every request (x-request-id)
- structured JSON logging (pino), one correlated line per request, injectable logger
- error envelope v2 { error: { statusCode, code, message, details? }, requestId }
- 5xx messages always generic; stack traces stay in server logs only
- explicit parseJson (zod) input validation hook at the API layer
- README HTTP contract section; deps justified in spec/tech.md
- all gates approved; verify.sh green
2026-08-14 22:13:28 +02:00

2.6 KiB

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

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)

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:boundaries enforces these rules.