first commit

This commit is contained in:
2026-10-03 13:40:26 +02:00
parent 732a5b5a16
commit 566f415fa7
555 changed files with 62704 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { MongooseModule } from '@nestjs/mongoose';
import { TypeOrmModule } from '@nestjs/typeorm';
import { IdentityApplicationModule } from '@task-stream/api/identity/application';
import { IdentityInfrastructureModule } from '@task-stream/api/identity/infrastructure';
import {
AuthRequest,
IdentityPresentersModule,
WsAuthenticator,
} from '@task-stream/api/identity/presenters';
import { SharedModule } from '@task-stream/api/shared/application';
import { SharedInfrastructureModule } from '@task-stream/api/shared/infrastructure';
import { TrackerApplicationModule } from '@task-stream/api/tracker/application';
import { TrackerInfrastructureModule } from '@task-stream/api/tracker/infrastructure';
import { TrackerPresentersModule } from '@task-stream/api/tracker/presenters';
import { join } from 'node:path';
import { configSchema } from './config.schema';
import { HealthController } from './health.controller';
/*
* Composition root. Each bounded context is assembled outside-in:
* presenters (GraphQL/HTTP) → application (services, CQRS handlers) → infrastructure (adapters)
*/
const identity = IdentityPresentersModule.withApplication(
IdentityApplicationModule.withInfrastructure(IdentityInfrastructureModule),
);
const tracker = TrackerPresentersModule.withApplication(
TrackerApplicationModule.withInfrastructure(TrackerInfrastructureModule),
);
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
validationSchema: configSchema,
cache: true,
}),
// Write model: PostgreSQL (event store + lookup tables)
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
type: 'postgres',
url: config.getOrThrow<string>('POSTGRES_URL'),
autoLoadEntities: true,
synchronize: config.get<boolean>('POSTGRES_SYNCHRONIZE'),
}),
}),
// Read model: MongoDB
MongooseModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
uri: config.getOrThrow<string>('MONGO_URL'),
}),
}),
// Event store (PostgreSQL) → Redis stream → events bridge, AggregateRehydrator
SharedModule.withInfrastructure(
SharedInfrastructureModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
redisUrl: config.getOrThrow<string>('REDIS_URL'),
streamKey: config.getOrThrow<string>('EVENT_STREAM_KEY'),
maxLength: config.getOrThrow<number>('EVENT_STREAM_MAX_LENGTH'),
eventsBridgeEnabled: config.getOrThrow<boolean>(
'EVENTS_BRIDGE_ENABLED',
),
}),
}),
),
// GraphQL + realtime subscriptions over graphql-ws
GraphQLModule.forRootAsync<ApolloDriverConfig>({
driver: ApolloDriver,
imports: [identity],
inject: [WsAuthenticator, ConfigService],
useFactory: (ws: WsAuthenticator, config: ConfigService) => ({
// Writes the SDL for frontend codegen; empty = keep the schema in memory.
autoSchemaFile: config.get<string>('GRAPHQL_SCHEMA_FILE')
? join(
process.cwd(),
config.get<string>('GRAPHQL_SCHEMA_FILE') as string,
)
: true,
sortSchema: true,
// GraphiQL on GET /graphql (send the Pireon token in the Headers tab).
graphiql: config.get<boolean>('GRAPHQL_PLAYGROUND')
? { url: '/graphql' }
: false,
playground: false,
includeStacktraceInErrorResponses:
config.get('NODE_ENV') === 'development',
introspection: config.get<boolean>('GRAPHQL_PLAYGROUND'),
subscriptions: {
'graphql-ws': {
path: '/graphql',
// connection_init payload: { "authorization": "Bearer <pireon token>" }
onConnect: async (ctx) => {
try {
(ctx.extra as { auth?: AuthRequest }).auth =
await ws.authenticate(ctx.connectionParams);
return true;
} catch {
return false; // closes the socket with 4403 Forbidden
}
},
},
},
context: ({
req,
extra,
}: {
req?: AuthRequest;
extra?: { auth?: AuthRequest };
}) => ({
req: extra?.auth ?? req,
}),
}),
}),
identity,
tracker,
],
controllers: [HealthController],
})
export class AppModule {}