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

73 lines
2.6 KiB
Markdown

# 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
<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
```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.