Files
tessera-ctl/.planning/phases/10-ausschreibungs-radar-foundation-d-e-ingestion/10-01-SUMMARY.md
T

8.6 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, coverage, duration, completed, status
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed coverage duration completed status
10-ausschreibungs-radar-foundation-d-e-ingestion 01 database
prisma
postgres
tender-radar
ingestion
adm-zip
fast-xml-parser
csv-parse
multi-tenant
phase provides
09 (module-registry / dkv patterns) Prisma schema conventions, handwritten-migration workflow, tenant-extension (forTenant) reference
Global (tenant-agnostic) Tender table with OCDS-oriented nullable deadline/value fields (SCHEMA-01)
Singleton TenderSourcePollConfig model (sourceType @unique) as INGEST-06 foundation
fast-xml-parser, adm-zip, csv-parse installed in @tessera/api
Applied migration + regenerated Prisma client types for Tender / TenderSourcePollConfig
10-02 module registration
10-03 adapter/normalizer
10-04 ingestion/scheduler
10-05 controller/DTOs
phase 11 saved searches
added patterns
fast-xml-parser@5
adm-zip@0.6
csv-parse@7
Global RLS-exempt reference table (no tenantId, no forTenant()) for platform-wide data (D-03)
Singleton-per-source config via fixed-slug @unique column (mirrors DkvModuleConfig.tenantId @unique)
Handwritten timestamped migration with IF NOT EXISTS guards (repo convention)
created modified
apps/api/prisma/migrations/20260721120000_add_tender_radar/migration.sql
apps/api/prisma/schema.prisma
apps/api/package.json
Tender carries NO tenantId column and is NOT wrapped by forTenant()/RLS — platform-global data (D-03)
deadlineAt / estimatedValue are nullable by mandate (RESEARCH Pattern 4), not optional hardening
TenderSourcePollConfig.lastIngestedDay is a day-cursor (DateTime?), not a poll timestamp (RESEARCH Pattern 1)
sourceType @unique makes the singleton-per-source intent explicit and enforceable at the DB level
Global reference table: no tenantId, no @@index([tenantId]), plain PrismaService client (no RLS wrap)
Singleton config row keyed by fixed slug via @unique
SCHEMA-01
id description requirement verification human_judgment
D1 Global Tender table exists with OCDS-oriented nullable deadline/value fields and no tenantId (SCHEMA-01, D-03) SCHEMA-01
kind ref status
automated_ui grep -c 'model Tender' schema.prisma >=1; awk Tender-block | grep -c tenantId == 0 pass
kind ref status
integration prisma migrate status -> 'Database schema is up to date!'; prisma.tender.count() == 0 pass
false
id description verification human_judgment
D2 Singleton TenderSourcePollConfig model (sourceType @unique) present and live (INGEST-06 foundation)
kind ref status
integration prisma.tenderSourcePollConfig.count() == 0 without error; grep -c 'model TenderSourcePollConfig' == 1 pass
false
id description verification human_judgment
D3 fast-xml-parser, adm-zip, csv-parse installed and resolvable in @tessera/api
kind ref status
integration node -e require('adm-zip');require('fast-xml-parser');require('csv-parse/sync') -> packages OK pass
false
~15min (aktive Ausführung, exkl. Checkpoint-Wartezeit) 2026-07-21 complete

Phase 10 Plan 01: Ausschreibungs-Radar Foundation & Dependencies Summary

Global (tenant-agnostic) Tender-Referenztabelle + singleton TenderSourcePollConfig in Prisma/Postgres, drei Ingestion-Pakete (fast-xml-parser, adm-zip, csv-parse) installiert, Migration angewendet — Datenfundament für das gesamte DÖE-Ingestion-Modul.

Performance

  • Duration: ~15 min aktive Ausführung (exkl. Checkpoint- und Infrastruktur-Wartezeit)
  • Started: 2026-07-21
  • Completed: 2026-07-21
  • Tasks: 3 (1 Checkpoint + 2 auto)
  • Files modified: 4 (schema.prisma, package.json, pnpm-lock.yaml, migration.sql)

Accomplishments

  • Globale Tender-Tabelle (OCDS-orientiert, nullable deadlineAt/estimatedValue) ohne tenantId — D-03 Invariante im Schema verankert (SCHEMA-01).
  • Singleton TenderSourcePollConfig mit sourceType @unique als Fundament für die geteilte, mandantensichere Poll-Konfiguration (INGEST-06).
  • Drei Ingestion-Bibliotheken installiert und auflösbar (fast-xml-parser, adm-zip, csv-parse) — adm-zip nach blockierendem Supply-Chain-Checkpoint vom User freigegeben.
  • Handgeschriebene, timestamped Migration angewendet; Prisma-Client-Typen regeneriert; DB-Schema up to date.

