import { Controller, Get, HttpStatus, Res } from '@nestjs/common'; import { HealthResponse, healthResponse } from '@dorfteich/shared'; import type { Response } from 'express'; import { Public } from '../auth/auth.guard'; import { MaintenanceExempt } from '../backup/maintenance.guard'; import { AppConfig } from '../config/app-config.service'; import { SetupExempt } from '../setup/setup.guard'; import { ReadinessService } from './readiness.service'; @Public() @SetupExempt() // deploys and monitors must see health during first-run setup @MaintenanceExempt() // …and during an in-app restore (issue #103) @Controller() export class HealthController { constructor( private readonly config: AppConfig, private readonly readiness: ReadinessService, ) {} /** Liveness: the process is up. Used by Docker healthchecks. */ @Get('healthz') healthz(): HealthResponse { return healthResponse('api', this.config.env.APP_VERSION); } /** * Readiness: the api can do real work. Used by uptime monitoring. * The report body is sent as-is with 200/503 (not through the exception * filter) so monitors always see which check failed. `degraded` stays * HTTP 200 — 503 is reserved for hard failures (issue #85); monitors * catch degradation via a keyword check on the body (deploy/monitoring.md). */ @Get('readyz') async readyz(@Res() res: Response): Promise { const report = await this.readiness.report(); res .status(report.status === 'unready' ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.OK) .json(report); } }