| 13-scraping-adapters-cross-source-dedup |
06 |
api |
| nestjs |
| prisma |
| react |
| tender-radar |
| dedup |
|
| phase |
provides |
| 13-01 |
TenderSource model (sourcePortal, sourceUrl, sourceNoticeId) + backfill of existing DÖE tenders |
|
| phase |
provides |
| 13-03 |
dedup-resolver fan-out wiring that attaches additional TenderSource rows to an existing Tender |
|
|
| GET /modules/tender-radar/:id now includes the sources[] relation (TenderSource rows) |
| Tender API client type carries optional sources[] (sourcePortal, sourceUrl, sourceNoticeId) |
| TenderDetail renders one link per source portal with a German portal label, falling back to the single sourceUrl block when sources is missing/empty |
|
| 14-i18n-admin-source-ui |
| tender-radar-detail-view |
|
| added |
patterns |
|
|
| Read-surface include: TenderSource is exposed via Prisma `include` with a minimal `select` (sourcePortal/sourceUrl/sourceNoticeId), same minimal-projection convention as getCoverage's groupBy. |
| Optional relation field on frontend API types (`sources?: [...]`) with an explicit empty/missing fallback to the legacy single-field UI block — safe rollout path for a new relation without breaking older/undeployed callers. |
|
|
| created |
modified |
|
|
| apps/api/src/tenders/tenders.controller.ts |
| apps/api/src/tenders/tenders.controller.spec.ts |
| apps/web/src/lib/tender-radar-api.ts |
| apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.tsx |
| apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.test.tsx |
|
|
| portalLabel() map lives inline in TenderDetail.tsx (not a shared constant) — only this component needs it today; unknown sourcePortal slugs fall back to the raw slug so a future portal never silently disappears from the list. |
| Fallback order is sources[]-non-empty -> legacy sourceUrl block -> 'Kein Quell-Link verfügbar' — preserves exact existing UI/tests for tenders that predate the TenderSource backfill or whose sources[] loads empty. |
|
|
| id |
description |
requirement |
verification |
human_judgment |
| D1 |
GET /modules/tender-radar/:id includes the TenderSource relation (sourcePortal, sourceUrl, sourceNoticeId) via Prisma include, without changing route order or tenant scoping. |
SCHEMA-03 |
| kind |
ref |
status |
| unit |
apps/api/src/tenders/tenders.controller.spec.ts#GET /:id includes the sources relation so the response carries all TenderSource links (13-06, SCHEMA-03) |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
| D2 |
TenderDetail renders a list of links (one per source portal, German label) when tender.sources[] has entries, and falls back to the existing single sourceUrl block when sources is missing or empty. |
SCHEMA-03 |
| kind |
ref |
status |
| unit |
apps/web/.../TenderDetail.test.tsx#renders a link for every source when tender.sources[] has multiple entries (13-06, SCHEMA-03) |
pass |
|
| kind |
ref |
status |
| unit |
apps/web/.../TenderDetail.test.tsx#falls back to the single sourceUrl block when tender.sources is missing/empty |
pass |
|
|
false |
|
|
15min |
2026-07-23 |
complete |