| 10-ausschreibungs-radar-foundation-d-e-ingestion |
02 |
api |
| nestjs |
| module-registry |
| prisma |
| next.js |
| module-loader |
| tender-radar |
| marketplace |
|
| phase |
provides |
| 10-01 (foundation & dependencies) |
Tender / TenderSourcePollConfig Prisma models, applied migration |
|
|
| Self-seeding TendersModule registered in app.module.ts imports (marketplace visibility, CONFIG-01) |
| Singleton doe-opendata TenderSourcePollConfig row upserted idempotently on boot |
| Web MODULE_REGISTRY['tender-radar'] whitelist entry + minimal placeholder page |
| Unit-test coverage proving the registry seed call shape |
|
| 10-03 adapter/normalizer |
| 10-04 ingestion/scheduler |
| 10-05 controller/DTOs |
| phase 11 saved searches UI |
|
| added |
patterns |
|
|
| Self-seeding NestJS module via OnModuleInit (mirrors DkvModule/CertManagerModule) |
| Singleton platform-global config upsert (sourceType @unique) inside module bootstrap, no forTenant() |
| Frontend module-loader security whitelist entry required alongside DB seed for a module's page to resolve |
|
|
| created |
modified |
| apps/api/src/tenders/tenders.module.ts |
| apps/api/src/tenders/tenders.seed.ts |
| apps/api/src/tenders/tenders.seed.spec.ts |
| apps/web/src/app/(portal)/modules/tender-radar/page.tsx |
|
| apps/api/src/app.module.ts |
| apps/web/src/lib/module-loader.ts |
|
|
| category: 'procurement' chosen for the marketplace card — free-form kebab-case per existing seed convention (dkv='fleet', cert-manager='security-tools'), no enum constraint in seedModule or the marketplace UI |
| Singleton doe-opendata poll config upserted directly inside TendersModule.onModuleInit() via injected PrismaService, not via a separate ingestion service (Plans 03-04 add ingestion machinery, not this plan) |
| isActive: true by default on the singleton so the platform-global DÖE poll runs regardless of any tenant's per-tenant activation state (D-04); day-cursor gating (Plan 04) makes ticks idempotent before that logic exists |
| Placeholder page.tsx uses a hardcoded German string, not next-intl — full i18n is CONFIG-03 (Phase 14); documented inline as an intentional MVP stub to be replaced in Phase 11 |
|
|
| id |
description |
requirement |
verification |
human_judgment |
| D1 |
TendersModule self-seeds 'tender-radar' into the module registry on boot (isSystem: true, bilingual description) so an admin can find it in the marketplace, same as DKV/Cert-Manager |
CONFIG-01 |
| kind |
ref |
status |
| unit |
apps/api/src/tenders/tenders.seed.spec.ts#calls moduleRegistryService.seedModule once with tender-radar slug |
pass |
|
| kind |
ref |
status |
| integration |
cd apps/api && pnpm exec tsc --noEmit -p tsconfig.json; grep -c TendersModule src/app.module.ts == 2 |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
rationale |
| D2 |
Activating the module opens /modules/tender-radar instead of 404, because the module-loader whitelist entry exists |
CONFIG-01 |
| kind |
ref |
status |
| integration |
cd apps/web && grep -c tender-radar src/lib/module-loader.ts >=1; test -f 'src/app/(portal)/modules/tender-radar/page.tsx'; pnpm exec tsc --noEmit |
pass |
|
|
true |
Whitelist entry and file existence are statically verified, but actually clicking Activate in the marketplace and confirming the page renders (rather than 404s) in a live browser session was not exercised in this run — recommend a quick UAT pass alongside Plan 03-05 verification. |
|
| id |
description |
requirement |
verification |
human_judgment |
rationale |
| D3 |
Singleton doe-opendata TenderSourcePollConfig row is seeded exactly once per boot (idempotent upsert), no per-tenant duplication possible (sourceType @unique) |
CONFIG-01 |
| kind |
ref |
status |
| unit |
schema.prisma sourceType @unique constraint (10-01) + upsert-by-sourceType in tenders.module.ts onModuleInit |
pass |
|
|
true |
DB-level uniqueness and upsert code are statically verifiable; actually restarting the live API container twice and confirming the row count stays at 1 was not exercised in this run (local Docker deploy/restart is left to the user per project convention). |
|
|
~20min |
2026-07-21 |
complete |