# Pattern Comparison: Template vs IAM Service

## Overview

This document compares implementation patterns between `_template` (baseline microservice) and `iam-service` (production implementation) to guide documentation updates.

## Module Structure Pattern

### Template Pattern (Simple)
```
src/modules/
├── common/          # Base repository, shared types
├── feature/         # Example CRUD module
├── health/          # Health checks
└── metrics/         # Prometheus metrics
```

### IAM Pattern (Production)
```
src/modules/
├── common/          # Base repository, shared types (same)
├── feature/         # Example CRUD module (inherited)
├── health/          # Health checks (same)
├── metrics/         # Prometheus metrics (same)
├── auth/            # + Core authentication
├── rbac/            # + Authorization
├── token/           # + Token management
├── session/         # + Session management
├── mfa/             # + Multi-factor auth
├── social/          # + Social OAuth
├── oidc/            # + OpenID Connect
├── identity/        # + Identity management
├── access/          # + Access workflows
└── governance/      # + Compliance & reporting
```

**Documentation Impact**:
- Template docs should focus on **foundational patterns**
- IAM docs should show **advanced patterns** and **real-world implementation**

---

## Controller Pattern

### Template (Basic)
```typescript
// src/modules/feature/feature.controller.ts
export class FeatureController {
  constructor(private service: FeatureService) {}

  async create(req: Request, res: Response, next: NextFunction) {
    try {
      const dto = CreateFeatureDto.parse(req.body);
      const result = await this.service.create(dto);
      res.status(201).json({ success: true, data: result });
    } catch (error) {
      next(error);
    }
  }
}
```

### IAM (Production with Auth)
```typescript
// src/modules/identity/identity.controller.ts
export class IdentityController {
  constructor(
    private service: IdentityService,
    private auditService: AuditService
  ) {}

  @RequireAuth()
  @RequirePermission('users', 'create')
  @RateLimit('strict')
  async create(req: Request, res: Response, next: NextFunction) {
    try {
      const dto = CreateUserDto.parse(req.body);
      const result = await this.service.create(dto);
      
      // Audit logging
      await this.auditService.log('USER_CREATED', req.user.id, {
        userId: result.id,
        correlationId: req.correlationId,
      });
      
      res.status(201).json({ success: true, data: result });
    } catch (error) {
      next(error);
    }
  }
}
```

**Pattern Differences**:
1. **Decorators**: IAM uses decorators for auth, permissions, rate limiting
2. **Audit Logging**: IAM logs all operations
3. **Dependency Injection**: IAM injects multiple services (Service + AuditService)

**Documentation Impact**:
- Template docs: Show basic controller pattern
- IAM docs: Show auth decorators, audit logging, multi-service injection

---

## Service Pattern

### Template (Simple Business Logic)
```typescript
// src/modules/feature/feature.service.ts
export class FeatureService {
  constructor(private repository: FeatureRepository) {}

  async create(data: CreateFeatureDto) {
    // Business validation
    const existing = await this.repository.findByName(data.name);
    if (existing) {
      throw new ConflictError('Feature already exists');
    }
    
    return await this.repository.create(data);
  }
}
```

### IAM (with Caching & Complex Logic)
```typescript
// src/modules/rbac/rbac.service.ts
export class RBACService {
  constructor(
    private repository: RBACRepository,
    private cacheService: CacheService,
    private auditService: AuditService
  ) {}

  async checkPermission(
    userId: string,
    resource: string,
    action: string
  ): Promise<boolean> {
    // Try cache first (L1 → L2)
    const cacheKey = `user:${userId}:permissions`;
    const cached = await this.cacheService.get<string[]>(cacheKey);
    
    let permissions: string[];
    if (cached) {
      permissions = cached;
    } else {
      // Cache miss - fetch from DB
      const userRoles = await this.repository.getUserRoles(userId);
      const rolePermissions = await this.repository.getRolePermissions(userRoles);
      const directPermissions = await this.repository.getUserPermissions(userId);
      
      permissions = [...rolePermissions, ...directPermissions];
      
      // Cache for 5 minutes
      await this.cacheService.set(cacheKey, permissions, 300);
    }
    
    // Check permission
    const required = `${resource}:${action}`;
    const hasPermission = permissions.some(p => this.matchesPermission(p, required));
    
    // Audit log
    await this.auditService.log(
      hasPermission ? 'ACCESS_GRANTED' : 'ACCESS_DENIED',
      userId,
      { resource, action }
    );
    
    return hasPermission;
  }

  private matchesPermission(granted: string, required: string): boolean {
    // Handle wildcards: users:*:* matches users:create:org
    const grantedParts = granted.split(':');
    const requiredParts = required.split(':');
    
    return grantedParts.every((part, i) => 
      part === '*' || part === requiredParts[i]
    );
  }
}
```

