Skip to content

Backend architecture (NestJS)

The LionPOS API is a NestJS 11 application in apps/backend, backed by TypeORM and MySQL. It exposes REST JSON under a global /api/v1 prefix, ships OpenAPI / Swagger for contract truth, and applies Helmet, rate limiting (Throttler), ValidationPipe, and JWT + Passport guards on feature routes. This page describes how the server is put together; per-area HTTP maps live in Backend modules.


GoalsNon-goals
Give engineers a single map of bootstrap, globals, and module boundariesReplace Swagger as the field-by-field API reference
Explain where auth, tenancy, and POS payment hooks attachDocument every entity column (use TypeORM entities + migrations)
Point to tests and scripts for safe changesPrescribe cloud infra beyond what env docs already cover

  • NestFactory.create with Express adapter; applyGlobalHttpConfig sets Helmet (CSP relaxed for Swagger UI), global prefix api/v1 with Swagger UI + OpenAPI JSON paths excluded, global ValidationPipe (whitelist, forbidNonWhitelisted, transform, production-safe error messages), and Swagger setup.
  • CORS from CORS_ORIGIN (comma-separated); port from PORT (default 3000).
  • Optional static SPA hosting via mountStaticSpasIfPresent (see Deployment).
ImportPurpose
ConfigModuleGlobal env (ConfigModule.forRoot({ isGlobal: true }))
DatabaseModuleTypeORM / MySQL registration
ThrottlerModuleDefault rate limit: THROTTLE_TTL_MS / THROTTLE_LIMIT
HealthModuleLiveness/readiness style endpoint
AuthModuleCustomer/shared auth/* routes
VendorModuleVendor JWT surfaces + vendor/*, auth/vendor, auth/vendor/context
AdminModuleAdmin JWT surfaces + admin/*, auth/admin
PosModulePOS checkout + pos/payments webhooks

Global guard: ThrottlerGuard is registered with APP_GUARD (applies before route handlers; still subject to @SkipThrottle() / Throttler config on routes).

  • Validation: DTOs use class-validator + class-transformer; unknown properties are rejected when forbidNonWhitelisted applies.
  • Auth: Feature controllers use Passport JWT strategies and custom guards (e.g. admin module keys, store/tenant checks)—see Authentication.
  • Tenancy: Store and vendor scoping is enforced in services (not only UI); see Tenancy — stores and outlets.
PathRole
src/app.module.tsRoot composition
src/main.tsProcess entry
src/bootstrap-http.tsHelmet, prefix, ValidationPipe, Swagger
src/database/TypeORM module, data source, migrations path
src/modules/*/Feature modules (controllers, services, DTOs, guards, strategies)
test/E2E Jest config and specs

  1. Request hits Express → HelmetCORSThrottler (if not skipped).
  2. Routing matches @Controller path under /api/v1/... (unless excluded for Swagger).
  3. Guards run (JWT, roles, module, zone/store assertions per route).
  4. ValidationPipe validates/transforms the body/query DTO.
  5. Controller delegates to serviceTypeORM / external HTTP as needed.
  6. Response serialized; errors mapped to HTTP exceptions (avoid leaking raw DB errors in production).

  • Rate limits: tune THROTTLE_TTL_MS and THROTTLE_LIMIT for edge/proxy environments; align with Operations if clients hit 429.
  • Swagger: disable in hardened prod with SWAGGER_ENABLED=false; JSON/UI paths stay off the versioned API prefix—see API conventions.
  • Secrets: never commit .env; index of variables in Environment.
  • Payment webhooks: verify signatures and idempotency—see POS payments & webhooks.

IDScenarioExpected
BA1npm run test in apps/backendUnit tests pass
BA2npm run test:e2eE2E suite passes against configured test env
BA3Start API + open Swagger/docs (or SWAGGER_PATH) lists controllers
BA4Invalid DTO body400 with validation errors (non-prod may include messages)
BA5Throttle storm429 when exceeding configured limit