Skip to content

Backend (NestJS)

The API (apps/api) is a NestJS 11 application written in strict TypeScript. Its defining constraint is module isolation.

  • Every feature lives in apps/api/src/modules/<name>/.
  • No direct cross-module imports. Communication happens through:
    • controller routes (HTTP boundary),
    • a module’s public exports (barrel index.ts),
    • events / queues,
    • the shared package (packages/shared).
  • Cross-cutting concerns live in src/common/ and are provided globally (e.g. SecretModule exposes SecretService app-wide).

Before adding an import, check whether it crosses a module boundary — if it does, use a defined interface instead.

Every request passes through a fixed guard chain:

ThrottlerGuard → TenantResolverGuard → JwtAuthGuard → RoleGuard → ModuleGuard
Guard Responsibility
ThrottlerGuard Rate limiting
TenantResolverGuard Resolves the tenant context for the request
JwtAuthGuard Validates the JWT access token; skipped on @Public() routes
RoleGuard Enforces @Roles(...) declarations
ModuleGuard Enforces @Permissions(...) declarations

Route metadata is declared via decorators directly on controllers:

@Controller('tools')
export class ToolsController {
@Get()
@Permissions(Permission.TOOL_READ)
list() { /* … */ }
@Post()
@Roles(UserRole.ADMIN)
create() { /* … */ }
@Get('health')
@Public()
health() { /* … */ }
}
Service Location Purpose
SecretService common/services/secret.service.ts Reads Docker secrets (/run/secrets/<name>) with env-var fallback; get() / getOrThrow()
GlobalExceptionFilter common/ Maps NestJS exceptions to TT-xxx error responses
PasswordService auth module argon2id hashing (RFC 9106 recommended parameters)
PrismaService prisma/ Prisma client via PrismaPg adapter
MistralVisionService ai module Vision model calls (photo recognition, checks)

Long-running work runs on Redis-backed queues consumed by the worker container — e.g. the daily encrypted database backup, notification delivery, and sync jobs. Producers live in the API; consumers live in modules/queue/worker.service.ts.

  • JWT access token (short-lived) + refresh token (longer-lived).
  • Passwords: argon2id (memory 64 MiB, time 3, parallelism 4 — RFC 9106 “first recommended” profile). Verification reads parameters from the PHC string, so older hashes keep working.
  • MFA: TOTP enrollment for privileged roles; a scoped enrollment token (mfa-enrollment scope) lets admins complete setup on first login.
  • M2M: tenant provisioning endpoints authenticate via a dedicated shared secret (timing-safe comparison, fail-closed).