feat(12-02): register TenderMailService/TenderDigestScheduler, import SettingsModule

TendersModule imports SettingsModule so TenderMailService can inject
SettingsService (getDecryptedSmtpConfig), and registers
TenderMailService + TenderDigestScheduler as providers alongside the
existing TenderMatchingService (12-01). ScheduleModule.forRoot() is
already global in AppModule — not re-imported. DI graph verified
resolvable via npx tsc --noEmit; full apps/api suite green (192/192).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-22 09:14:40 +02:00
parent c0a8906d6a
commit 32441678c1
+16 -1
View File
@@ -2,9 +2,12 @@ import { Logger, Module, OnModuleInit } from '@nestjs/common';
import { ModuleRegistryModule } from '../module-registry/module-registry.module';
import { ModuleRegistryService } from '../module-registry/module-registry.service';
import { PrismaService } from '../prisma/prisma.service';
import { SettingsModule } from '../settings/settings.module';
import { DoeOpenDataAdapter } from './adapters/doe-opendata.adapter';
import { seedTendersModule } from './tenders.seed';
import { TenderDigestScheduler } from './tender-digest.scheduler';
import { TenderIngestionService } from './tender-ingestion.service';
import { TenderMailService } from './tender-mail.service';
import { TenderMatchingService } from './tender-matching.service';
import { TenderNormalizerService } from './tender-normalizer.service';
import { TenderSavedSearchService } from './tender-saved-search.service';
@@ -38,11 +41,21 @@ import { TendersController } from './tenders.controller';
* D-07) — reuses buildTenderWhere against every active TenderSavedSearch
* profile and upserts TenderMatch rows (matched-vs-notified state, D-06).
*
* Phase 12, Plan 02 (NOTIFY-01/04) adds the digest delivery channel:
* TenderMailService (a structural DkvMailService clone — fresh nodemailer
* transport per send via SettingsService.getDecryptedSmtpConfig(tenantId),
* never a cached/global mailer, D-08) and TenderDigestScheduler (a SINGLE
* global @nestjs/schedule cron, mirroring TenderSchedulerService's
* poll-once-fan-out-many pattern rather than DkvSchedulerService's
* single-tenant pattern — Pitfall 1). SettingsModule is imported so
* TenderMailService can inject SettingsService. ScheduleModule.forRoot()
* is already registered globally in AppModule — not re-imported here.
*
* Seeds itself into the module registry on application startup via
* OnModuleInit lifecycle hook — same pattern as DkvModule.
*/
@Module({
imports: [ModuleRegistryModule],
imports: [ModuleRegistryModule, SettingsModule],
controllers: [TendersController],
providers: [
DoeOpenDataAdapter,
@@ -52,6 +65,8 @@ import { TendersController } from './tenders.controller';
TenderTriageService,
TenderSavedSearchService,
TenderMatchingService,
TenderMailService,
TenderDigestScheduler,
],
})
export class TendersModule implements OnModuleInit {