feat(13-03): wire SourceRegistry + TenderDedupService into TendersModule
Register SourceRegistry and TenderDedupService as providers. onModuleInit registers DoeOpenDataAdapter with the registry before the scheduler's first tick — the DI-boot-time enforcement point for the INGEST-07 denylist gate (D-06). This is Wave 2's sole writer of tenders.module.ts; 13-04 (NetServer) and 13-05 (cosinex) add their own registry.register(...) calls additively in later waves. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,9 @@ import { ModuleRegistryService } from '../module-registry/module-registry.servic
|
|||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { SettingsModule } from '../settings/settings.module';
|
import { SettingsModule } from '../settings/settings.module';
|
||||||
import { DoeOpenDataAdapter } from './adapters/doe-opendata.adapter';
|
import { DoeOpenDataAdapter } from './adapters/doe-opendata.adapter';
|
||||||
|
import { SourceRegistry } from './source-registry';
|
||||||
import { seedTendersModule } from './tenders.seed';
|
import { seedTendersModule } from './tenders.seed';
|
||||||
|
import { TenderDedupService } from './tender-dedup.service';
|
||||||
import { TenderDigestScheduler } from './tender-digest.scheduler';
|
import { TenderDigestScheduler } from './tender-digest.scheduler';
|
||||||
import { TenderIngestionService } from './tender-ingestion.service';
|
import { TenderIngestionService } from './tender-ingestion.service';
|
||||||
import { TenderMailService } from './tender-mail.service';
|
import { TenderMailService } from './tender-mail.service';
|
||||||
@@ -61,13 +63,27 @@ import { TendersController } from './tenders.controller';
|
|||||||
*
|
*
|
||||||
* Seeds itself into the module registry on application startup via
|
* Seeds itself into the module registry on application startup via
|
||||||
* OnModuleInit lifecycle hook — same pattern as DkvModule.
|
* OnModuleInit lifecycle hook — same pattern as DkvModule.
|
||||||
|
*
|
||||||
|
* Phase 13, Plan 03 (SCHEMA-03): adds `SourceRegistry` (fan-out lookup +
|
||||||
|
* INGEST-07 denylist gate, Plan 13-02) and `TenderDedupService`
|
||||||
|
* (three-tier cross-source dedup resolver, Plan 13-03 Task 1) as
|
||||||
|
* providers. `onModuleInit` registers every known source adapter with the
|
||||||
|
* registry via `SourceRegistry.register()` BEFORE the scheduler's first
|
||||||
|
* tick can run — this is the DI-boot-time hook where the denylist gate
|
||||||
|
* (D-06) structurally applies. `DoeOpenDataAdapter` is registered here;
|
||||||
|
* this is deliberately the ONE place that grows an additional
|
||||||
|
* `registry.register(...)` call as 13-04 (NetServer) and 13-05 (cosinex)
|
||||||
|
* add their adapters in later waves — this plan is Wave 2's sole writer
|
||||||
|
* of tenders.module.ts, so those additions are purely additive follow-ups.
|
||||||
*/
|
*/
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ModuleRegistryModule, SettingsModule],
|
imports: [ModuleRegistryModule, SettingsModule],
|
||||||
controllers: [TendersController],
|
controllers: [TendersController],
|
||||||
providers: [
|
providers: [
|
||||||
DoeOpenDataAdapter,
|
DoeOpenDataAdapter,
|
||||||
|
SourceRegistry,
|
||||||
TenderNormalizerService,
|
TenderNormalizerService,
|
||||||
|
TenderDedupService,
|
||||||
TenderIngestionService,
|
TenderIngestionService,
|
||||||
TenderSchedulerService,
|
TenderSchedulerService,
|
||||||
TenderTriageService,
|
TenderTriageService,
|
||||||
@@ -84,9 +100,27 @@ export class TendersModule implements OnModuleInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly moduleRegistryService: ModuleRegistryService,
|
private readonly moduleRegistryService: ModuleRegistryService,
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
|
private readonly sourceRegistry: SourceRegistry,
|
||||||
|
private readonly doeAdapter: DoeOpenDataAdapter,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async onModuleInit(): Promise<void> {
|
async onModuleInit(): Promise<void> {
|
||||||
|
try {
|
||||||
|
// D-06/INGEST-07: registration itself is the denylist-gate enforcement
|
||||||
|
// point — SourceRegistry.register() throws for any adapter serving a
|
||||||
|
// denylisted portal. DoeOpenDataAdapter is legitimate; this call is
|
||||||
|
// additive-only for 13-04/13-05's future adapters.
|
||||||
|
this.sourceRegistry.register(this.doeAdapter);
|
||||||
|
this.logger.log(
|
||||||
|
`Registered source adapters: ${this.sourceRegistry
|
||||||
|
.activeAdapters()
|
||||||
|
.map((a) => a.sourceType)
|
||||||
|
.join(', ')}`,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Failed to register tender source adapters', error);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await seedTendersModule(this.moduleRegistryService);
|
await seedTendersModule(this.moduleRegistryService);
|
||||||
this.logger.log('Ausschreibungs-Radar module seeded in registry');
|
this.logger.log('Ausschreibungs-Radar module seeded in registry');
|
||||||
|
|||||||
Reference in New Issue
Block a user