# 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<void> {
    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<User> {
    // 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<User> {
    return PrismaService.main.user.create({ data });
}

async findByEmail(email: string): Promise<User | null> {
    return PrismaService.main.user.findUnique({ where: { email } });
}
```

**Notice:** Each layer has clear, distinct responsibilities!

---

**Related Files:**
- 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
