Backend (NestJS)
Backend Architecture
Section titled “Backend Architecture”The API (apps/api) is a NestJS 11 application written in strict
TypeScript. Its defining constraint is module isolation.
Module isolation
Section titled “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.SecretModuleexposesSecretServiceapp-wide).
Before adding an import, check whether it crosses a module boundary — if it does, use a defined interface instead.
Guard pipeline
Section titled “Guard pipeline”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() { /* … */ }}Key services
Section titled “Key services”| 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) |
Queues (BullMQ)
Section titled “Queues (BullMQ)”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.
Authentication model
Section titled “Authentication model”- 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-enrollmentscope) lets admins complete setup on first login. - M2M: tenant provisioning endpoints authenticate via a dedicated shared secret (timing-safe comparison, fail-closed).