# Architecture Overview - Backend Services Complete guide to the layered architecture pattern used in backend microservices. ## Table of Contents - [Layered Architecture Pattern](#layered-architecture-pattern) - [Request Lifecycle](#request-lifecycle) - [Service Comparison](#service-comparison) - [Directory Structure Rationale](#directory-structure-rationale) - [Module Organization](#module-organization) - [Separation of Concerns](#separation-of-concerns) --- ## Layered Architecture Pattern ### The Four Layers ``` ┌─────────────────────────────────────┐ │ HTTP Request │ └───────────────┬─────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Layer 1: ROUTES │ │ - Route definitions only │ │ - Middleware registration │ │ - Delegate to controllers │ │ - NO business logic │ └───────────────┬─────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Layer 2: CONTROLLERS │ │ - Request/response handling │ │ - Input validation │ │ - Call services │ │ - Format responses │ │ - Error handling │ └───────────────┬─────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Layer 3: SERVICES │ │ - Business logic │ │ - Orchestration │ │ - Call repositories │ │ - No HTTP knowledge │ └───────────────┬─────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Layer 4: REPOSITORIES │ │ - Data access abstraction │ │ - Prisma operations │ │ - Query optimization │ │ - Caching │ └───────────────┬─────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Database (MySQL) │ └─────────────────────────────────────┘ ``` ### Why This Architecture? **Testability:** - Each layer can be tested independently - Easy to mock dependencies - Clear test boundaries **Maintainability:** - Changes isolated to specific layers - Business logic separate from HTTP concerns - Easy to locate bugs **Reusability:** - Services can be used by routes, cron jobs, scripts - Repositories hide database implementation - Business logic not tied to HTTP **Scalability:** - Easy to add new endpoints - Clear patterns to follow - Consistent structure --- ## Request Lifecycle ### Complete Flow Example ```typescript 1. HTTP POST /api/users ↓ 2. Express matches route in userRoutes.ts ↓ 3. Middleware chain executes: - SSOMiddleware.verifyLoginStatus (authentication) - auditMiddleware (context tracking) ↓ 4. Route handler delegates to controller: router.post('/users', (req, res) => userController.create(req, res)) ↓ 5. Controller validates and calls service: - Validate input with Zod - Call userService.create(data) - Handle success/error ↓ 6. Service executes business logic: - Check business rules - Call userRepository.create(data) - Return result ↓ 7. Repository performs database operation: - PrismaService.main.user.create({ data }) - Handle database errors - Return created user ↓ 8. Response flows back: Repository → Service → Controller → Express → Client ``` ### Middleware Execution Order **Critical:** Middleware executes in registration order ```typescript app.use(Sentry.Handlers.requestHandler()); // 1. Sentry tracing (FIRST) app.use(express.json()); // 2. Body parsing app.use(express.urlencoded({ extended: true })); // 3. URL encoding app.use(cookieParser()); // 4. Cookie parsing app.use(SSOMiddleware.initialize()); // 5. Auth initialization // ... routes registered here app.use(auditMiddleware); // 6. Audit (if global) app.use(errorBoundary); // 7. Error handler (LAST) app.use(Sentry.Handlers.errorHandler()); // 8. Sentry errors (LAST) ``` **Rule:** Error handlers must be registered AFTER routes! --- ## Service Comparison ### Email Service (Mature Pattern ✅) **Strengths:** - Comprehensive BaseController with Sentry integration - Clean route delegation (no business logic in routes) - Consistent dependency injection pattern - Good middleware organization - Type-safe throughout - Excellent error handling **Example Structure:** ``` email/src/ ├── controllers/ │ ├── BaseController.ts ✅ Excellent template │ ├── NotificationController.ts ✅ Extends BaseController │ └── EmailController.ts ✅ Clean patterns ├── routes/ │ ├── notificationRoutes.ts ✅ Clean delegation │ └── emailRoutes.ts ✅ No business logic ├── services/ │ ├── NotificationService.ts ✅ Dependency injection │ └── BatchingService.ts ✅ Clear responsibility └── middleware/ ├── errorBoundary.ts ✅ Comprehensive └── DevImpersonationSSOMiddleware.ts ``` **Use as template** for new services! ### Form Service (Transitioning ⚠️) **Strengths:** - Excellent workflow architecture (event sourcing) - Good Sentry integration - Innovative audit middleware (AsyncLocalStorage) - Comprehensive permission system **Weaknesses:** - Some routes have 200+ lines of business logic - Inconsistent controller naming - Direct process.env usage (60+ occurrences) - Minimal repository pattern usage **Example:** ``` form/src/ ├── routes/ │ ├── responseRoutes.ts ❌ Business logic in routes │ └── proxyRoutes.ts ✅ Good validation pattern ├── controllers/ │ ├── formController.ts ⚠️ Lowercase naming │ └── UserProfileController.ts ✅ PascalCase naming ├── workflow/ ✅ Excellent architecture! │ ├── core/ │ │ ├── WorkflowEngineV3.ts ✅ Event sourcing │ │ └── DryRunWrapper.ts ✅ Innovative │ └── services/ └── middleware/ └── auditMiddleware.ts ✅ AsyncLocalStorage pattern ``` **Learn from:** workflow/, middleware/auditMiddleware.ts **Avoid:** responseRoutes.ts, direct process.env --- ## Directory Structure Rationale ### Controllers Directory **Purpose:** Handle HTTP request/response concerns **Contents:** - `BaseController.ts` - Base class with common methods - `{Feature}Controller.ts` - Feature-specific controllers **Naming:** PascalCase + Controller **Responsibilities:** - Parse request parameters - Validate input (Zod) - Call appropriate service methods - Format responses - Handle errors (via BaseController) - Set HTTP status codes ### Services Directory **Purpose:** Business logic and orchestration **Contents:** - `{feature}Service.ts` - Feature business logic **Naming:** camelCase + Service (or PascalCase + Service) **Responsibilities:** - Implement business rules - Orchestrate multiple repositories - Transaction management - Business validations - No HTTP knowledge (Request/Response types) ### Repositories Directory **Purpose:** Data access abstraction **Contents:** - `{Entity}Repository.ts` - Database operations for entity **Naming:** PascalCase + Repository **Responsibilities:** - Prisma query operations - Query optimization - Database error handling - Caching layer - Hide Prisma implementation details **Current Gap:** Only 1 repository exists (WorkflowRepository) ### Routes Directory **Purpose:** Route registration ONLY **Contents:** - `{feature}Routes.ts` - Express router for feature **Naming:** camelCase + Routes **Responsibilities:** - Register routes with Express - Apply middleware - Delegate to controllers - **NO business logic!** ### Middleware Directory **Purpose:** Cross-cutting concerns **Contents:** - Authentication middleware - Audit middleware - Error boundaries - Validation middleware - Custom middleware **Naming:** camelCase **Types:** - Request processing (before handler) - Response processing (after handler) - Error handling (error boundary) ### Config Directory **Purpose:** Configuration management **Contents:** - `unifiedConfig.ts` - Type-safe configuration - Environment-specific configs **Pattern:** Single source of truth ### Types Directory **Purpose:** TypeScript type definitions **Contents:** - `{feature}.types.ts` - Feature-specific types - DTOs (Data Transfer Objects) - Request/Response types - Domain models --- ## Module Organization ### Feature-Based Organization For large features, use subdirectories: ``` src/workflow/ ├── core/ # Core engine ├── services/ # Workflow-specific services ├── actions/ # System actions ├── models/ # Domain models ├── validators/ # Workflow validation └── utils/ # Workflow utilities ``` **When to use:** - Feature has 5+ files - Clear sub-domains exist - Logical grouping improves clarity ### Flat Organization For simple features: ``` src/ ├── controllers/UserController.ts ├── services/userService.ts ├── routes/userRoutes.ts └── repositories/UserRepository.ts ``` **When to use:** - Simple features (< 5 files) - No clear sub-domains - Flat structure is clearer --- ## Separation of Concerns ### What Goes Where **Routes Layer:** - ✅ Route definitions - ✅ Middleware registration - ✅ Controller delegation - ❌ Business logic - ❌ Database operations - ❌ Validation logic (should be in validator or controller) **Controllers Layer:** - ✅ Request parsing (params, body, query) - ✅ Input validation (Zod) - ✅ Service calls - ✅ Response formatting - ✅ Error handling - ❌ Business logic - ❌ Database operations **Services Layer:** - ✅ Business logic - ✅ Business rules enforcement - ✅ Orchestration (multiple repos) - ✅ Transaction management - ❌ HTTP concerns (Request/Response) - ❌ Direct Prisma calls (use repositories) **Repositories Layer:** - ✅ Prisma operations - ✅ Query construction - ✅ Database error handling - ✅ Caching - ❌ Business logic - ❌ HTTP concerns ### Example: User Creation **Route:** ```typescript router.post('/users', SSOMiddleware.verifyLoginStatus, auditMiddleware, (req, res) => userController.create(req, res) ); ``` **Controller:** ```typescript async create(req: Request, res: Response): Promise { try { const validated = createUserSchema.parse(req.body); const user = await this.userService.create(validated); this.handleSuccess(res, user, 'User created'); } catch (error) { this.handleError(error, res, 'create'); } } ``` **Service:** ```typescript async create(data: CreateUserDTO): Promise { // Business rule: check if email already exists const existing = await this.userRepository.findByEmail(data.email); if (existing) throw new ConflictError('Email already exists'); // Create user return await this.userRepository.create(data); } ``` **Repository:** ```typescript async create(data: CreateUserDTO): Promise { return PrismaService.main.user.create({ data }); } async findByEmail(email: string): Promise { return PrismaService.main.user.findUnique({ where: { email } }); } ``` **Notice:** Each layer has clear, distinct responsibilities! --- **Related Files:** - [SKILL.md](SKILL.md) - Main guide - [routing-and-controllers.md](routing-and-controllers.md) - Routes and controllers details - [services-and-repositories.md](services-and-repositories.md) - Service and repository patterns