Backend Architecture
Backend Architecture Document
Project: {{PROJECT_NAME}} Version: {{VERSION}} Date: {{DATE}} Author: {{AUTHOR}} Status: Draft | In Review | Approved Reviewers: {{REVIEWERS}}
Document History
| Version | Date | Author | Changes |
|---|---|---|---|
| 0.1 | {{DATE}} | {{AUTHOR}} | Initial draft |
1. Architecture Pattern
Pattern: {{Modular Monolith | Microservices | Monolith | Event-Driven Microservices}}
| Pattern Considered | Pros | Cons | Decision |
|---|---|---|---|
| Monolith | Simple deploy, low latency | Scaling bottleneck, team coupling | {{Selected/Rejected}} |
| Modular Monolith | Organized, single deploy, module isolation | Shared DB risk | {{Selected/Rejected}} |
| Microservices | Independent scaling, team autonomy | Operational complexity | {{Selected/Rejected}} |
Rationale:
TODO: 3-5 sentences explaining the decision considering team size, scale requirements, and operational maturity.
2. Technology Stack
| Layer | Technology | Version | Notes |
|---|---|---|---|
| Runtime | {{Node.js}} |
{{20.x LTS}} |
|
| Framework | {{NestJS / Express / Fastify / Hono}} |
{{10.x}} |
|
| ORM | {{Prisma / TypeORM / Drizzle}} |
{{5.x}} |
|
| Primary DB | {{PostgreSQL}} |
{{16.x}} |
Managed: {{RDS / Supabase}} |
| Cache | {{Redis}} |
{{7.x}} |
Managed: {{ElastiCache / Upstash}} |
| Queue | {{BullMQ / SQS / RabbitMQ}} |
{{5.x}} |
|
| Search | {{Elasticsearch / MeiliSearch / Typesense}} |
{{8.x}} |
Optional |
| File storage | {{AWS S3 / Cloudflare R2}} |
API | |
| Auth | {{Custom JWT / Auth0 / Supabase Auth}} |
||
| Logging | {{Pino / Winston}} |
{{8.x}} |
→ {{Datadog / Loki}} |
| APM | {{Datadog / Sentry / Elastic APM}} |
||
| API docs | {{Swagger / OpenAPI 3.1}} |
{{3.1}} |
3. Project Structure
src/
├── modules/ # Feature modules (NestJS) / route handlers (Express)
│ ├── users/
│ │ ├── users.module.ts
│ │ ├── users.controller.ts
│ │ ├── users.service.ts
│ │ ├── users.repository.ts
│ │ ├── dto/
│ │ │ ├── create-user.dto.ts
│ │ │ └── update-user.dto.ts
│ │ └── entities/
│ │ └── user.entity.ts
│ ├── auth/
│ ├── notifications/
│ └── {{FEATURE}}/
├── common/
│ ├── decorators/ # Custom decorators
│ ├── filters/ # Exception filters
│ ├── guards/ # Auth / role guards
│ ├── interceptors/ # Logging, transform interceptors
│ ├── pipes/ # Validation pipes
│ └── middleware/ # Request middleware
├── database/
│ ├── migrations/
│ └── seeds/
├── config/
│ ├── app.config.ts
│ ├── database.config.ts
│ └── redis.config.ts
├── jobs/ # Background job definitions
└── main.ts # Application entry point
test/
├── unit/
├── integration/
└── e2e/
4. Request Processing Pipeline
sequenceDiagram
participant Client
participant Gateway as API Gateway / LB
participant Middleware as Middleware Stack
participant Guard as Guards
participant Pipe as Validation Pipe
participant Controller
participant Service
participant Repository
participant DB as Database
Client->>Gateway: HTTP Request
Gateway->>Middleware: Forward (with tracing headers)
Middleware->>Middleware: Request ID, CORS, Security Headers, Rate Limit
Middleware->>Guard: Authenticated request
Guard->>Guard: JWT verification, Role check
Guard->>Pipe: Authorized request
Pipe->>Pipe: Schema validation (Zod/class-validator)
Pipe->>Controller: Validated DTO
Controller->>Service: Business method call
Service->>Repository: Data access call
Repository->>DB: Query
DB-->>Repository: Result
Repository-->>Service: Domain entity
Service-->>Controller: Response data
Controller-->>Client: HTTP Response (transformed)
5. Middleware Stack Configuration
Execution order (applied left-to-right):
| Order | Middleware | Purpose | Global? |
|---|---|---|---|
| 1 | helmet |
Security headers (CSP, HSTS, etc.) | Yes |
| 2 | cors |
CORS policy enforcement | Yes |
| 3 | request-id |
Inject X-Request-ID header |
Yes |
| 4 | compression |
gzip response compression | Yes |
| 5 | body-parser |
Parse JSON/urlencoded bodies | Yes |
| 6 | rate-limiter |
IP-based rate limiting (Redis) | Yes |
| 7 | request-logger |
Structured request logging | Yes |
| 8 | Route-specific middleware | Auth, validation per route | No |
Security headers configured via Helmet:
app.use(helmet({
contentSecurityPolicy: { /* ... */ },
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
referrerPolicy: { policy: 'same-origin' },
}));
6. Authentication & Authorization Flow
flowchart TD
Login["POST /auth/login\n{email, password}"] --> ValidateCreds["Validate credentials\n(bcrypt compare)"]
ValidateCreds -->|Invalid| Reject["401 Unauthorized"]
ValidateCreds -->|Valid| IssuePair["Issue token pair\naccess (15m) + refresh (30d)"]
IssuePair --> StoreRefresh["Store refresh token\n(hashed, Redis or DB)"]
IssuePair --> ReturnTokens["Return tokens to client"]
AuthReq["Authenticated Request"] --> ExtractJWT["Extract Bearer token"]
ExtractJWT --> VerifyJWT["Verify signature + expiry"]
VerifyJWT -->|Invalid/Expired| RefreshFlow["POST /auth/refresh"]
VerifyJWT -->|Valid| CheckRoles["Role/permission check"]
CheckRoles -->|Unauthorized| Forbidden["403 Forbidden"]
CheckRoles -->|Authorized| Handler["Route Handler"]
RefreshFlow --> VerifyRefresh["Verify refresh token\n(hash match, not revoked)"]
VerifyRefresh -->|Invalid| Logout["Force logout → 401"]
VerifyRefresh -->|Valid| RotateToken["Rotate tokens\n(old token revoked)"]
RBAC / ABAC:
- Roles:
{{admin | manager | user | viewer}} - Permissions:
{{resource:action}}e.g.users:delete - Role-permission mapping:
{{database table | config file | code}}
7. Database Access Patterns
Pattern: {{Repository Pattern}}
// Repository interface — decouples business logic from storage
interface UserRepository {
findById(id: string): Promise<User | null>;
findByEmail(email: string): Promise<User | null>;
findMany(filters: UserFilters): Promise<PaginatedResult<User>>;
create(data: CreateUserData): Promise<User>;
update(id: string, data: UpdateUserData): Promise<User>;
delete(id: string): Promise<void>;
}
Query performance rules:
- All queries accessing > 1000 rows must have paginator
- All filterable fields must have DB indexes (document in migration)
- N+1 queries forbidden — use
include/JOIN ordataloaderpattern - Raw SQL allowed only when ORM cannot express the query efficiently
8. Caching Architecture
graph LR
Request --> L1["L1: In-Memory\n(node-cache)"]
L1 -->|Cache miss| L2["L2: Redis\n(shared, distributed)"]
L2 -->|Cache miss| DB["Database"]
DB --> L2
L2 --> L1
L1 --> Response
| Layer | Technology | TTL | What's Cached |
|---|---|---|---|
| L1 (in-process) | node-cache / Map |
30 sec | Config, feature flags |
| L2 (distributed) | Redis | Per resource | User sessions, API responses |
| L3 (CDN edge) | Cloudflare / CloudFront | Per route | Public API responses |
Cache-aside pattern (L2):
async function getCachedUser(id: string): Promise<User> {
const cacheKey = `user:${id}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
const user = await userRepository.findById(id);
await redis.setex(cacheKey, 300, JSON.stringify(user)); // 5 min TTL
return user;
}
Cache invalidation strategy:
- On update/delete:
await redis.del(cacheKey) - Pattern-based:
await redis.del('user:*')(use sparingly — expensive) - Tag-based:
{{ioredis-tag | custom tagging}}
9. Background Job Processing
Library: {{BullMQ | Agenda | pg-boss}}
Queue storage: {{Redis | PostgreSQL}}
| Queue | Job Types | Concurrency | Retry Policy |
|---|---|---|---|
emails |
Welcome, reset password, notifications | 10 | 3 retries, exp. backoff |
uploads |
Image processing, file conversion | 5 | 2 retries |
sync |
External API sync, data aggregation | 3 | 5 retries |
reports |
PDF generation, exports | 2 | 1 retry |
Job schema:
interface EmailJob {
type: 'welcome' | 'password_reset' | 'notification';
to: string;
templateId: string;
data: Record<string, unknown>;
}
Monitoring: {{Bull Board | BullMQ Metrics API}} — admin UI at {{/admin/queues}}
10. File Storage & Media Handling
Storage provider: {{AWS S3 | Cloudflare R2 | MinIO}}
Bucket naming: {{company-project-env}} (e.g., alai-app-production)
Upload flow:
- Client requests pre-signed URL from API (
POST /uploads/presigned) - API validates file type, size, generates pre-signed URL (expiry: 15 min)
- Client uploads directly to storage (bypasses API server)
- Client notifies API of upload completion (
POST /uploads/confirm) - API validates file exists, creates database record, triggers processing job
File size limits:
| Type | Max Size |
|---|---|
| Profile images | 5 MB |
| Documents | 25 MB |
| Videos | 500 MB |
11. Logging & Observability
Logger: {{Pino}} — structured JSON logs
Log aggregation: {{Datadog / Loki / CloudWatch}}
Log levels policy:
| Level | When to use |
|---|---|
error |
Exceptions, failures requiring attention |
warn |
Unexpected but handled situations |
info |
Significant business events (user created, order placed) |
debug |
Detailed diagnostic info — dev/staging only |
trace |
Verbose request tracing — never in production |
Always log:
- Request: method, path, request ID, user ID (hashed), status code, duration
- Errors: full stack trace, request context
- Background jobs: job ID, queue, start/end, duration, outcome
Never log:
- Passwords, tokens, API keys
- Full request/response bodies with PII
- Payment card data
12. Configuration Management
Pattern: Typed config module with validation on startup
// config/app.config.ts
const schema = z.object({
NODE_ENV: z.enum(['development', 'staging', 'production']),
PORT: z.coerce.number().default(4000),
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
// ...
});
export const config = schema.parse(process.env);
// App fails FAST at startup if any required variable is missing/invalid
Secrets management: {{HashiCorp Vault | AWS Secrets Manager | Doppler}}
NO secrets in environment files committed to git.
13. Health Check Endpoints
| Endpoint | Type | Checks |
|---|---|---|
GET /health/live |
Liveness | Process is running |
GET /health/ready |
Readiness | DB connected, Redis connected, app ready |
GET /health/startup |
Startup | Migrations run, config valid |
Readiness check response:
{
"status": "ok",
"checks": {
"database": { "status": "ok", "latency": 3 },
"redis": { "status": "ok", "latency": 1 },
"queue": { "status": "ok", "pendingJobs": 12 }
},
"version": "1.2.3",
"uptime": 3600
}
14. Architecture Diagram
graph TB
subgraph "Clients"
Web["Web App"]
Mobile["Mobile App"]
end
subgraph "Infrastructure"
LB["Load Balancer\n(Nginx / ALB)"]
API["API Server\n({{FRAMEWORK}})"]
Workers["Background Workers\n(BullMQ)"]
end
subgraph "Data"
DB["PostgreSQL\n(Primary + Replicas)"]
Cache["Redis\n(Cache + Queue)"]
Storage["Object Storage\n(S3 / R2)"]
end
subgraph "Observability"
Logs["Log Aggregation\n(Datadog / Loki)"]
APM["APM / Tracing"]
end
Web --> LB
Mobile --> LB
LB --> API
API --> DB
API --> Cache
API --> Storage
API --> Cache
Workers --> Cache
Workers --> DB
API --> Logs
Workers --> Logs
API --> APM
Approval
| Role | Name | Date | Signature |
|---|---|---|---|
| Author | |||
| Backend Lead | |||
| Tech Lead / Architect | |||
| Security Reviewer |
No comments to display
No comments to display