**Pattern Differences**:
1. **Caching**: IAM uses multi-layer caching
2. **Complex Logic**: Permission matching with wildcards
3. **Audit Logging**: Every operation logged
4. **Performance**: Cache-first approach for frequently accessed data

**Documentation Impact**:
- Template docs: Simple business logic
- IAM docs: Caching strategies, complex permission logic, audit logging

---

## Repository Pattern

### Template (Basic CRUD)
```typescript
// src/modules/feature/feature.repository.ts
export class FeatureRepository extends BaseRepository<Feature> {
  constructor(prisma: PrismaClient) {
    super(prisma, 'feature');
  }

  async findByName(name: string): Promise<Feature | null> {
    return this.prisma.feature.findUnique({ where: { name } });
  }
}
```

### IAM (with Joins & Complex Queries)
```typescript
// src/modules/rbac/rbac.repository.ts
export class RBACRepository extends BaseRepository<Role> {
  constructor(prisma: PrismaClient) {
    super(prisma, 'role');
  }

  async getUserRoles(userId: string): Promise<string[]> {
    const userRoles = await this.prisma.userRole.findMany({
      where: {
        userId,
        OR: [
          { expiresAt: null },
          { expiresAt: { gt: new Date() } }
        ]
      },
      include: { role: true }
    });
    
    return userRoles.map(ur => ur.role.name);
  }

  async getRolePermissions(roleNames: string[]): Promise<string[]> {
    const rolePermissions = await this.prisma.rolePermission.findMany({
      where: { role: { name: { in: roleNames } } },
      include: { permission: true }
    });
    
    return rolePermissions.map(rp => rp.permission.code);
  }

  async getUserPermissions(userId: string): Promise<string[]> {
    const userPermissions = await this.prisma.userPermission.findMany({
      where: { userId },
      include: { permission: true }
    });
    
    return userPermissions.map(up => up.permission.code);
  }
}
```

**Pattern Differences**:
1. **Complex Joins**: IAM uses nested includes
2. **Conditional Logic**: Expiration checking
3. **Data Aggregation**: Combining data from multiple sources

**Documentation Impact**:
- Template docs: Basic CRUD with unique lookups
- IAM docs: Complex joins, conditional queries, data aggregation

---

## Middleware Pattern

### Template (Basic)
```typescript
// src/middlewares/logger.middleware.ts
export const loggerMiddleware = (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = Date.now() - start;
    logger.info('Request completed', {
      method: req.method,
      url: req.url,
      statusCode: res.statusCode,
      duration,
    });
  });
  
  next();
};
```

### IAM (with Correlation IDs & Audit)
```typescript
// src/middlewares/logger.middleware.ts
export const loggerMiddleware = (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  const start = Date.now();
  const correlationId = req.correlationId || generateCorrelationId();
  
  // Attach to request for downstream use
  req.correlationId = correlationId;
  res.setHeader('x-correlation-id', correlationId);
  
  res.on('finish', () => {
    const duration = Date.now() - start;
    logger.info('Request completed', {
      correlationId,
      method: req.method,
      url: req.url,
      statusCode: res.statusCode,
      duration,
      userId: req.user?.id,
      ipAddress: req.ip,
      userAgent: req.headers['user-agent'],
    });
    
    // Audit logging for sensitive endpoints
    if (req.url.startsWith('/api/v1/auth') || req.url.startsWith('/api/v1/rbac')) {
      auditService.log('API_REQUEST', req.user?.id, {
        method: req.method,
        url: req.url,
        statusCode: res.statusCode,
        correlationId,
      });
    }
  });
  
  next();
};
```

**Pattern Differences**:
1. **Correlation IDs**: IAM propagates correlation IDs
2. **Enhanced Context**: User ID, IP, user agent
3. **Audit Integration**: Sensitive endpoints get audit logs

**Documentation Impact**:
- Template docs: Basic request logging
- IAM docs: Distributed tracing, audit integration, correlation IDs

---

## Configuration Pattern

### Template (Simple Zod Validation)
```typescript
// src/config/app.config.ts
import { z } from 'zod';

const envSchema = z.object({
  PORT: z.coerce.number().default(5000),
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  DATABASE_URL: z.string().url(),
  REDIS_URL: z.string().url().optional(),
});

const env = envSchema.parse(process.env);

export const appConfig = {
  port: env.PORT,
  env: env.NODE_ENV,
  database: { url: env.DATABASE_URL },
  redis: { url: env.REDIS_URL },
};
```

