Architecture
Architecture
Section titled “Architecture”Current Architecture Summary
Section titled “Current Architecture Summary”The new backend is a NestJS application organized around modules, shared infrastructure services, and a strongly typed runtime.
It is architected very differently from the legacy PHP monolith. Instead of server-rendered route handling, it is designed as a modern API service with centralized bootstrap configuration and modular domain boundaries.
Application Bootstrap
Section titled “Application Bootstrap”The application starts from backend/src/main.ts.
At bootstrap time, the backend does the following:
- loads Sentry instrumentation first through
import './instrument' - creates the Nest application with buffered logs
- replaces the default logger with a custom application logger
- applies a global
ValidationPipe - applies a global response interceptor
- enables CORS using environment-driven configuration
- enables Swagger in non-production environments
- starts listening on
process.env.PORTor port3000
This means the backend has one centralized bootstrap layer where cross-cutting concerns are wired once for the whole service.
Global Runtime Behavior
Section titled “Global Runtime Behavior”Several architectural decisions are applied globally instead of per module.
Validation
Section titled “Validation”The backend uses Nest’s global ValidationPipe with:
- transformation enabled
- whitelist enabled
- non-whitelisted fields not forbidden by default
This indicates a request-validation-first design where DTOs are expected to define the allowed request shape.
Response Standardization
Section titled “Response Standardization”A global response interceptor is registered:
ResponseInterceptor
This suggests the backend aims to normalize response structure across modules instead of letting each controller define a different response style.
Logging
Section titled “Logging”The application uses:
CustomLogger
This logger is injected into the application bootstrap and also used by lower-level services such as Prisma-related infrastructure.
CORS is configured through environment variables:
CORS_ORIGINCORS_METHODSCORS_HEADERS
This makes the backend deployment-aware and easier to adapt across development, staging, and production.
AppModule Composition
Section titled “AppModule Composition”The root composition happens in backend/src/app.module.ts.
The AppModule imports:
- global configuration via
ConfigModule - global i18n configuration
- Sentry module support
- Prisma module
- health module
- auth module
- consultants module
- reference module
- development module only in development mode
This confirms the backend follows a root-module composition pattern where common infrastructure is loaded first and feature modules are registered explicitly.
Cross-Cutting Infrastructure
Section titled “Cross-Cutting Infrastructure”1. Configuration Layer
Section titled “1. Configuration Layer”Configuration is provided through Nest ConfigModule and environment files.
The current root config setup loads:
.env.local.env
This indicates a layered environment strategy where local overrides take precedence over shared defaults.
2. Observability Layer
Section titled “2. Observability Layer”The backend includes Sentry-based observability through:
@sentry/nestjsSentryGlobalFilter- early initialization in
backend/src/instrument.ts
The Sentry setup currently:
- enables logging capture based on environment
- filters sensitive headers
- attaches contextual tags such as
errorId - disables remote reporting in development
This shows the backend is designed with production diagnostics in mind, not as a purely local development service.
3. Exception Handling Layer
Section titled “3. Exception Handling Layer”Two global filters are registered in AppModule:
SentryGlobalFilterHttpExceptionFilter
This means exceptions are expected to pass through a centralized error-handling path rather than being handled ad hoc in individual controllers.
4. Internationalization Layer
Section titled “4. Internationalization Layer”The i18n system is globally configured in backend/src/i18n/i18n.module.ts.
The current i18n design includes:
- fallback language support
- locale loading from filesystem
- query-based language resolution through
langorlocale Accept-Languageheader support- generated TypeScript typing for translation keys
This is a strong sign that localization is treated as a first-class architectural concern.
Current Module Areas
Section titled “Current Module Areas”The currently visible module areas include:
authconsultantsreferencehealthmessagingdatabasei18ndevelopment
These are not flat folders only for organization. They are actual Nest modules that separate controllers, services, and infrastructure responsibilities.
Module Roles
Section titled “Module Roles”Auth Module
Section titled “Auth Module”The auth module is one of the most architecturally significant modules.
From the current implementation, it includes:
- controller-driven auth endpoints
- JWT configuration
- Passport integration
- JWT strategy
- a global auth guard
- messaging integration for OTP-like flows
- Prisma access for identity persistence
- translation-aware error messaging
The auth module therefore acts as both:
- a feature module
- a security boundary provider for the rest of the application
Important implication
Section titled “Important implication”APP_GUARD is registered inside the auth module using AuthGuard.
This strongly suggests authentication is applied globally by default, with explicit decorators such as @Public() or other scoped decorators used to opt routes out or change access behavior.
Database Layer
Section titled “Database Layer”The backend uses Prisma as the clearest active data access layer.
The current database architecture includes:
- a global
PrismaModule - a
PrismaServiceextendingPrismaClient - Nest lifecycle integration through
OnModuleInitandOnModuleDestroy - connection health checks
This means database access is exposed as an application-wide injectable infrastructure dependency rather than being re-created per module.
Important implication
Section titled “Important implication”Because PrismaModule is marked @Global(), any module can inject PrismaService without re-declaring the provider chain. This reduces friction, but it also increases the need for discipline in how domain modules access persistence.
Health and Operational Endpoints
Section titled “Health and Operational Endpoints”The health module exposes a public operational endpoint using Terminus.
The health controller currently checks:
- disk health
- heap memory health
- database health through Prisma
This reflects a backend that is being prepared for deployment, uptime monitoring, and operational checks across environments.
API Documentation Layer
Section titled “API Documentation Layer”Swagger is configured centrally in main.ts for non-production environments.
The current Swagger setup includes:
- title and description
- versioning
- bearer authentication support
- local, staging, and production server entries
- global
Accept-Languageheader documentation
This indicates the backend is intended to be discoverable and explorable by developers and integrators during development and staging.
Security Model
Section titled “Security Model”The current security model is shaped by several layers working together:
- JWT token issuance and refresh behavior
- Passport integration
- global auth guard
- route decorators such as
@Public(),@Private(), and refresh-auth behavior - scope-aware access control inside auth flows
This is a cleaner and more explicit security model than the session-driven style of the legacy PHP application.
Development-Only Behavior
Section titled “Development-Only Behavior”The DevelopmentModule is conditionally imported only when NODE_ENV === 'development'.
This is an important architectural signal:
- the backend already differentiates between development-only capabilities and normal runtime behavior
- environment-sensitive module registration is part of the design
Architectural Style
Section titled “Architectural Style”The current backend can be described as:
- modular monolithic API service
- infrastructure-first NestJS application
- centralized bootstrap with global pipes, filters, and interceptors
- Prisma-backed data layer
- JWT-based stateless auth model
- observability-aware and deployment-aware service
It is not yet a microservice architecture, but it is clearly designed to be cleaner, more testable, and more operationally mature than the legacy website backend.
Strengths of the Current Architecture
Section titled “Strengths of the Current Architecture”Based on the current implementation, the architecture already has several strong qualities:
- clear modular boundaries
- centralized cross-cutting concerns
- typed request validation
- built-in observability hooks
- explicit health monitoring
- development-friendly Swagger exposure
- structured authentication foundation
Current Architectural Tradeoffs
Section titled “Current Architectural Tradeoffs”A few important tradeoffs are also visible:
- Prisma is clearly active, but TypeORM is still present in dependencies, which may indicate partial transition or unused stack weight
- global infrastructure patterns reduce duplication, but can hide coupling if domain boundaries are not kept clean
- auth being globally enforced is powerful, but requires disciplined use of public/private decorators across controllers
- a global Prisma dependency is convenient, but can encourage modules to bypass stronger repository or service boundaries if not managed carefully
Recommended Documentation Framing
Section titled “Recommended Documentation Framing”For documentation purposes, this backend should currently be framed as:
- the new backend foundation
- a NestJS modular API platform
- a service-oriented replacement path for selected legacy responsibilities
- a typed, validated, observable backend designed for growth
That framing matches the code more accurately than describing it as only a basic Nest starter or a complete distributed microservice system.