Architecture and Technologies
Understand how technologies relate, the request flow, caching, and database access.
Technology Stack
Framework
- NestJS 11.x
- TypeScript
- Node.js
Databases
- MongoDB (Mongoose + pool)
- PostgreSQL (TypeORM + pool)
Cache & Messaging
- Redis (ioredis)
- Apache Kafka
Storage & APIs
- MinIO (S3 Compatible)
- GraphQL (Apollo)
- REST API
Authentication
- JWT (Passport)
- Argon2id
- Social login
- Active Directory
Services
- Graylog (GELF Logging)
- SMTP / MailHog (Email)
- WhatsApp (Evolution API)
- Terminus (/health)
Configuration and Environment Variables
All configuration is centralized through config files in src/config/ and accessed via ConfigService. Environment variables are loaded automatically.
Config Files
app.config.ts- Application settingsdatabase.config.ts- MongoDB and PostgreSQL (includes pool)redis.config.ts- Redis cachekafka.config.ts- Kafka messagingjwt.config.ts- JWT authenticationargon2.config.ts- Password hashinggoogle-oauth.config.ts- Google OAuth2facebook-oauth.config.ts- Facebook OAuth2twitter-oauth.config.ts- X / Twitter OAuth2 (PKCE)github-oauth.config.ts- GitHub OAuth2figma-oauth.config.ts- Figma OAuth2linkedin-oauth.config.ts- LinkedIn OpenID Connectslack-oauth.config.ts- Slack OpenID Connectatlassian-oauth.config.ts- Atlassian OAuth 2.0 (3LO)gitlab-oauth.config.ts- GitLab OAuth2bitbucket-oauth.config.ts- Bitbucket OAuth2discord-oauth.config.ts- Discord OAuth2twitch-oauth.config.ts- Twitch OAuth2steam-openid.config.ts- Steam OpenID 2.0reddit-oauth.config.ts- Reddit OAuth2amazon-oauth.config.ts- Amazon Login with Amazonpatreon-oauth.config.ts- Patreon OAuth2dropbox-oauth.config.ts- Dropbox OAuth2metamask-auth.config.ts- MetaMask SIWE (EIP-4361)ad-ldap.config.ts- Active Directory LDAP/LDAPS (on-prem AD DS)apple-oauth.config.ts- Apple Sign In (OIDC form_post)smtp.config.ts- SMTP emailminio.config.ts- MinIO storagegraylog.config.ts- Graylog logging (GELF)graphql.config.ts- GraphQLwhatsapp.config.ts- WhatsApp API
Usage Example
constructor(private configService: ConfigService) {}
// Access configuration
const mongoUri = this.configService.get('database.mongoUri');
const redisHost = this.configService.get('redis.host');
const jwtSecret = this.configService.get('jwt.secret');
Request Flow
1. Client sends HTTP request
Request arrives at the NestJS server with headers (Authorization, Content-Type, etc.)
2. Security (IP / catch-all)
SecurityModule tracks invalid API routes and can block IPs (catch-all in production/staging). Admin API under /api/v1/security — see the Security page.
3. JWT Authentication
JwtAuthGuard validates the JWT token. Routes marked with @Public() are skipped.
4. Role Authorization
RolesGuard checks whether the user has the required roles defined via @Roles()
5. Cache Interceptor
TypeOrmCacheInterceptor or MongooseCacheInterceptor checks for cached data in Redis
6. Controller/Resolver
Request reaches the controller (REST) or resolver (GraphQL)
7. Service Layer
Business logic runs in the service, which uses repositories for data access
8. Repository Pattern
The module service injects the chosen repository — PostgreSQL (TypeORM) and/or MongoDB (Mongoose) — based on domain needs. Two repositories per domain allow a single database or CQRS (commands in one, queries in the other).
9. Logging (Graylog)
Interceptor and exception filter send structured GELF logs to Graylog (when GRAYLOG_ENABLED=true).
10. Response and Cache
Data is returned to the client and, when applicable, stored in Redis for subsequent requests
Cache System
How It Works
The cache system uses Redis as an intermediate layer to store results from frequent queries, reducing database load and improving response time.
Cache Interceptors
TypeOrmCacheInterceptor- Cache for TypeORM queries (PostgreSQL)MongooseCacheInterceptor- Cache for Mongoose queries (MongoDB)CacheService- Centralized service for cache management
Redis Configuration
REDIS_HOST=localhost REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 REDIS_TTL=3600 # Time to Live in seconds
Cache Flow
- Request reaches the cache interceptor
- Interceptor checks if a key exists in Redis
- If it exists: return cached data (cache hit)
- If not: run the database query, store in Redis, and return (cache miss)
- Data expires automatically after the configured TTL
Persistence: Mongo, Postgres, and CQRS-ready
Template pattern
The template keeps MongoDB and PostgreSQL in the stack. Each domain can have two repositories; the service chooses one database or both (CQRS). There is no mandatory command/query split — the choice is per module.
Connection pools
Both connections use an explicit pool (configured in database.config.ts). The GET /health endpoint includes pool metadata in the postgres and mongo checks.
POSTGRES_POOL_MAX=10 POSTGRES_POOL_MIN=2 POSTGRES_POOL_IDLE=30000 POSTGRES_POOL_TIMEOUT=5000 MONGO_POOL_MAX=10 MONGO_POOL_MIN=0 MONGO_POOL_IDLE=30000 MONGO_POOL_TIMEOUT=5000
PostgreSQL
- • Relational, typed schema (TypeORM)
- • Repository:
ResourcePostgresRepository - • Use as the single source of truth or as the query side in CQRS
MongoDB
- • Flexible document schema (Mongoose)
- • Repository:
ResourceMongoRepository - • Use alone or as the command side in CQRS
Example: single database
constructor(
private readonly postgresRepo: ResourcePostgresRepository,
) {}
async create(data: CreateResourceDto) {
return this.postgresRepo.create(data);
}
async findAll() {
return this.postgresRepo.findAll();
}
Example: enable CQRS
Inject both repositories in the service: commands in one database, queries in the other. Optionally sync with Kafka for eventual consistency.
constructor(
private readonly mongoRepo: ResourceMongoRepository, // commands
private readonly postgresRepo: ResourcePostgresRepository, // queries
) {}
async create(data: CreateResourceDto) {
const resource = await this.mongoRepo.create(data);
// publish Kafka event to project into Postgres...
return resource;
}
async findAll() {
return this.postgresRepo.findAll();
}
Mongo or Postgres
You can use Postgres only, Mongo only, or both (CQRS). The choice is in the service/module without removing the other database infrastructure from the project.
How Technologies Relate
Relationship Diagram
Framework Core
Available / CQRS
Persistence / queries
Cache
Messaging
Storage
GELF Logs
- NestJS ↔ MongoDB/PostgreSQL: The framework communicates with databases through Mongoose and TypeORM; the service chooses which repository to use
- NestJS ↔ Redis: Cache interceptors use Redis to store results
- NestJS ↔ Kafka: Events and messages are published/consumed via Kafka (useful for projecting data in CQRS)
- NestJS ↔ MinIO: File upload and download via S3-compatible API
- NestJS ↔ Graylog: Structured logs via GELF HTTP (interceptor + exception filter)
- MongoDB ↔ PostgreSQL (optional): In a CQRS design, synchronization via Kafka events or async processes