mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
feat(r0.10): apps/api — auth fermée par défaut, matrice en base, démo-login ADR-002, seed
- packages/shared : rôles/catégories, schémas Zod, contrat d'API ; pnpm contract → docs/openapi.json committée (règle d'or ADR-001) - apps/api : NestJS 11 + Prisma 6, migration r0_identity (Role/Permission/User) ; guard JWT global + @Public() ; PermissionsGuard (@RequirePermission, matrice relue en base, cache 60 s) ; FileStorage (seul import MinIO) ; /health - démo-login ADR-002 : module conditionnel DEMO_MODE (404 sinon, testé e2e), double verrou production, refus des comptes isDemo=false - seed idempotent : 7 rôles, matrice complète (70 lignes), 7 comptes démo - 19 tests Jest (unit + e2e) ; smoke test sur build de prod Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
53
apps/api/src/health/health.controller.ts
Normal file
53
apps/api/src/health/health.controller.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Controller, Get, Inject } from '@nestjs/common';
|
||||
import type { HealthResponse } from '@siop/shared';
|
||||
import Redis from 'ioredis';
|
||||
import { Public } from '../auth/public.decorator';
|
||||
import { loadEnv } from '../config/env';
|
||||
import { FILE_STORAGE, type FileStorage } from '../files/file-storage';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
|
||||
@Controller('health')
|
||||
export class HealthController {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
@Inject(FILE_STORAGE) private readonly storage: FileStorage,
|
||||
) {}
|
||||
|
||||
@Public()
|
||||
@Get()
|
||||
async health(): Promise<HealthResponse> {
|
||||
const [database, redis, storage] = await Promise.all([
|
||||
this.check(() => this.prisma.$queryRaw`SELECT 1`),
|
||||
this.check(async () => {
|
||||
const client = new Redis(loadEnv().REDIS_URL, {
|
||||
lazyConnect: true,
|
||||
maxRetriesPerRequest: 0,
|
||||
connectTimeout: 2000,
|
||||
});
|
||||
try {
|
||||
await client.connect();
|
||||
await client.ping();
|
||||
} finally {
|
||||
client.disconnect();
|
||||
}
|
||||
}),
|
||||
this.check(() => this.storage.healthCheck()),
|
||||
]);
|
||||
const services = { database, redis, storage };
|
||||
return {
|
||||
status: Object.values(services).every((s) => s === 'up')
|
||||
? 'ok'
|
||||
: 'degraded',
|
||||
services,
|
||||
};
|
||||
}
|
||||
|
||||
private async check(fn: () => Promise<unknown>): Promise<'up' | 'down'> {
|
||||
try {
|
||||
await fn();
|
||||
return 'up';
|
||||
} catch {
|
||||
return 'down';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user