NestJS 11 and TypeScript API for the Natours application.
- Node.js 24
- pnpm 11.18.0 (pinned through
packageManager)
Install Corepack if your Node distribution does not include it, then install the pinned package manager and dependencies:
npm install --global corepack@latest
corepack enable
corepack install
pnpm install --frozen-lockfile
cp .env.example .envpnpm db:migrate
pnpm start:devThe API uses PostgreSQL through Drizzle. With DBngin, create dedicated natours_dev and
natours_test databases on the default passwordless local PostgreSQL instance. The example
environment file is already configured for that setup.
Optional PostgreSQL 18 and Redis 8.8 containers are available on ports 5433 and 6380:
docker compose up -d postgres redis
DATABASE_URL=postgresql://postgres:postgres@localhost:5433/natours_dev pnpm db:migrateThe database workflow is:
pnpm db:generate --name=describe_change # generate a committed SQL migration
pnpm db:check # validate migration history
pnpm db:migrate # apply pending migrations
pnpm db:seed # canonical data, then local demo data
pnpm db:purge # clear app rows, preserve migration history
pnpm db:reset # purge, migrate, and seed deterministically
pnpm db:studio # inspect the configured databasedb:purge and db:reset refuse production. Outside production, they only accept database names
listed in DATABASE_RESET_ALLOWED_DATABASES and worker databases derived from those names. Set
ALLOW_DATABASE_RESET=true only when intentionally resetting another non-production database.
Demo seeds are never production-safe.
The generated OpenAPI document is a reviewed contract artifact:
pnpm openapi:generate # update openapi/openapi.json after an intentional contract change
pnpm openapi:check # fail when generated and committed contracts differBuild once, then run the two independently scalable processes:
pnpm build
pnpm start:prod # API
pnpm start:worker # durable jobs and transactional outbox relayInspect and replay retained jobs without exposing their payloads:
pnpm jobs:list-failed --limit=20
pnpm jobs:inspect --id=<job-id>
pnpm jobs:replay --id=<job-id> --state=failedThe initial HTTP surface is:
GET /api/v1— API discovery responseGET /health— dependency-free, unversioned livenessGET /ready— PostgreSQL and Redis readiness/docsand/docs-json— Scalar API reference and OpenAPI JSON outside production
Configuration is validated at startup. Production requires an explicit comma-separated CORS_ORIGINS allowlist. Requests accept an optional x-request-id; the API returns that ID (or a generated UUID) and includes it in structured logs. Deploy the API and worker separately and route traffic only to ready API instances.
pnpm format:check
pnpm lint
pnpm typecheck
pnpm test
pnpm test:integration
pnpm test:redis
pnpm test:e2e
pnpm test:processes
pnpm openapi:check
pnpm buildSee docs/01_SPEC.md for the product contract and docs/05_DEVELOPMENT.md for the contributor
workflow. Resend is the selected future email provider; its live adapter arrives with identity
delivery. Sentry remains a planned capability.