Task Commits

  1. Task 1: adm-zip package legitimacy verification — kein Commit (blocking-human Checkpoint, vom User "approved": cthackers/adm-zip, MIT, seit 2012, Mio. DLs/Woche)
  2. Task 2: Install packages + Tender/TenderSourcePollConfig models — 713b1eb (feat)
  3. Task 3: [BLOCKING] Apply tender-radar migration — kein separater Code-Commit; Migrations-SQL ist Teil von 713b1eb, Anwendung auf die laufende DB durch den Coordinator (Stack lokal gestartet)

Plan metadata: siehe finalen docs(10-01)-Commit.

Files Created/Modified

  • apps/api/prisma/schema.prisma — Modelle Tender (global, kein tenantId) + TenderSourcePollConfig (singleton) ergänzt
  • apps/api/prisma/migrations/20260721120000_add_tender_radar/migration.sql — handgeschriebene additive Migration (2 Tabellen, 4 Indexe, 2 Unique-Indexe)
  • apps/api/package.json — fast-xml-parser, adm-zip, csv-parse als Dependencies
  • pnpm-lock.yaml — Lockfile-Aktualisierung

Decisions Made

  • Tender ist plattform-global (D-03): kein tenantId, kein @@index([tenantId]), keine RLS/forTenant()-Umhüllung. Verhindert, dass ein späterer where: { tenantId }-Reflex globale Daten für einen zweiten Mandanten unsichtbar macht (Threat T-10-01, mitigiert).
  • Nullable deadline/value verpflichtend: deadlineAt und estimatedValue sind laut RESEARCH Pattern 4 häufig leer — nullable ist Korrektheitsanforderung, kein optionales Hardening.
  • Day-cursor statt Timestamp: TenderSourcePollConfig.lastIngestedDay ist ein Tages-Cursor (DateTime?), passend zum DÖE-Daily-Batch-ZIP-Modell (RESEARCH Pattern 1).
  • Singleton via sourceType @unique: macht die "eine Konfig pro Quelle"-Absicht auf DB-Ebene explizit und erzwingbar.

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] Kommentar-Wortlaut verletzte die tenantId-Assertion

  • Found during: Task 2 (Schema-Verifikation)
  • Issue: Der erläuternde Kommentar im Tender-Modell enthielt das Token tenantId ("Deliberately NO tenantId field ..."), wodurch die Acceptance-Assertion grep -c "tenantId" im Tender-Block 1 statt 0 lieferte — ein False-Positive gegen die D-03-Invariante.
  • Fix: Kommentar umformuliert zu "NO tenant column and NO tenant index — this is global data (D-03)"; Aussage bleibt erhalten, Token entfernt.
  • Files modified: apps/api/prisma/schema.prisma
  • Verification: awk Tender-block | grep -c "tenantId" == 0; tsc --noEmit exit 0.
  • Committed in: 713b1eb (Task-2-Commit)

Total deviations: 1 auto-fixed (1 Bug) Impact on plan: Reine Kommentar-Korrektur zur Erfüllung der Design-Invarianten-Assertion. Kein Scope-Creep, keine Verhaltensänderung.

Issues Encountered

  • Task 3 blockiert durch offline DB-Stack: Der Tessera-Docker-Stack (tessera-ctl-db-1/-api-1/-web-1) war beendet, die Postgres-DB liegt auf einem internal: true-Netzwerk ohne Host-Port-Mapping, und DATABASE_URL war vom Host nicht zugänglich. Als blockierendes Infrastruktur-Gate an den Coordinator/User zurückgegeben. Auflösung: Coordinator startete den lokalen Stack und wandte prisma migrate deploy an. Verifikation (auch eigenständig via DATABASE_URL=...@172.19.0.2:5432 gegengeprüft): prisma migrate status → "Database schema is up to date!", Tender-Count = 0, TenderSourcePollConfig-Count = 0 — beide Tabellen live, keine Fehler.

User Setup Required

None — keine externe Service-Konfiguration nötig. (Hinweis: Migrations werden in diesem Repo bei laufendem Stack angewendet; up/rebuild liegt beim User.)

Next Phase Readiness

  • Datenfundament steht: Tender + TenderSourcePollConfig live, Prisma-Client-Typen generiert, Pakete installiert.
  • Plan 10-02 (TendersModule + seedTendersModule) kann direkt aufsetzen.
  • Keine offenen Blocker.

Self-Check: PASSED

  • FOUND: apps/api/prisma/schema.prisma
  • FOUND: apps/api/prisma/migrations/20260721120000_add_tender_radar/migration.sql
  • FOUND: .planning/phases/10-ausschreibungs-radar-foundation-d-e-ingestion/10-01-SUMMARY.md
  • FOUND commit: 713b1eb

Phase: 10-ausschreibungs-radar-foundation-d-e-ingestion Completed: 2026-07-21