dorfteich/apps/api/src/app.module.ts
Claude Fable 5 c12acbdb2c Add NestJS API skeleton with config, logging, and /healthz
apps/api boots a NestJS application with: Zod-validated environment
configuration (schema in @dorfteich/shared, fails fast listing every
invalid variable), structured pino request logging via nestjs-pino
(pretty in development, JSON otherwise, auth headers redacted), a
global exception filter producing the uniform ApiErrorBody shape, and
GET /api/v1/healthz. Vitest runs Nest through SWC for decorator
metadata; supertest covers healthz and the 404 error shape.

Closes #2

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:10:07 +02:00

31 lines
1.1 KiB
TypeScript

import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { LoggerModule } from 'nestjs-pino';
import { ApiExceptionFilter } from './common/api-exception.filter';
import { AppConfig } from './config/app-config.service';
import { ConfigModule } from './config/config.module';
import { HealthModule } from './health/health.module';
@Module({
imports: [
ConfigModule,
LoggerModule.forRootAsync({
inject: [AppConfig],
useFactory: (config: AppConfig) => ({
pinoHttp: {
level: config.env.LOG_LEVEL,
// Human-readable logs in local development, JSON everywhere else.
transport: config.env.NODE_ENV === 'development' ? { target: 'pino-pretty' } : undefined,
autoLogging: config.env.NODE_ENV !== 'test',
// Request bodies are never logged (operations.md logging rules).
redact: { paths: ['req.headers.authorization', 'req.headers.cookie'], remove: true },
},
}),
}),
HealthModule,
],
providers: [{ provide: APP_FILTER, useClass: ApiExceptionFilter }],
})
export class AppModule {}