feat(10-02): register TendersModule with marketplace self-seed + singleton poll config
- tenders.seed.ts seeds slug 'tender-radar' (isSystem: true, category 'procurement') - tenders.module.ts self-seeds registry on boot (mirrors DkvModule pattern) - upserts singleton doe-opendata TenderSourcePollConfig row (global, no forTenant()) - TendersModule added to app.module.ts imports
This commit is contained in:
@@ -20,6 +20,7 @@ import { PrismaModule } from './prisma/prisma.module';
|
||||
import { SettingsModule } from './settings/settings.module';
|
||||
import { TenantGuard } from './tenant/tenant.guard';
|
||||
import { TenantModule } from './tenant/tenant.module';
|
||||
import { TendersModule } from './tenders/tenders.module';
|
||||
import { UserModule } from './user/user.module';
|
||||
|
||||
@Module({
|
||||
@@ -41,6 +42,7 @@ import { UserModule } from './user/user.module';
|
||||
SettingsModule,
|
||||
DkvModule,
|
||||
FavoritesModule,
|
||||
TendersModule,
|
||||
],
|
||||
providers: [
|
||||
// Global JWT guard: all routes require auth unless @Public()
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
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 { seedTendersModule } from './tenders.seed';
|
||||
|
||||
/**
|
||||
* NestJS module for the Ausschreibungs-Radar feature.
|
||||
*
|
||||
* Wave 2 (this plan) only registers the module in the marketplace and
|
||||
* seeds the singleton DÖE poll config so the shared poll is
|
||||
* admin-drivable. Ingestion/adapter/scheduler/controller wiring is
|
||||
* added in Plans 03-05.
|
||||
*
|
||||
* PrismaModule is global (no explicit import needed).
|
||||
*
|
||||
* Seeds itself into the module registry on application startup via
|
||||
* OnModuleInit lifecycle hook — same pattern as DkvModule.
|
||||
*/
|
||||
@Module({
|
||||
imports: [ModuleRegistryModule],
|
||||
controllers: [],
|
||||
providers: [],
|
||||
})
|
||||
export class TendersModule implements OnModuleInit {
|
||||
private readonly logger = new Logger(TendersModule.name);
|
||||
|
||||
constructor(
|
||||
private readonly moduleRegistryService: ModuleRegistryService,
|
||||
private readonly prisma: PrismaService,
|
||||
) {}
|
||||
|
||||
async onModuleInit(): Promise<void> {
|
||||
try {
|
||||
await seedTendersModule(this.moduleRegistryService);
|
||||
this.logger.log('Ausschreibungs-Radar module seeded in registry');
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to seed Ausschreibungs-Radar module', error);
|
||||
}
|
||||
|
||||
try {
|
||||
// Singleton poll config — global, RLS-exempt (D-03). Do NOT use
|
||||
// forTenant() here: this row is shared platform-wide, not per-tenant.
|
||||
// isActive defaults true so the platform-global DÖE poll (D-04
|
||||
// hourly) runs regardless of tenant activation; the day-cursor
|
||||
// gate (Plan 04) makes repeated ticks idempotent.
|
||||
await this.prisma.tenderSourcePollConfig.upsert({
|
||||
where: { sourceType: 'doe-opendata' },
|
||||
update: {},
|
||||
create: {
|
||||
sourceType: 'doe-opendata',
|
||||
pollIntervalMin: 60,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
this.logger.log('doe-opendata poll config seeded');
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to seed doe-opendata poll config', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { ModuleRegistryService } from '../module-registry/module-registry.service';
|
||||
|
||||
/**
|
||||
* Seeds the tender-radar module into the module registry.
|
||||
*
|
||||
* Called during TendersModule initialization to ensure the
|
||||
* "tender-radar" module record exists in the database (CONFIG-01).
|
||||
*
|
||||
* isSystem: true registers the module in the registry but does NOT
|
||||
* auto-activate it per tenant. Admin must activate via Marketplace UI.
|
||||
*/
|
||||
export async function seedTendersModule(
|
||||
moduleRegistryService: ModuleRegistryService,
|
||||
): Promise<void> {
|
||||
await moduleRegistryService.seedModule({
|
||||
slug: 'tender-radar',
|
||||
name: 'Ausschreibungs-Radar',
|
||||
version: '1.0.0',
|
||||
category: 'procurement',
|
||||
description: {
|
||||
de: 'Deutsche Ausschreibungen automatisch erfassen und durchsuchen',
|
||||
en: 'Automatically track and search German public tenders',
|
||||
},
|
||||
isSystem: true,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user