import { Controller, Get, Inject, Optional } from '@nestjs/common'; import { ApiTags, ApiOperation } from '@nestjs/swagger'; import { Public } from '../common/decorators/public.decorator'; import { CrmPrismaService } from '../prisma/crm-prisma.service'; import { RedisService } from '../redis/redis.service'; import { LexwareClientService } from '../lexware/lexware-client.service'; import { EnrichmentService } from '../enrichment/enrichment.service'; interface HealthResponse { status: 'ok' | 'error'; service: string; timestamp: string; version: string; services: { database: 'up' | 'down'; redis: 'up' | 'down'; lexware: 'up' | 'down' | 'unconfigured'; enrichment: 'up' | 'down' | 'unconfigured'; }; } @ApiTags('Health') @Controller('health') export class HealthController { constructor( private readonly prisma: CrmPrismaService, private readonly redis: RedisService, @Optional() @Inject(LexwareClientService) private readonly lexwareClient?: LexwareClientService, @Optional() @Inject(EnrichmentService) private readonly enrichmentService?: EnrichmentService, ) {} @Get() @Public() @ApiOperation({ summary: 'Health-Check fuer CRM-Service' }) async check(): Promise { const [dbStatus, redisStatus, lexwareStatus, enrichmentStatus] = await Promise.allSettled([ this.checkDatabase(), this.checkRedis(), this.checkLexware(), this.checkEnrichment(), ]); const dbOk = dbStatus.status === 'fulfilled' && dbStatus.value; const redisOk = redisStatus.status === 'fulfilled' && redisStatus.value; const lexwareResult: 'up' | 'down' | 'unconfigured' = lexwareStatus.status === 'fulfilled' ? lexwareStatus.value : 'down'; const enrichmentResult: 'up' | 'down' | 'unconfigured' = enrichmentStatus.status === 'fulfilled' ? enrichmentStatus.value : 'down'; // "unconfigured" ist kein Fehler const allUp = dbOk && redisOk && lexwareResult !== 'down' && enrichmentResult !== 'down'; return { status: allUp ? 'ok' : 'error', service: 'crm-service', timestamp: new Date().toISOString(), version: '0.3.0', services: { database: dbOk ? 'up' : 'down', redis: redisOk ? 'up' : 'down', lexware: lexwareResult, enrichment: enrichmentResult, }, }; } private async checkDatabase(): Promise { try { await this.prisma.$queryRaw`SELECT 1`; return true; } catch { return false; } } private async checkRedis(): Promise { try { const pong = await this.redis.ping(); return pong === 'PONG'; } catch { return false; } } private async checkLexware(): Promise<'up' | 'down' | 'unconfigured'> { if (!this.lexwareClient) return 'unconfigured'; return this.lexwareClient.isHealthy(); } private async checkEnrichment(): Promise<'up' | 'down' | 'unconfigured'> { if (!this.enrichmentService) return 'unconfigured'; return this.enrichmentService.isHealthy(); } }