Files
TREK/server/src/nest/app.module.ts
T
Maurice cc9587676a Give the feature-flag endpoint a health module of its own
GET /api/health/features lived in booking-import, which meant the client's
capability probe was reachable only because that domain happened to be
registered. Move it to health/ and give health an actual module instead of
two loose entries in app.module.

The extractor probe follows into a leaf module rather than health importing
BookingImportModule: features() needs isAvailable(), not llm-parse,
reservations, budget, maps and places.

The /api/_nest/{health,me,echo} smoke endpoints go. They proved boot, DI,
the cookie guard and the Zod pipe back when nothing else did; every one of
those now has real domain coverage, and nothing outside their own test ever
called them. The container probe is GET /api/health on the raw express layer
and is untouched.
2026-08-10 13:38:26 +02:00

84 lines
5.3 KiB
TypeScript

import { Module } from '@nestjs/common';
import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
import { ZodValidationPipe } from './common/zod-validation.pipe';
import { AppConfigModule } from './app-config/app-config.module';
import { DatabaseModule } from './database/database.module';
import { RealtimeModule } from './realtime/realtime.module';
import { HealthModule } from './health/health.module';
import { WeatherModule } from './weather/weather.module';
import { HelpModule } from './help/help.module';
import { AirportsModule } from './airports/airports.module';
import { ConfigModule } from './config/config.module';
import { SystemNoticesModule } from './system-notices/system-notices.module';
import { MapsModule } from './maps/maps.module';
import { PlaceEnrichmentModule } from './place-enrichment/place-enrichment.module';
import { CategoriesModule } from './categories/categories.module';
import { TagsModule } from './tags/tags.module';
import { NotificationsModule } from './notifications/notifications.module';
import { AtlasModule } from './atlas/atlas.module';
import { VacayModule } from './vacay/vacay.module';
import { PackingModule } from './packing/packing.module';
import { BudgetModule } from './budget/budget.module';
import { ReservationsModule } from './reservations/reservations.module';
import { DaysModule } from './days/days.module';
import { AssignmentsModule } from './assignments/assignments.module';
import { PlacesModule } from './places/places.module';
import { TripsModule } from './trips/trips.module';
import { TodoModule } from './todo/todo.module';
import { CollabModule } from './collab/collab.module';
import { FilesModule } from './files/files.module';
import { PhotosModule } from './photos/photos.module';
import { MemoriesModule } from './memories/memories.module';
import { AirtrailModule } from './integrations/airtrail.module';
import { JourneyModule } from './journey/journey.module';
import { CollectionsModule } from './collections/collections.module';
import { ShareModule } from './share/share.module';
import { TripInviteModule } from './trip-invite/trip-invite.module';
import { TransitModule } from './transit/transit.module';
import { FeedsModule } from './feeds/feeds.module';
import { SettingsModule } from './settings/settings.module';
import { BackupModule } from './backup/backup.module';
import { BookingImportModule } from './booking-import/booking-import.module';
import { LlmParseModule } from './llm-parse/llm-parse.module';
import { AuthModule } from './auth/auth.module';
import { OidcModule } from './oidc/oidc.module';
import { OauthModule } from './oauth/oauth.module';
import { AdminModule } from './admin/admin.module';
import { AddonsModule } from './addons/addons.module';
import { AuditModule } from './audit/audit.module';
import { PermissionsModule } from './permissions/permissions.module';
import { PluginsModule } from './plugins/plugins.module';
import { McpModule } from '@trek/nest-mcp';
import { trekMcpAccessPolicy, trekMcpValidateAccess } from '../mcp/nest-mcp-policy';
import { TrekExceptionFilter } from './common/trek-exception.filter';
import { SpaFallbackFilter } from './platform/spa-fallback.filter';
import { IdempotencyInterceptor } from './common/idempotency.interceptor';
/**
* Root NestJS module for the incremental migration. Domain modules
* (weather, notifications, integrations, ...) get registered here as they are
* migrated.
*/
@Module({
imports: [AppConfigModule, DatabaseModule, RealtimeModule, McpModule.forRoot({ accessPolicy: trekMcpAccessPolicy, validateAccess: trekMcpValidateAccess }), HealthModule, WeatherModule, HelpModule, AirportsModule, ConfigModule, SystemNoticesModule, MapsModule, PlaceEnrichmentModule, CategoriesModule, TagsModule, NotificationsModule, AtlasModule, VacayModule, PackingModule, TodoModule, BudgetModule, ReservationsModule, DaysModule, AssignmentsModule, PlacesModule, TripsModule, CollabModule, FilesModule, PhotosModule, MemoriesModule, AirtrailModule, JourneyModule, CollectionsModule, ShareModule, TripInviteModule, TransitModule, FeedsModule, SettingsModule, BackupModule, AuthModule, OidcModule, OauthModule, AdminModule, AddonsModule, AuditModule, PermissionsModule, PluginsModule, BookingImportModule, LlmParseModule],
providers: [
// Global error-envelope normaliser (DI-registered so it also catches
// framework-level exceptions like the not-found handler).
{ provide: APP_FILTER, useClass: TrekExceptionFilter },
// SPA fallback: serves index.html for unmatched GETs in production (the Nest
// equivalent of the legacy Express app.get('*') catch-all). @Catch(NotFoundException)
// is more specific than TrekExceptionFilter, so Nest routes 404s here.
{ provide: APP_FILTER, useClass: SpaFallbackFilter },
// Replays the X-Idempotency-Key the client sends on every write, so retried
// mutations don't double-apply.
{ provide: APP_INTERCEPTOR, useClass: IdempotencyInterceptor },
// Global Zod validation: any parameter typed with a createZodDto class
// (the <domain>.dto.ts wrappers over @trek/shared schemas) is validated;
// everything else passes through untouched. Paired with the boot gate in
// common/validate-body-contracts.ts so unvalidated mutation bodies refuse
// to boot instead of shipping silently.
{ provide: APP_PIPE, useClass: ZodValidationPipe },
],
})
export class AppModule {}