managarten/COMPATIBILITY_MATRIX_AND_REMEDIATION.md
Wuesteon 5b0b3095ff 🔒️ feat(auth): centralize JWT validation and add deployment docs
- Migrate Chat, Picture, Presi, Zitare backends to shared auth guards
- Remove duplicate local JWT guards and decorators
- Add CD staging workflow for tagged releases
- Add comprehensive auth architecture documentation
- Add Hetzner deployment and Docker setup guides
- Add environment configuration audit docs
- Update env generation scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 20:44:45 +01:00

1144 lines
33 KiB
Markdown

# Backend Compatibility Matrix & Remediation Plan
## Mana Universe Monorepo
**Date:** 2025-12-01
**Source of Truth:** mana-core-auth (port 3001, `/api/v1`)
**Status:** ⚠️ FUNCTIONAL BUT NEEDS STANDARDIZATION
---
## Quick Reference Compatibility Matrix
| Feature | mana-core-auth | Chat | Picture | Zitare | Presi | ManaDeck | Status |
|---------|---------------|------|---------|--------|-------|----------|--------|
| **Route Prefix** | `/api/v1` ✅ | `/api` ⚠️ | `/api` ⚠️ | `/api` ⚠️ | `/api` ⚠️ | `/v1` ❌ | INCONSISTENT |
| **Port** | 3001 ✅ | 3002 ⚠️ | 3006 ✅ | 3007 ✅ | 3008 ✅ | 8080 ⚠️ | CONFLICTS |
| **Auth Package** | N/A | Custom ❌ | Custom ❌ | Shared ✅ | Custom ❌ | Integration ✅ | FRAGMENTED |
| **JWT Validation** | Source ✅ | Works ✅ | Works ✅ | Works ✅ | Works ✅ | Works ✅ | COMPATIBLE |
| **Field Naming** | `sub` ✅ | `userId` ⚠️ | `userId` ⚠️ | `userId` ⚠️ | `sub` ✅ | `sub` ✅ | MIXED |
| **Dev Bypass** | N/A | Yes ✅ | No ❌ | Yes ✅ | Yes ✅ | Yes ✅ | MISSING (1) |
| **Dev User ID** | N/A | `000...` ✅ | Custom ❌ | `000...` ✅ | N/A | Config ✅ | INCONSISTENT |
| **@CurrentUser** | N/A | No ❌ | No ❌ | Yes ✅ | No ❌ | Yes ✅ | MISSING (3) |
| **@Public** | N/A | No ❌ | No ❌ | No ❌ | No ❌ | Yes ✅ | MISSING (4) |
| **Env Validation** | Yes ✅ | No ❌ | No ❌ | No ❌ | No ❌ | Yes ✅ | MISSING (4) |
| **Health Checks** | Advanced ✅ | Basic ⚠️ | Basic ⚠️ | Basic ⚠️ | Terminus ✅ | Terminus ✅ | MIXED |
| **CORS Config** | Config ✅ | Hardcoded ❌ | Hardcoded ❌ | Hardcoded ❌ | Hardcoded ❌ | Hardcoded ❌ | HARDCODED (5) |
### Legend
- ✅ Fully compliant with source of truth
- ⚠️ Works but deviates from standard
- ❌ Missing or incompatible
---
## Detailed Feature Comparison
### 1. API Route Structure
| Backend | Current Prefix | Current Version | Target Prefix | Migration Effort |
|---------|---------------|----------------|---------------|-----------------|
| mana-core-auth | `/api/v1` | v1 | N/A (source) | N/A |
| Chat | `/api` | None | `/api/v1` | 5 min |
| Picture | `/api` | None | `/api/v1` | 5 min |
| Zitare | `/api` | None | `/api/v1` | 5 min |
| Presi | `/api` | None | `/api/v1` | 5 min |
| ManaDeck | `/v1` | v1 | `/api/v1` | 10 min + client updates |
**Compatibility:** ⚠️ PARTIAL - All backends reachable but inconsistent client URLs
---
### 2. Port Allocation
| Backend | Current Port | Has Conflict | Target Port | Migration Effort |
|---------|-------------|--------------|-------------|-----------------|
| mana-core-auth | 3001 | No | 3001 | N/A |
| Chat | 3002 | **Yes** (Nutriphi) | 3002 | Move Nutriphi to 3010 |
| Picture | 3006 | **Yes** (Maerchenzauber) | 3006 | Move Maerchenzauber to 3011 |
| Zitare | 3007 | No | 3007 | N/A |
| Presi | 3008 | No | 3008 | N/A |
| ManaDeck | 8080 | No | 3009 | 5 min |
**Compatibility:** ❌ BLOCKED - Cannot run all backends simultaneously
---
### 3. Authentication Implementation
| Backend | Current Guard | Package Location | Target Package | Migration Effort |
|---------|--------------|-----------------|----------------|-----------------|
| mana-core-auth | N/A | N/A | N/A | N/A |
| Chat | `JwtAuthGuard` | Local (58 lines) | `@manacore/shared-nestjs-auth` | 30 min |
| Picture | `JwtAuthGuard` | Local (52 lines) | `@manacore/shared-nestjs-auth` | 30 min |
| Zitare | `JwtAuthGuard` | `@manacore/shared-nestjs-auth` | No change | N/A |
| Presi | `AuthGuard` | Local (47 lines) | `@mana-core/nestjs-integration` | 1 hour |
| ManaDeck | `AuthGuard` | `@mana-core/nestjs-integration` | No change | N/A |
**Compatibility:** ✅ COMPATIBLE - All validate via mana-core-auth correctly
**Code Duplication:** 157 lines of duplicate guard logic to eliminate
---
### 4. JWT Token Field Mapping
| Backend/Package | User ID Field | Email Field | Role Field | Session Field | Compatible |
|----------------|--------------|-------------|------------|---------------|-----------|
| JWT Payload (source) | `sub` | `email` | `role` | `sid` / `sessionId` | N/A |
| `@manacore/shared-nestjs-auth` | `userId` ⚠️ | `email` ✅ | `role` ✅ | `sessionId` ✅ | MAPPED |
| `@mana-core/nestjs-integration` | `sub` ✅ | `email` ✅ | `role` ✅ | `sessionId` ✅ | EXACT |
| Chat (local) | `userId` ⚠️ | `email` ✅ | `role` ✅ | `sessionId` ✅ | MAPPED |
| Picture (local) | `userId` ⚠️ | `email` ✅ | `role` ✅ | `sessionId` ✅ | MAPPED |
| Presi (local) | `sub` ✅ | `email` ✅ | `role` ✅ | N/A | PARTIAL |
**Compatibility:** ⚠️ FUNCTIONAL - Different field names but values correct
**Issue:** Code not portable between backends using `userId` vs `sub`
---
### 5. Development Mode Support
| Backend | Dev Bypass | Dev User ID | Dev User Email | Config Source |
|---------|-----------|------------|----------------|--------------|
| mana-core-auth | N/A | N/A | N/A | N/A |
| Chat | ✅ YES | `000...000` | `test@example.com` | Hardcoded const |
| Picture | ❌ NO | `17cb...014` | N/A | Hardcoded const (unused) |
| Zitare | ✅ YES | `000...000` | `dev@example.com` | Shared package |
| Presi | ✅ YES | N/A | N/A | Local guard (no bypass implemented) |
| ManaDeck | ✅ YES | Configurable | `dev@example.com` | Environment variable |
**Compatibility:** ⚠️ MIXED - Picture lacks dev bypass entirely
**Issue:** 3 different dev user IDs in use
---
### 6. Decorator Support
| Backend | `@CurrentUser()` | `@CurrentUser('field')` | `@Public()` | `OptionalAuthGuard` |
|---------|-----------------|------------------------|-------------|-------------------|
| mana-core-auth | N/A | N/A | N/A | N/A |
| Chat | ❌ NO | ❌ NO | ❌ NO | ❌ NO |
| Picture | ❌ NO | ❌ NO | ❌ NO | ❌ NO |
| Zitare | ✅ YES | ❌ NO | ❌ NO | ❌ NO |
| Presi | ❌ NO | ❌ NO | ❌ NO | ❌ NO |
| ManaDeck | ✅ YES | ✅ YES | ✅ YES | ✅ YES |
**Compatibility:** ❌ FRAGMENTED - Feature parity varies widely
---
### 7. Environment Configuration
| Variable | mana-core-auth | Chat | Picture | Zitare | Presi | ManaDeck | Standardized |
|----------|---------------|------|---------|--------|-------|----------|--------------|
| `MANA_CORE_AUTH_URL` | N/A | ✅ | ✅ | ✅ | ✅ | ❌ (uses `MANA_SERVICE_URL`) | NO |
| `NODE_ENV` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | YES |
| `PORT` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | YES |
| `DEV_BYPASS_AUTH` | N/A | ✅ | ❌ | ✅ | ✅ | ✅ | NO (missing 1) |
| `DEV_USER_ID` | N/A | Hardcoded | Hardcoded | Hardcoded | N/A | ✅ | NO |
| `CORS_ORIGINS` | ✅ | Hardcoded | Hardcoded | Hardcoded | Hardcoded | Hardcoded | NO |
| Validation Schema | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | NO (missing 4) |
**Compatibility:** ⚠️ FUNCTIONAL - Configs work but naming inconsistent
---
### 8. Code Organization
| Backend | Structure | Controllers | Largest File | Modular | Maintainability |
|---------|-----------|------------|-------------|---------|----------------|
| mana-core-auth | Modular | 3 | ~200 lines | ✅ YES | HIGH |
| Chat | Modular | 6 | ~150 lines | ✅ YES | HIGH |
| Picture | Modular | 6 | ~180 lines | ✅ YES | HIGH |
| Zitare | Modular | 2 | ~100 lines | ✅ YES | HIGH |
| Presi | Modular | 4 | ~200 lines | ✅ YES | HIGH |
| ManaDeck | **Monolithic** | 3 (1 huge) | **971 lines** | ❌ NO | LOW |
**Compatibility:** ✅ MOSTLY GOOD - Only ManaDeck needs refactoring
---
## Compatibility Risk Assessment
### Risk Level: MEDIUM
**Why MEDIUM and not HIGH:**
- ✅ All backends can authenticate successfully
- ✅ JWT validation works correctly
- ✅ No data corruption or security vulnerabilities
- ✅ All backends can run (just not simultaneously)
**Why MEDIUM and not LOW:**
- ⚠️ Port conflicts prevent simultaneous execution
- ⚠️ Code duplication creates maintenance burden
- ⚠️ Inconsistent patterns confuse developers
- ⚠️ Missing features limit functionality
### Compatibility Scores by Category
| Category | Score | Status |
|----------|-------|--------|
| **JWT Validation** | 10/10 | ✅ PERFECT - All backends validate correctly |
| **API Routes** | 4/10 | ❌ POOR - Inconsistent prefixes and versioning |
| **Port Allocation** | 3/10 | ❌ POOR - Conflicts prevent simultaneous use |
| **Auth Implementation** | 6/10 | ⚠️ FAIR - Works but duplicated code |
| **Environment Config** | 5/10 | ⚠️ FAIR - Functional but inconsistent naming |
| **Code Organization** | 7/10 | ✅ GOOD - Only ManaDeck needs work |
| **Developer Experience** | 5/10 | ⚠️ FAIR - Inconsistent patterns confuse |
| **Maintainability** | 5/10 | ⚠️ FAIR - Duplicate code increases burden |
**Overall Compatibility: 6.2/10**
---
## Remediation Plan
### Phase 1: Emergency Fixes (2-3 hours)
**Goal:** Enable simultaneous backend execution
**Urgency:** IMMEDIATE
**Blocking:** Development, testing, demos
#### Task 1.1: Fix Port Conflicts (30 minutes)
**Conflicts to resolve:**
1. Port 3002: Chat vs Nutriphi
2. Port 3003: Picture vs Maerchenzauber
**Actions:**
```bash
# Edit .env.development
CHAT_BACKEND_PORT=3002 # Keep (active)
NUTRIPHI_BACKEND_PORT=3010 # Move (archived)
PICTURE_BACKEND_PORT=3006 # Fix (documented as 3006)
MAERCHENZAUBER_BACKEND_PORT=3011 # Move (archived)
```
**Files to edit:**
- `.env.development` (2 lines changed)
- `apps/picture/apps/backend/src/main.ts:52` (change default from 3003 to 3006)
**Validation:**
```bash
pnpm dev:chat:backend &
pnpm dev:picture:backend &
pnpm dev:zitare:backend &
pnpm dev:presi:backend &
pnpm dev:manadeck:backend &
# All should start without port conflicts
ps aux | grep node
```
#### Task 1.2: Standardize Route Prefix (1 hour)
**Decision needed:** Choose one standard
**Option A: Full compliance** (`/api/v1`)
```typescript
// All backends
app.setGlobalPrefix('api/v1');
```
- ✅ Matches source of truth exactly
- ✅ Future-proof for versioning
- ⚠️ Requires client URL updates for all backends
**Option B: Prepare for versioning** (`/api`)
```typescript
// All backends
app.setGlobalPrefix('api');
```
- ✅ Minimal changes (only ManaDeck affected)
- ✅ Easy to add /v1 later
- ⚠️ Doesn't match source of truth now
**Recommended: Option A** (Full compliance)
**Actions:**
```typescript
// Edit each main.ts
// Chat: apps/chat/apps/backend/src/main.ts:36
// Picture: apps/picture/apps/backend/src/main.ts:50
// Zitare: apps/zitare/apps/backend/src/main.ts:32
// Presi: apps/presi/apps/backend/src/main.ts:33
// ManaDeck: apps/manadeck/apps/backend/src/main.ts:39
app.setGlobalPrefix('api/v1', {
exclude: ['health', 'health/ready', 'health/live']
});
```
**Files to edit:** 5 main.ts files
#### Task 1.3: Add DEV_USER_ID to Central Config (30 minutes)
**Actions:**
```bash
# Add to .env.development
DEV_USER_ID=00000000-0000-0000-0000-000000000000
```
```typescript
// Update Chat guard: apps/chat/apps/backend/src/common/guards/jwt-auth.guard.ts:8
- const DEV_USER_ID = '17cb0be7-058a-4964-9e18-1fe7055fd014';
+ const devUserId = this.configService.get<string>('DEV_USER_ID') ||
+ '00000000-0000-0000-0000-000000000000';
// Update Picture guard similarly
```
**Files to edit:**
- `.env.development` (1 line added)
- `scripts/generate-env.mjs` (add DEV_USER_ID mapping)
- `apps/chat/apps/backend/src/common/guards/jwt-auth.guard.ts`
- `apps/picture/apps/backend/src/common/guards/jwt-auth.guard.ts`
**Validation:**
```bash
# Test dev bypass
curl http://localhost:3002/api/v1/health \
-H "X-Test: dev-mode" # Should work with DEV_BYPASS_AUTH=true
```
#### Task 1.4: Add Dev Bypass to Picture Backend (30 minutes)
**Action:**
```typescript
// apps/picture/apps/backend/src/common/guards/jwt-auth.guard.ts
// Add after line 20 (before token extraction)
const isDev = this.configService.get<string>('NODE_ENV') === 'development';
const bypassAuth = this.configService.get<string>('DEV_BYPASS_AUTH') === 'true';
if (isDev && bypassAuth) {
const devUserId = this.configService.get<string>('DEV_USER_ID') ||
'00000000-0000-0000-0000-000000000000';
request.user = {
userId: devUserId,
email: 'dev@example.com',
role: 'user',
sessionId: 'dev-session',
};
return true;
}
```
**Validation:**
```bash
# Set env vars
export DEV_BYPASS_AUTH=true
export NODE_ENV=development
# Test Picture backend
curl http://localhost:3006/api/v1/health
# Should work without Bearer token
```
---
### Phase 2: Standardization (4-6 hours)
**Goal:** Eliminate code duplication and inconsistencies
**Urgency:** HIGH (this week)
**Impact:** Code quality, maintainability
#### Task 2.1: Migrate Chat to Shared Auth Package (1 hour)
**Current:** Custom local guard (58 lines)
**Target:** `@manacore/shared-nestjs-auth`
**Actions:**
1. Install package (if not already)
```bash
pnpm add @manacore/shared-nestjs-auth --filter @chat/backend
```
2. Update all imports
```typescript
// Find all files with: import { JwtAuthGuard } from './common/guards/jwt-auth.guard'
// Replace with: import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth'
// Files to update:
// apps/chat/apps/backend/src/**/*.controller.ts
```
3. Add decorators
```typescript
// Before
@UseGuards(JwtAuthGuard)
@Get('profile')
getProfile(@Request() req) {
return { user: req.user };
}
// After
@UseGuards(JwtAuthGuard)
@Get('profile')
getProfile(@CurrentUser() user: CurrentUserData) {
return { user };
}
```
4. Delete local guard
```bash
rm apps/chat/apps/backend/src/common/guards/jwt-auth.guard.ts
```
**Validation:**
```bash
# Run tests
pnpm --filter @chat/backend test
# Test auth flow
TOKEN=$(curl -X POST http://localhost:3001/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password"}' | jq -r '.accessToken')
curl http://localhost:3002/api/v1/profile \
-H "Authorization: Bearer $TOKEN"
```
#### Task 2.2: Migrate Picture to Shared Auth Package (1 hour)
**Same steps as Task 2.1**, but for Picture backend
**Files affected:**
- All `apps/picture/apps/backend/src/**/*.controller.ts`
- Delete `apps/picture/apps/backend/src/common/guards/jwt-auth.guard.ts`
#### Task 2.3: Migrate Presi to Mana Core Integration (2 hours)
**Current:** Custom local guard (47 lines)
**Target:** `@mana-core/nestjs-integration` (for credit support)
**Actions:**
1. Install package
```bash
pnpm add @mana-core/nestjs-integration --filter @presi/backend
```
2. Configure module
```typescript
// apps/presi/apps/backend/src/app.module.ts
import { ManaCoreModule } from '@mana-core/nestjs-integration';
@Module({
imports: [
ManaCoreModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
appId: config.get('APP_ID'),
serviceKey: config.get('MANA_CORE_SERVICE_KEY'),
debug: config.get('NODE_ENV') === 'development',
}),
inject: [ConfigService],
}),
],
})
```
3. Update all controllers
```typescript
// Before
import { AuthGuard } from '../auth/auth.guard';
// After
import { AuthGuard } from '@mana-core/nestjs-integration/guards';
import { CurrentUser } from '@mana-core/nestjs-integration/decorators';
```
4. Add environment variables
```bash
# .env.development
PRESI_APP_ID=presi
PRESI_MANA_CORE_SERVICE_KEY=your-service-key
```
5. Delete local guard
```bash
rm apps/presi/apps/backend/src/auth/auth.guard.ts
```
**Validation:** Same as Tasks 2.1 and 2.2
#### Task 2.4: Standardize Auth URL Variable (30 minutes)
**Changes:**
```bash
# .env.development
# ManaDeck: Rename MANA_SERVICE_URL → MANA_CORE_AUTH_URL
- MANADECK_MANA_SERVICE_URL=http://localhost:3001
+ MANADECK_MANA_CORE_AUTH_URL=http://localhost:3001
# Nutriphi: Rename MANACORE_AUTH_URL → MANA_CORE_AUTH_URL
- NUTRIPHI_MANACORE_AUTH_URL=http://localhost:3001
+ NUTRIPHI_MANA_CORE_AUTH_URL=http://localhost:3001
```
```javascript
// scripts/generate-env.mjs
// Update mappings for ManaDeck and Nutriphi
```
**Files to edit:**
- `.env.development`
- `scripts/generate-env.mjs`
- `apps/manadeck/apps/backend/.env.example` (if exists)
#### Task 2.5: Extract CORS Origins to Environment (1 hour)
**Changes:**
```bash
# .env.development
CORS_ORIGINS=http://localhost:5173,http://localhost:3000,http://localhost:4173
```
```typescript
// Each main.ts
const corsOrigins = configService
.get<string>('CORS_ORIGINS')
?.split(',')
.map(origin => origin.trim()) || ['http://localhost:5173'];
app.enableCors({
origin: corsOrigins,
credentials: true,
});
```
**Files to edit:**
- `.env.development` (add CORS_ORIGINS)
- `apps/chat/apps/backend/src/main.ts:20`
- `apps/picture/apps/backend/src/main.ts:34`
- `apps/zitare/apps/backend/src/main.ts:18`
- `apps/presi/apps/backend/src/main.ts:19`
---
### Phase 3: Code Quality (6-8 hours)
**Goal:** Add missing features and improve maintainability
**Urgency:** MEDIUM (next week)
**Impact:** Error handling, observability, code quality
#### Task 3.1: Add Environment Validation Schemas (2 hours)
**For each backend** (Chat, Picture, Zitare, Presi):
1. Install Joi
```bash
pnpm add joi --filter @{backend}/backend
```
2. Create validation schema
```typescript
// apps/{backend}/apps/backend/src/config/validation.schema.ts
import * as Joi from 'joi';
export const validationSchema = Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production', 'test')
.default('development'),
PORT: Joi.number().default(3000),
MANA_CORE_AUTH_URL: Joi.string().uri().required(),
DEV_BYPASS_AUTH: Joi.boolean().default(false),
DEV_USER_ID: Joi.string().optional(),
CORS_ORIGINS: Joi.string().default('http://localhost:5173'),
// Add backend-specific vars
});
```
3. Register in module
```typescript
// apps/{backend}/apps/backend/src/app.module.ts
import { validationSchema } from './config/validation.schema';
@Module({
imports: [
ConfigModule.forRoot({
validationSchema,
validationOptions: {
abortEarly: false, // Show all errors
},
}),
],
})
```
**Validation:**
```bash
# Test with missing var
unset MANA_CORE_AUTH_URL
pnpm dev:{backend}:backend
# Should see clear error:
# "Configuration validation failed:
# - MANA_CORE_AUTH_URL is required"
```
#### Task 3.2: Refactor ManaDeck Controller (3-4 hours)
**Current:** 971-line monolithic controller
**Target:** Feature-based modular structure
**New structure:**
```
apps/manadeck/apps/backend/src/
├── controllers/
│ ├── health.controller.ts (existing, keep)
│ └── public.controller.ts (existing, keep)
├── modules/
│ ├── deck/
│ │ ├── deck.controller.ts (NEW - ~150 lines)
│ │ ├── deck.service.ts
│ │ └── deck.module.ts
│ ├── card/
│ │ ├── card.controller.ts (NEW - ~200 lines)
│ │ ├── card.service.ts
│ │ └── card.module.ts
│ ├── study-session/
│ │ ├── study-session.controller.ts (NEW - ~180 lines)
│ │ ├── study-session.service.ts
│ │ └── study-session.module.ts
│ ├── progress/
│ │ ├── progress.controller.ts (NEW - ~120 lines)
│ │ ├── progress.service.ts
│ │ └── progress.module.ts
│ └── ai/
│ ├── ai.controller.ts (NEW - ~150 lines)
│ ├── ai.service.ts
│ └── ai.module.ts
└── app.module.ts (update imports)
```
**Migration steps:**
1. Create feature modules
2. Extract routes from api.controller.ts
3. Move business logic to services
4. Update app.module.ts imports
5. Delete old api.controller.ts
6. Test all endpoints
**Validation:**
```bash
# Run full test suite
pnpm --filter @manadeck/backend test
# Test each feature endpoint
curl http://localhost:3009/api/v1/decks -H "Authorization: Bearer $TOKEN"
curl http://localhost:3009/api/v1/cards -H "Authorization: Bearer $TOKEN"
# etc.
```
#### Task 3.3: Standardize Health Checks (1-2 hours)
**Add Terminus to** Chat, Picture, Zitare:
1. Install Terminus
```bash
pnpm add @nestjs/terminus --filter @{backend}/backend
```
2. Create health module
```typescript
// apps/{backend}/apps/backend/src/health/health.module.ts
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HttpModule } from '@nestjs/axios';
import { HealthController } from './health.controller';
@Module({
imports: [TerminusModule, HttpModule],
controllers: [HealthController],
})
export class HealthModule {}
```
3. Update health controller
```typescript
// apps/{backend}/apps/backend/src/health/health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { HealthCheck, HealthCheckService, HttpHealthIndicator } from '@nestjs/terminus';
@Controller('health')
export class HealthController {
constructor(
private health: HealthCheckService,
private http: HttpHealthIndicator,
) {}
@Get()
@HealthCheck()
check() {
return this.health.check([
() => this.http.pingCheck('mana-core-auth', 'http://localhost:3001/api/v1/health'),
]);
}
@Get('ready')
@HealthCheck()
readiness() {
return this.health.check([
() => this.http.pingCheck('auth-service', 'http://localhost:3001/api/v1/health'),
// Add database check, etc.
]);
}
@Get('live')
liveness() {
return { status: 'ok', timestamp: new Date().toISOString() };
}
}
```
**Validation:**
```bash
curl http://localhost:3002/health
curl http://localhost:3002/health/ready
curl http://localhost:3002/health/live
```
#### Task 3.4: Create Missing .env.example Files (30 minutes)
**For Zitare:**
```bash
# apps/zitare/apps/backend/.env.example
NODE_ENV=development
PORT=3007
MANA_CORE_AUTH_URL=http://localhost:3001
DEV_BYPASS_AUTH=true
DEV_USER_ID=00000000-0000-0000-0000-000000000000
CORS_ORIGINS=http://localhost:5173
SUPABASE_URL=your-supabase-url
SUPABASE_ANON_KEY=your-anon-key
```
**For Presi:**
```bash
# apps/presi/apps/backend/.env.example
NODE_ENV=development
PORT=3008
MANA_CORE_AUTH_URL=http://localhost:3001
DEV_BYPASS_AUTH=true
DEV_USER_ID=00000000-0000-0000-0000-000000000000
CORS_ORIGINS=http://localhost:5173
APP_ID=presi
MANA_CORE_SERVICE_KEY=your-service-key
SUPABASE_URL=your-supabase-url
SUPABASE_ANON_KEY=your-anon-key
```
#### Task 3.5: Add @Public Decorator to Shared Auth (1 hour)
**Update shared package:**
```typescript
// packages/shared-nestjs-auth/src/decorators/public.decorator.ts (NEW)
import { SetMetadata } from '@nestjs/common';
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
```
```typescript
// packages/shared-nestjs-auth/src/guards/jwt-auth.guard.ts
import { IS_PUBLIC_KEY } from '../decorators/public.decorator';
async canActivate(context: ExecutionContext): Promise<boolean> {
// Check for @Public decorator
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
if (isPublic) {
return true;
}
// Continue with normal auth check
// ...
}
```
```typescript
// packages/shared-nestjs-auth/src/index.ts
export { Public } from './decorators/public.decorator';
```
**Usage in backends:**
```typescript
import { Public } from '@manacore/shared-nestjs-auth';
@Public()
@Get('webhook')
handleWebhook() {
// No auth required
}
```
---
### Phase 4: Observability & Advanced Features (4-6 hours)
**Goal:** Production-ready monitoring and resilience
**Urgency:** LOW (future sprint)
**Impact:** Debugging, reliability, security
#### Task 4.1: Add Request Context Logging (1 hour)
**Update all guards:**
```typescript
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
// Log in development
if (process.env.NODE_ENV === 'development') {
console.log(`[${new Date().toISOString()}] Auth check: ${request.method} ${request.path}`);
}
// Continue with auth logic
// ...
}
```
#### Task 4.2: Implement Circuit Breaker (2-3 hours)
**Add circuit breaker for auth service:**
```typescript
// packages/shared-nestjs-auth/src/utils/circuit-breaker.ts
export class CircuitBreaker {
private failureCount = 0;
private readonly threshold = 5;
private readonly timeout = 30000; // 30 seconds
private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
private openedAt: number = 0;
async call<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === 'OPEN') {
if (Date.now() - this.openedAt > this.timeout) {
this.state = 'HALF_OPEN';
} else {
throw new Error('Circuit breaker is OPEN');
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
private onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
private onFailure() {
this.failureCount++;
if (this.failureCount >= this.threshold) {
this.state = 'OPEN';
this.openedAt = Date.now();
}
}
}
```
#### Task 4.3: Standardize Error Response Format (1-2 hours)
**Create error codes enum:**
```typescript
// packages/shared-nestjs-auth/src/types/errors.ts
export enum AuthErrorCode {
NO_TOKEN = 'AUTH_NO_TOKEN',
INVALID_TOKEN = 'AUTH_INVALID_TOKEN',
EXPIRED_TOKEN = 'AUTH_EXPIRED_TOKEN',
SERVICE_UNAVAILABLE = 'AUTH_SERVICE_UNAVAILABLE',
}
export class AuthException extends UnauthorizedException {
constructor(
public readonly code: AuthErrorCode,
message: string,
public readonly details?: unknown,
) {
super({ code, message, details });
}
}
```
**Use in guards:**
```typescript
if (!token) {
throw new AuthException(
AuthErrorCode.NO_TOKEN,
'No authorization token provided'
);
}
if (!result.valid) {
throw new AuthException(
AuthErrorCode.INVALID_TOKEN,
'Invalid or expired token',
{ reason: result.error }
);
}
```
#### Task 4.4: Add Integration Tests (2-3 hours)
**Create auth integration test suite:**
```typescript
// packages/shared-nestjs-auth/src/__tests__/integration.spec.ts
describe('Auth Integration Tests', () => {
it('should validate valid JWT token', async () => {
// Get token from mana-core-auth
const token = await getTestToken();
// Call protected endpoint
const response = await request(app.getHttpServer())
.get('/protected')
.set('Authorization', `Bearer ${token}`)
.expect(200);
expect(response.body.user).toBeDefined();
});
it('should reject invalid token', async () => {
await request(app.getHttpServer())
.get('/protected')
.set('Authorization', 'Bearer invalid-token')
.expect(401);
});
it('should allow dev bypass in development', async () => {
process.env.NODE_ENV = 'development';
process.env.DEV_BYPASS_AUTH = 'true';
await request(app.getHttpServer())
.get('/protected')
.expect(200);
});
});
```
---
## Remediation Timeline
### Sprint Overview
| Phase | Duration | Start | End | Effort | Priority |
|-------|----------|-------|-----|--------|----------|
| Phase 1: Emergency Fixes | 2-3 hours | Day 1 | Day 1 | 1 dev | CRITICAL |
| Phase 2: Standardization | 4-6 hours | Day 2 | Day 3 | 1 dev | HIGH |
| Phase 3: Code Quality | 6-8 hours | Day 4 | Day 6 | 1 dev | MEDIUM |
| Phase 4: Observability | 4-6 hours | Week 2 | Week 2 | 1 dev | LOW |
**Total Effort:** 16-23 hours (2-3 developer days)
### Critical Path
```
Day 1 (CRITICAL):
└─ Phase 1: Emergency Fixes (2-3 hours)
├─ Task 1.1: Fix port conflicts (30 min) ← BLOCKING
├─ Task 1.2: Standardize route prefix (1 hour)
├─ Task 1.3: Add DEV_USER_ID to config (30 min)
└─ Task 1.4: Add dev bypass to Picture (30 min)
Day 2-3 (HIGH):
└─ Phase 2: Standardization (4-6 hours)
├─ Task 2.1: Migrate Chat auth (1 hour)
├─ Task 2.2: Migrate Picture auth (1 hour)
├─ Task 2.3: Migrate Presi auth (2 hours)
├─ Task 2.4: Standardize auth URL var (30 min)
└─ Task 2.5: Extract CORS to env (1 hour)
Day 4-6 (MEDIUM):
└─ Phase 3: Code Quality (6-8 hours)
├─ Task 3.1: Add validation schemas (2 hours)
├─ Task 3.2: Refactor ManaDeck controller (3-4 hours)
├─ Task 3.3: Standardize health checks (1-2 hours)
├─ Task 3.4: Create .env.example files (30 min)
└─ Task 3.5: Add @Public decorator (1 hour)
Week 2 (LOW):
└─ Phase 4: Observability (4-6 hours)
├─ Task 4.1: Add request logging (1 hour)
├─ Task 4.2: Circuit breaker (2-3 hours)
├─ Task 4.3: Standardize errors (1-2 hours)
└─ Task 4.4: Integration tests (2-3 hours)
```
---
## Success Criteria
### Phase 1 Complete When:
- [ ] All 5 active backends start simultaneously without port conflicts
- [ ] All backends use same route prefix pattern
- [ ] Dev user ID is centralized and consistent
- [ ] Picture backend has dev bypass support
### Phase 2 Complete When:
- [ ] Zero duplicate auth guard code
- [ ] All backends use shared packages
- [ ] Auth URL variable naming is consistent
- [ ] CORS origins are configurable via environment
### Phase 3 Complete When:
- [ ] All backends have environment validation
- [ ] ManaDeck uses modular controller structure
- [ ] Health checks are standardized with Terminus
- [ ] All backends have .env.example files
- [ ] @Public decorator available in all backends
### Phase 4 Complete When:
- [ ] Request context logging enabled
- [ ] Circuit breaker protects against auth service failures
- [ ] Error responses include codes and details
- [ ] Integration test suite achieves 80% coverage
### Overall Success (All Phases):
- [ ] Compatibility score: 9/10 or higher
- [ ] Zero code duplication in auth logic
- [ ] Consistent API patterns across all backends
- [ ] Comprehensive documentation
- [ ] All backends production-ready
---
## Rollback Plan
### If Phase 1 Fails:
```bash
# Restore original port configuration
git checkout -- .env.development
git checkout -- apps/picture/apps/backend/src/main.ts
# Restart backends with original config
pnpm install
```
### If Phase 2 Fails:
```bash
# Revert shared package migrations
git checkout -- apps/chat/apps/backend/src
git checkout -- apps/picture/apps/backend/src
git checkout -- apps/presi/apps/backend/src
# Restore local guards
git restore apps/*/apps/backend/src/*/guards/*.ts
```
### If Phase 3/4 Fails:
- Code quality improvements don't break functionality
- Can be rolled back individually without affecting other phases
---
## Post-Remediation Validation
### Comprehensive Test Suite
```bash
#!/bin/bash
# test-compatibility.sh
echo "Starting all backends..."
pnpm dev:chat:backend &
pnpm dev:picture:backend &
pnpm dev:zitare:backend &
pnpm dev:presi:backend &
pnpm dev:manadeck:backend &
sleep 10
echo "Testing authentication flow..."
TOKEN=$(curl -s -X POST http://localhost:3001/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password"}' \
| jq -r '.accessToken')
if [ -z "$TOKEN" ]; then
echo "❌ Failed to get auth token"
exit 1
fi
echo "Testing each backend..."
for PORT in 3002 3006 3007 3008 3009; do
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
http://localhost:$PORT/api/v1/health \
-H "Authorization: Bearer $TOKEN")
if [ "$RESPONSE" = "200" ]; then
echo "✅ Backend on port $PORT: OK"
else
echo "❌ Backend on port $PORT: FAILED ($RESPONSE)"
fi
done
echo "Testing dev bypass..."
export DEV_BYPASS_AUTH=true
export NODE_ENV=development
for PORT in 3002 3006 3007 3008 3009; do
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
http://localhost:$PORT/api/v1/health)
if [ "$RESPONSE" = "200" ]; then
echo "✅ Dev bypass on port $PORT: OK"
else
echo "❌ Dev bypass on port $PORT: FAILED"
fi
done
echo "All tests complete!"
```
### Compatibility Scorecard (Post-Remediation Target)
| Category | Current Score | Target Score | Status |
|----------|--------------|--------------|--------|
| JWT Validation | 10/10 | 10/10 | ✅ Already perfect |
| API Routes | 4/10 | 10/10 | 📈 Phase 1 fixes |
| Port Allocation | 3/10 | 10/10 | 📈 Phase 1 fixes |
| Auth Implementation | 6/10 | 10/10 | 📈 Phase 2 fixes |
| Environment Config | 5/10 | 9/10 | 📈 Phases 2-3 fix |
| Code Organization | 7/10 | 9/10 | 📈 Phase 3 fixes |
| Developer Experience | 5/10 | 9/10 | 📈 All phases |
| Maintainability | 5/10 | 9/10 | 📈 All phases |
**Overall Target: 9.4/10** (up from 6.2/10)
---
## Summary
This remediation plan addresses **18 identified issues** across 5 backends:
- **3 critical blocking issues** (Phase 1 - 2-3 hours)
- **8 high-priority deviations** (Phase 2 - 4-6 hours)
- **7 medium-priority improvements** (Phases 3-4 - 10-14 hours)
**Total estimated effort:** 16-23 hours (2-3 developer days)
**Expected outcome:**
- Zero port conflicts
- Consistent API patterns
- Shared authentication packages
- No code duplication
- Production-ready observability
- Compatibility score: 6.2/10 → 9.4/10
**Risk level after remediation:** LOW (from MEDIUM)
---
**Document Version:** 1.0
**Last Updated:** 2025-12-01
**Next Review:** After Phase 2 completion