mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
- 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>
54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
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';
|
|
}
|
|
}
|
|
}
|