### IAM (with Nested Configs & Secrets)
```typescript
// src/config/app.config.ts
import { z } from 'zod';

const envSchema = z.object({
  // Server
  PORT: z.coerce.number().default(3001),
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  
  // Database
  DATABASE_URL: z.string().url(),
  DATABASE_POOL_SIZE: z.coerce.number().default(10),
  
  // Redis
  REDIS_HOST: z.string().default('localhost'),
  REDIS_PORT: z.coerce.number().default(6379),
  REDIS_PASSWORD: z.string().optional(),
  REDIS_DB: z.coerce.number().default(0),
  
  // JWT
  JWT_SECRET: z.string().min(32),
  JWT_REFRESH_SECRET: z.string().min(32),
  JWT_ACCESS_EXPIRY: z.string().default('15m'),
  JWT_REFRESH_EXPIRY: z.string().default('7d'),
  
  // Encryption
  ENCRYPTION_KEY: z.string().min(32).optional(),
  
  // OAuth
  GOOGLE_CLIENT_ID: z.string().optional(),
  GOOGLE_CLIENT_SECRET: z.string().optional(),
  FACEBOOK_APP_ID: z.string().optional(),
  FACEBOOK_APP_SECRET: z.string().optional(),
  GITHUB_CLIENT_ID: z.string().optional(),
  GITHUB_CLIENT_SECRET: z.string().optional(),
  
  // Feature Flags
  MFA_ENABLED: z.coerce.boolean().default(true),
  SOCIAL_AUTH_ENABLED: z.coerce.boolean().default(true),
  TRACING_ENABLED: z.coerce.boolean().default(false),
});

const env = envSchema.parse(process.env);

export const appConfig = {
  server: {
    port: env.PORT,
    env: env.NODE_ENV,
  },
  database: {
    url: env.DATABASE_URL,
    poolSize: env.DATABASE_POOL_SIZE,
  },
  redis: {
    host: env.REDIS_HOST,
    port: env.REDIS_PORT,
    password: env.REDIS_PASSWORD,
    db: env.REDIS_DB,
  },
  jwt: {
    secret: env.JWT_SECRET,
    refreshSecret: env.JWT_REFRESH_SECRET,
    accessExpiry: env.JWT_ACCESS_EXPIRY,
    refreshExpiry: env.JWT_REFRESH_EXPIRY,
  },
  encryption: {
    key: env.ENCRYPTION_KEY,
  },
  oauth: {
    google: {
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
    },
    facebook: {
      appId: env.FACEBOOK_APP_ID,
      appSecret: env.FACEBOOK_APP_SECRET,
    },
    github: {
      clientId: env.GITHUB_CLIENT_ID,
      clientSecret: env.GITHUB_CLIENT_SECRET,
    },
  },
  features: {
    mfa: env.MFA_ENABLED,
    socialAuth: env.SOCIAL_AUTH_ENABLED,
    tracing: env.TRACING_ENABLED,
  },
};
```

**Pattern Differences**:
1. **Nested Configuration**: IAM groups related configs
2. **Secrets Management**: JWT, encryption, OAuth secrets
3. **Feature Flags**: Runtime feature toggles
4. **Complex Validation**: Min length requirements, optional fields

**Documentation Impact**:
-Template docs: Show basic Zod validation
- IAM docs: Show nested configs, secrets management, feature flags

---

## Testing Pattern

### Template (Simple Unit Test)
```typescript
// src/modules/feature/__tests__/feature.service.test.ts
describe('FeatureService', () => {
  let service: FeatureService;
  let mockRepository: any;

  beforeEach(() => {
    mockRepository = {
      findByName: jest.fn(),
      create: jest.fn(),
    };
    service = new FeatureService(mockRepository);
  });

  it('should create feature', async () => {
    mockRepository.findByName.mockResolvedValue(null);
    mockRepository.create.mockResolvedValue({ id: '1', name: 'test' });
    
    const result = await service.create({ name: 'test' });
    
    expect(result).toEqual({ id: '1', name: 'test' });
    expect(mockRepository.create).toHaveBeenCalledWith({ name: 'test' });
  });

  it('should throw conflict error if feature exists', async () => {
    mockRepository.findByName.mockResolvedValue({ id: '1', name: 'test' });
    
    await expect(service.create({ name: 'test' }))
      .rejects
      .toThrow(ConflictError);
  });
});
```

