Backend Architecture
NestJS architecture principles and patterns
Backend Architecture
Goal
Build a clean, maintainable NestJS backend with consistent patterns that scales with the team and codebase.
Three-Layer Architecture
Controllers → Services (optional) → Repositories → Database| Layer | Purpose | When to Use |
|---|---|---|
| Controllers | HTTP handling, validation, routing | Always |
| Services | Business logic, orchestration | When logic needed |
| Repositories | Database access via Prisma | Always |
Two Patterns
Simple Pattern: Controller → Repository
Use for straightforward CRUD without business logic.
Full Pattern: Controller → Service → Repository
Use when you need:
- Business rules or validation beyond DTOs
- Multiple database operations
- External service calls
- Background jobs (BullMQ)
Default: Start simple, add service layer when complexity grows.
Project Structure
src/
├── modules/ # Feature modules
│ ├── employees/
│ │ ├── employees.controller.ts
│ │ ├── employees.service.ts # Optional
│ │ ├── employees.repository.ts
│ │ └── dto/
│ ├── time-off/
│ ├── documents/
│ └── ...
├── common/ # Shared utilities
│ ├── guards/
│ ├── decorators/
│ └── pipes/
└── main.tsRequired NestJS Features
| Feature | Why Required |
|---|---|
| TenantGuard | Security - validates tenant context from x-tenant-id header (MVP uses Auth.js sessions, not JWT) |
| ValidationPipe | Validate all DTOs automatically (configured globally in main.ts) |
| ParseIntPipe | Type-safe route parameters |
Optional Features (Use When Needed)
- Interceptors - Logging, response transforms, timeouts
- Custom Pipes - Complex data transformations
- Exception Filters - Custom error formatting
NOT Used
- EventEmitter - Use BullMQ for background jobs instead
- Complex patterns (CQRS, Event Sourcing) - Keep it simple
Key Principles
Tenant Isolation
- Every repository method takes
tenantIdas first parameter - Every query filters by
tenantId - Never expose data across tenants
Data Access Policy
- API-First: All frontend data fetching must go through the API (
apps/api). - Auth Exception: The ONLY exception is
apps/webconnecting to the database forAuth.js(NextAuth). This is due to library limitations.
Error Handling
- Throw NestJS exceptions (
NotFoundException,BadRequestException, etc.) - Let exception filter handle HTTP responses
- Services throw, controllers delegate
Transactions
- Use Prisma
$transaction()for multi-step operations - Keep transactions short
- No external calls inside transactions
Background Jobs
Use BullMQ for:
- Email sending
- Report generation
- File processing
- Scheduled tasks
Don't use BullMQ for:
- Synchronous operations
- Operations needing immediate results
- Simple CRUD
Feature Modules
Employees
- CRUD operations
- Manager-employee relationships (dual role supported)
- Org chart queries
Time-Off
- Request submission and approval workflow
- Balance tracking and validation
- Manager approval for direct reports
Documents
- Upload to Cloud Storage
- Metadata in PostgreSQL
- Access control (employee, manager, admin)
Team Feed
- Posts with media (text, image, video, voice)
- Likes and comments
- AI-generated summaries
Goals/OKR
- Personal, team, company goals
- Key results with progress tracking
- AI goal suggestions
Workflows
- Onboarding/offboarding templates
- Task assignment by role
- Progress tracking
Implementation details to be defined during development