--- context: phase phase: 10-ausschreibungs-radar-foundation-d-e-ingestion task: null total_tasks: 16 status: code_complete_uat_pending last_updated: 2026-07-21T09:34:48.800Z --- # Phase 10 — Ausschreibungs-Radar Foundation & DÖE Ingestion _No blocking anti-patterns were discovered this session. Execution was clean._ ## Critical Anti-Patterns | Pattern | Description | Severity | Prevention Mechanism | |---------|-------------|----------|---------------------| | Stale live container masks completion | Code + migration + tests are complete and green, but the running `tessera-ctl-api-1` container is on the pre-Phase-10 image, so nobody has observed the boot-seed or a live HTTP request against the new routes. This is why verification is `human_needed`, NOT a code defect. | advisory | Rebuild the container (`docker compose up -d --build api web`) before treating a "green tests" state as user-visible done. | Phase 10 is code-complete: all 6 plans executed, 22 commits on `main`. Full monorepo test suite green (API 74/74, Web 111/111), `tsc --noEmit` clean for both apps. Independent goal-backward verification (`10-VERIFICATION.md`) confirmed 5/5 must-haves at the code/DB/test level. Verification status is `human_needed` — the only open item is a live UAT run after a Docker rebuild. - Plan 10-01: Prisma `Tender` + `TenderSourcePollConfig` (global, no tenantId/RLS) + migration APPLIED to local DB — SCHEMA-01. Commit 6cfda90. - Plan 10-02: Marketplace self-seed `tender-radar` + web module-loader whitelist + placeholder page — CONFIG-01. Commit f80d491. - Plan 10-03: `DoeOpenDataAdapter` + `TenderNormalizerService` (TDD, real DÖE fixtures, D-02 positive tag-match filter, zip-bomb guard T-10-07) — INGEST-01, SCHEMA-01. Commit 7610778. - Plan 10-04: `TenderIngestionService` + `TenderSchedulerService` (day-cursor, single global cron, contentHash upsert-update, 90-day retention with null-deadline exemption, two-tenant safety test) — SCHEMA-02, INGEST-06. Commit 9227cc9. - Plan 10-05: `TendersController` (global read, ModuleGuard-gated) + admin `GET/PUT /modules/tender-radar/source-config` (live-applies interval to scheduler) — INGEST-06. Commit 6d63022. - Plan 10-06: Admin config UI (`tender-radar-api.ts` client + `SourceConfigForm.tsx` + `settings/page.tsx`) — INGEST-06 admin-facing. Commit 4f3c6cf. Code: none. Pending human UAT (after Docker rebuild), all from `10-VERIFICATION.md`: - UAT-1: activate "Ausschreibungs-Radar" for a tenant from the marketplace, confirm the module page loads. - UAT-2: settings form — change interval / toggle isActive, save → GET/PUT source-config roundtrip works. - UAT-3: after rebuild, `TenderSourcePollConfig` has 1 row (boot-seed fired). - DÖE is a daily-batch export ZIP (not a paginated feed); today/future days return HTTP 400 → scheduler uses a day-cursor, not a since-timestamp. The admin-configurable hourly poll mostly no-ops by design. - Parse eForms-DE XML as primary (OCDS drops tenderPeriod/value for Unterschwelle notices); OCDS only for ocid/party resolution. - `Tender` + `TenderSourcePollConfig` are platform-global: no tenantId, no forTenant()/RLS (D-03) — verified in the live schema. - Single global cron, `findUnique` on fixed sourceType, no `activeTenantId`/`findFirst` (poll-once-fan-out-many, not the DKV single-tenant pattern). Two-tenant test proves 0 extra DÖE calls / cron jobs / rows on 2nd activation. - adm-zip approved via the supply-chain human-verify checkpoint (cthackers/adm-zip, MIT, since 2012; RESEARCH `[SUS]` flag was a too-new heuristic false positive). - Live container stale: `tessera-ctl-api-1` runs the pre-Phase-10 image. Resolve with `docker compose up -d --build api web`. Not a code defect. ## Required Reading (in order) 1. `.planning/phases/10-ausschreibungs-radar-foundation-d-e-ingestion/10-VERIFICATION.md` — the 3 structured human-verification items + per-criterion findings. 2. `.planning/phases/10-ausschreibungs-radar-foundation-d-e-ingestion/10-RESEARCH.md` — the live-verified DÖE API contract (daily-batch ZIP, day-cursor, eForms-primary). 3. Memory `project_local_db_migrations` — how to reach the local dev DB (no host port; use db container IP). ## Infrastructure State - Local Docker stack STARTED this session (was down 2 days after a reboot). `db` + `api` up. - `api` container is on the OLD image — needs rebuild to run Phase 10 code. - DB migrations applied from host (tender-radar + an older LDAP migration never run locally). `prisma migrate status` = up to date. - DB reachable only via container IP (no host port): `postgresql://tessera:tessera_dev@172.19.0.2:5432/tessera` (IP ephemeral). - Boundary: the no-docker-rebuild rule in memory is about the TEST SERVER (192.168.13.12); the local dev machine is fine to rebuild. The phase went cleanly through the full GSD pipeline this session: research → validation strategy → pattern map → plan (5) → checker (1 blocker: missing admin config UI) → replan (+Plan 06) → verification passed → execute all 6 waves sequentially on main (worktrees auto-degraded, origin/HEAD unresolved) → goal-backward verify. The only reason this isn't marked fully Complete is the stale live container — everything else is proven. Start with: `docker compose up -d --build api web`, then run the 3 UAT checks in `10-VERIFICATION.md`. If green, proceed to `/gsd-discuss-phase 11` (Filter Engine, Results UI & Saved Searches).