From 9ab65cc7750e135e56d9d7ceee288eeb1b8ea10a Mon Sep 17 00:00:00 2001 From: autocommit Date: Sun, 17 May 2026 07:41:16 -0700 Subject: [PATCH] =?UTF-8?q?refactor(platform-api):=20=E2=99=BB=EF=B8=8F=20?= =?UTF-8?q?Restructure=20health=20module=20integration=20in=20platform-api?= =?UTF-8?q?,=20adding=20registration=20in=20app.module.ts,=20initializing?= =?UTF-8?q?=20checks=20in=20main.ts,=20and=20defining=20routes/controllers?= =?UTF-8?q?=20in=20health.module.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../@features/platform-api/src/app.module.ts | 38 +++++++++++++++ .../platform-api/src/health/health.module.ts | 25 ++++++++++ .../@features/platform-api/src/main.ts | 47 +++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 @platform/codebase/@features/platform-api/src/app.module.ts create mode 100644 @platform/codebase/@features/platform-api/src/health/health.module.ts create mode 100644 @platform/codebase/@features/platform-api/src/main.ts diff --git a/@platform/codebase/@features/platform-api/src/app.module.ts b/@platform/codebase/@features/platform-api/src/app.module.ts new file mode 100644 index 0000000..3d89616 --- /dev/null +++ b/@platform/codebase/@features/platform-api/src/app.module.ts @@ -0,0 +1,38 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { APP_GUARD } from '@nestjs/core'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AuthModule } from './auth/auth.module.js'; +import { QuinnSsoGuard } from './auth/quinn-sso.guard.js'; +import { CacheInvalidateModule } from './common/cache-invalidate.module.js'; +import { databaseConfig } from './config/database.config.js'; +import { HealthModule } from './health/health.module.js'; +import { AgentActionsModule } from './modules/agent-actions/agent-actions.module.js'; +import { ContentPlansModule } from './modules/content-plans/content-plans.module.js'; +import { ContentPostsModule } from './modules/content-posts/content-posts.module.js'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + cache: true, + envFilePath: ['.env.local', '.env'], + }), + TypeOrmModule.forRootAsync(databaseConfig), + CacheInvalidateModule, + AuthModule, + HealthModule, + // V3 domain modules — add new modules here as they land. + // P0 ships content-plans + content-posts + agent-actions (the verification-gate trio). + // P1+ adds: users, orgs, personas, content-assets, engagement-events. + ContentPlansModule, + ContentPostsModule, + AgentActionsModule, + ], + providers: [ + // Global auth guard. Federates against quinn.sso (v2). Bypassed by @Public()-decorated routes. + { provide: APP_GUARD, useClass: QuinnSsoGuard }, + ], +}) +export class AppModule {} diff --git a/@platform/codebase/@features/platform-api/src/health/health.module.ts b/@platform/codebase/@features/platform-api/src/health/health.module.ts new file mode 100644 index 0000000..f09672b --- /dev/null +++ b/@platform/codebase/@features/platform-api/src/health/health.module.ts @@ -0,0 +1,25 @@ +import { Controller, Get, Module } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; + +import { Public } from '../auth/public.decorator.js'; + +interface HealthResponse { + status: 'ok'; + service: 'platform.api'; + ts: string; +} + +@ApiTags('health') +@Controller('health') +class HealthController { + @Get() + @Public() + check(): HealthResponse { + return { status: 'ok', service: 'platform.api', ts: new Date().toISOString() }; + } +} + +@Module({ + controllers: [HealthController], +}) +export class HealthModule {} diff --git a/@platform/codebase/@features/platform-api/src/main.ts b/@platform/codebase/@features/platform-api/src/main.ts new file mode 100644 index 0000000..3943f9b --- /dev/null +++ b/@platform/codebase/@features/platform-api/src/main.ts @@ -0,0 +1,47 @@ +import 'reflect-metadata'; + +import { Logger, ValidationPipe } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { NestFactory } from '@nestjs/core'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; + +import { AppModule } from './app.module.js'; + +async function bootstrap(): Promise { + const app = await NestFactory.create(AppModule, { bufferLogs: true }); + const config = app.get(ConfigService); + const logger = new Logger('Bootstrap'); + + app.useGlobalPipes( + new ValidationPipe({ + whitelist: true, + forbidNonWhitelisted: true, + transform: true, + transformOptions: { enableImplicitConversion: false }, + }), + ); + + app.setGlobalPrefix('api/v1', { exclude: ['health', 'health/(.*)'] }); + + if (config.get('NODE_ENV') !== 'production') { + const swaggerConfig = new DocumentBuilder() + .setTitle('platform.api') + .setDescription('V3 platform data plane — multi-tenant CRUD over platform.db') + .setVersion('0.1.0') + .addBearerAuth() + .build(); + const document = SwaggerModule.createDocument(app, swaggerConfig); + SwaggerModule.setup('docs', app, document); + } + + const port = config.get('PLATFORM_API_PORT', 3060); + await app.listen(port, '0.0.0.0'); + + logger.log(`platform.api listening on :${port} (env=${config.get('NODE_ENV') ?? 'development'})`); +} + +bootstrap().catch((err: unknown) => { + const logger = new Logger('Bootstrap'); + logger.error('Fatal bootstrap error', err instanceof Error ? err.stack : String(err)); + process.exit(1); +});