### IAM (with Mocking Complete Dependencies)
```typescript
// src/modules/rbac/__tests__/rbac.service.test.ts
describe('RBACService', () => {
  let service: RBACService;
  let mockRepository: any;
  let mockCacheService: any;
  let mockAuditService: any;

  beforeEach(() => {
    mockRepository = {
      getUserRoles: jest.fn(),
      getRolePermissions: jest.fn(),
      getUserPermissions: jest.fn(),
    };
    mockCacheService = {
      get: jest.fn(),
      set: jest.fn(),
    };
    mockAuditService = {
      log: jest.fn(),
    };
    
    service = new RBACService(
      mockRepository,
      mockCacheService,
      mockAuditService
    );
  });

  describe('checkPermission', () => {
    it('should return true if user has permission (cache hit)', async () => {
      mockCacheService.get.mockResolvedValue(['users:create:*', 'posts:read:*']);
      
      const result = await service.checkPermission('user1', 'users', 'create');
      
      expect(result).toBe(true);
      expect(mockCacheService.get).toHaveBeenCalledWith('user:user1:permissions');
      expect(mockRepository.getUserRoles).not.toHaveBeenCalled(); // Cache hit
      expect(mockAuditService.log).toHaveBeenCalledWith(
        'ACCESS_GRANTED',
        'user1',
        { resource: 'users', action: 'create' }
      );
    });

    it('should return false if user lacks permission (cache miss)', async () => {
      mockCacheService.get.mockResolvedValue(null); // Cache miss
      mockRepository.getUserRoles.mockResolvedValue(['user']);
      mockRepository.getRolePermissions.mockResolvedValue(['posts:read:*']);
      mockRepository.getUserPermissions.mockResolvedValue([]);
      
      const result = await service.checkPermission('user1', 'users', 'delete');
      
      expect(result).toBe(false);
      expect(mockCacheService.set).toHaveBeenCalledWith(
        'user:user1:permissions',
        ['posts:read:*'],
        300
      );
      expect(mockAuditService.log).toHaveBeenCalledWith(
        'ACCESS_DENIED',
        'user1',
        { resource: 'users', action: 'delete' }
      );
    });

    it('should handle wildcard permissions', async () => {
      mockCacheService.get.mockResolvedValue(['users:*:*']);
      
      const result = await service.checkPermission('user1', 'users', 'create');
      
      expect(result).toBe(true);
    });
  });
});
```

**Pattern Differences**:
1. **Multiple Dependencies**: IAM mocks repository, cache, audit
2. **Cache Behavior**: Tests cache hit and cache miss scenarios
3. **Audit Verification**: Ensures audit logs are created
4. **Complex Logic**: Tests wildcard permission matching

**Documentation Impact**:
- Template docs: Simple mocking, basic test cases
- IAM docs: Complex mocking, cache behavior, audit verification

---

## Summary Table

| Pattern | Template | IAM | Docs to Update |
|---------|----------|-----|----------------|
| **Controller** | Basic try-catch | + Auth decorators, audit | `api-design.md`, `middleware-patterns.md` |
| **Service** | Simple logic | + Caching, complex logic | `service-layer-patterns.md`, `caching-patterns.md` |
| **Repository** | Basic CRUD | + Complex joins, aggregation | `repository-pattern.md`, `database-prisma.md` |
| **Middleware** | Basic logging | + Correlation IDs, audit | `middleware-patterns.md`, `observability-monitoring.md` |
| **Configuration** | Simple Zod | + Nested configs, secrets | `configuration-management.md` |
| **Testing** | Simple mocks | + Multi-dependency mocks | `testing-patterns.md` |
| **Caching** | None | Multi-layer (L1/L2/L3) | `caching-patterns.md` (NEW examples) |
| **Security** | Helmet only | + Zero-trust, encryption | `security.md` (NEW examples) |
| **Authorization** | None | RBAC + ABAC | NEW skill docs needed |
| **Audit Logging** | None | Event sourcing | `observability-monitoring.md` |

---

## Recommended Documentation Updates

### High Priority
1. **Update `caching-patterns.md`** with IAM multi-layer caching
2. **Update `security.md`** with zero-trust, encryption, JWT patterns
3. **Update `service-layer-patterns.md`** with caching integration
4. **Update `middleware-patterns.md`** with correlation IDs, audit
5. **Update `testing-patterns.md`** with complex mocking examples

### Medium Priority
6. **Update `repository-pattern.md`** with complex joins
7. **Update `api-design.md`** with auth middleware patterns
8. **Update `configuration-management.md`** with secrets management
9. **Update `observability-monitoring.md`** with audit logging

### New Content Needed
10. **RBAC patterns** (currently basic in user rules)
11. **Event sourcing** (audit logging implementation)
12. **Zero-trust architecture** (security validation)

---

## Code Example Sources

All code examples in docs should reference:
- **Template**: For foundational patterns
- **IAM Service**: For production patterns

**Example Mapping**:
- `_template/src/modules/feature/feature.service.ts` → Basic service pattern
- `iam-service/src/modules/rbac/rbac.service.ts` → Advanced service with caching
- `iam-service/src/core/cache/multi-layer-cache.ts` → Caching implementation
- `iam-service/src/core/security/zero-trust-validator.ts` → Security patterns
