wip: session paused between milestones, v1.2 complete
Tessera CI/CD / Lint & Type Check (push) Successful in 46s
Tessera CI/CD / Tests (push) Successful in 47s
Tessera CI/CD / Build & Publish Images (push) Successful in 6s

No phase work in flight: Phase 15 (8/8) and Phase 16 (5/5) are both closed and
the roadmap reflects it. The handoff therefore sits at project level rather
than in a phase directory.

Records four anti-patterns discovered through actual failure this session, two
of them marked blocking: the tautological test that let the objectGUID defect
through review, and the fact that /opt/tessera is not a checkout, so compose
changes in this repository never reach the test server.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-11 15:01:00 +02:00
parent f38b9f203f
commit 96432a6a7b
2 changed files with 113 additions and 80 deletions
+33 -25
View File
@@ -1,40 +1,48 @@
{
"version": "1.0",
"timestamp": "2026-07-21T09:34:48.800Z",
"phase": "10",
"phase_name": "ausschreibungs-radar-foundation-d-e-ingestion",
"phase_dir": ".planning/phases/10-ausschreibungs-radar-foundation-d-e-ingestion",
"plan": 6,
"timestamp": "2026-08-11T12:59:01.215Z",
"phase": "16",
"phase_name": "ad-gruppen-synchronisation",
"phase_dir": ".planning/phases/16-ad-gruppen-synchronisation",
"plan": null,
"task": null,
"total_tasks": 16,
"total_tasks": 0,
"status": "paused",
"context": "between-milestones",
"completed_tasks": [
{"id": "10-01", "name": "Data + dependency foundation (Tender/TenderSourcePollConfig models, migration)", "status": "done", "commit": "6cfda90"},
{"id": "10-02", "name": "Marketplace self-seed + module-loader whitelist + page", "status": "done", "commit": "f80d491"},
{"id": "10-03", "name": "DOE adapter + normalizer (TDD, real fixtures, D-02 filter, zip-bomb guard)", "status": "done", "commit": "7610778"},
{"id": "10-04", "name": "Ingestion + shared scheduler (day-cursor, two-tenant safety test)", "status": "done", "commit": "9227cc9"},
{"id": "10-05", "name": "TendersController global read + admin source-config route", "status": "done", "commit": "6d63022"},
{"id": "10-06", "name": "Admin config UI (SourceConfigForm)", "status": "done", "commit": "4f3c6cf"}
{"id": "16-UAT", "name": "Phase-16 UAT: Browser-Durchlauf 5/6/7 bestanden, Test 2 gegen echtes AD, Tests 1/3/4/8 bewusst uebersprungen", "status": "done", "commit": "ba21b0c,234f80b"},
{"id": "260811-f9i", "name": "KRITISCH: objectGUID-Existenzpruefung fand nie etwas (escapter String statt Rohbytes) — haette beim ersten Sync alle AD-gebundenen Gruppen samt Mitgliedschaften und Modulfreigaben geloescht", "status": "done", "commit": "d2019dc"},
{"id": "260811-j04", "name": "DOE-Ausschreibungen verlinkten auf die API statt auf die Bekanntmachung; Adapter + Backfill fuer 2846 Zeilen", "status": "done", "commit": "ecf7872"},
{"id": "15-04", "name": "Fehlender Abschlussbericht nachgezogen, Phase 15 damit 8/8", "status": "done", "commit": "149b5aa"},
{"id": "ldap-crypto", "name": "LDAP-Bind-Passwort AES-256-GCM verschluesselt, Spalte encryptedBindPassword, Bootstrap-Backfill", "status": "done", "commit": "4f687ea"},
{"id": "key-hardening", "name": "Stack startet nicht mehr ohne Verschluesselungsschluessel (beide Compose-Dateien)", "status": "done", "commit": "7bda56d"},
{"id": "key-rename", "name": "CALENDAR_ENCRYPTION_KEY -> TESSERA_ENCRYPTION_KEY mit Rueckfallebene; CryptoService in eigenem globalem Modul", "status": "done", "commit": "f574884"}
],
"remaining_tasks": [
{"id": "backlog-lizenz", "name": "Lizenzpruefung bei der Modulaktivierung — jeder Mandanten-Admin kann sich jedes Modul selbst freischalten", "status": "not_started"},
{"id": "backlog-settings", "name": "Persoenliche vs. Admin-Einstellungen in Modul-Einstellungsseiten trennen", "status": "not_started"},
{"id": "backlog-compose", "name": "Compose-Datei auf dem Testserver driftet vom Repository ab", "status": "not_started"},
{"id": "backlog-envkey", "name": "Vorgabewert entfernen und Schluessel in den Beispiel-Umgebungsdateien dokumentieren", "status": "not_started"}
],
"remaining_tasks": [],
"blockers": [
{"description": "Running tessera-ctl-api-1 container is on the pre-Phase-10 image; new TendersModule/routes/boot-seed not live yet", "type": "human_action", "workaround": "docker compose up -d --build api web"}
{"description": "Kein Schreibzugriff im AD (balios.ctl.local) — UAT 1/3/4 der Phase 16 koennen dort nie ausgefuehrt werden", "type": "external", "workaround": "Bewusst als offene Annahme dokumentiert (16-UAT.md, Entscheidung 2026-08-11); A1 stuetzt sich auf die Microsoft-Dokumentation"},
{"description": "Zugriff auf .env.example / .env.prod.example war in der Sitzung durch Berechtigungen gesperrt", "type": "technical", "workaround": "Dokumentation des Schluessels bleibt im Backlog-Punkt 2026-08-11-verschluesselungsschluessel-vorgabewert.md"}
],
"async_jobs": [],
"human_actions_pending": [
{"action": "docker compose up -d --build api web, then run 3 UAT checks from 10-VERIFICATION.md", "context": "Verifier status=human_needed: code/tests prove 5/5 must-haves but nobody observed live boot-seed or HTTP against new routes. Container rebuild is the user's job per project convention.", "blocking": true},
{"action": "UAT-1: activate Ausschreibungs-Radar for a tenant from marketplace, confirm page loads", "context": "Success Criterion 1", "blocking": false},
{"action": "UAT-2: settings form interval/isActive save -> GET/PUT source-config roundtrip", "context": "INGEST-06 admin UI", "blocking": false},
{"action": "UAT-3: after rebuild TenderSourcePollConfig has 1 row (boot-seed)", "context": "Singleton poll config seed", "blocking": false}
{"action": "Entscheidung zur Lizenzierung: wer vergibt Lizenzen, was passiert beim Ablauf, braucht es Laufzeiten, wie kommt eine Lizenz in eine Kundeninstallation", "context": "Blockiert den groessten Backlog-Punkt; ohne diese Antworten ist der Rest Spekulation", "blocking": true},
{"action": "Grundsatzentscheidung, wo persoenliche Einstellungen in Tessera leben (eigene Nutzerseite vs. im Modul abgetrennt)", "context": "Betrifft tender-radar und dkv-fleet gleichermassen — einmal grundsaetzlich statt pro Modul", "blocking": true},
{"action": "Entscheiden, wie /opt/tessera an die Compose-Datei kommt (Arbeitskopie, CI-Artefakt, oder Abgleich-Skript)", "context": "Vorher klaeren, WARUM die Datei dort von Hand gepflegt wird — sie kann host-spezifische Anpassungen tragen", "blocking": true},
{"action": "Deploys auf alpha (pull + up -d --force-recreate) macht der User selbst", "context": "Stehende Regel; Konfigurationsdateien dort darf Claude seit 2026-08-11 bearbeiten", "blocking": false}
],
"decisions": [
{"decision": "DOE is a daily-batch export ZIP, not a paginated feed; scheduler uses a day-cursor (today/future rejected HTTP 400)", "rationale": "Live-verified in RESEARCH; hourly poll interval mostly no-ops by design", "phase": "10"},
{"decision": "eForms-DE XML is the primary parse target; OCDS only for ocid/party resolution", "rationale": "OCDS drops tenderPeriod/value for Unterschwelle notices", "phase": "10"},
{"decision": "Tender + TenderSourcePollConfig are platform-global: NO tenantId, NO forTenant()/RLS", "rationale": "D-03 tender data is global; verified in live schema + grep gates", "phase": "10"},
{"decision": "Single global cron (poll-once-fan-out-many), findUnique on fixed sourceType, no activeTenantId/findFirst", "rationale": "Avoids DKV single-tenant anti-pattern; two-tenant test proves 0 extra calls/jobs/rows", "phase": "10"},
{"decision": "adm-zip approved after supply-chain human-verify checkpoint", "rationale": "cthackers/adm-zip, MIT, since 2012, millions DL/week; RESEARCH [SUS] flag was a too-new heuristic false positive", "phase": "10"}
{"decision": "Phase 16 mit A1 als offener, dokumentierter Annahme abgeschlossen statt einen Wegwerf-Domaenencontroller zu bauen", "rationale": "User hat keinen AD-Schreibzugriff; der eine substanzielle Fehler an der Stelle war bereits gefunden und behoben, der Rest-Erkenntnisgewinn rechtfertigte den Aufwand nicht", "phase": "16"},
{"decision": "Ein Plattform-Schluessel, umbenannt, statt eines eigenen Schluessels fuer das AD-Bind-Passwort", "rationale": "Zwei Schluessel in derselben .env auf demselben Host erhoehen die Sicherheit nicht, verdoppeln aber was bei Backup und Wiederherstellung schiefgehen kann", "phase": null},
{"decision": "Alter Schluesselname CALENDAR_ENCRYPTION_KEY bleibt lesbar, mit Veraltet-Warnung", "rationale": "Ein harter Rename haette jede bestehende Installation beim naechsten Start gestoppt — erst recht, seit Compose ohne Schluessel abbricht", "phase": null},
{"decision": "CryptoService in ein eigenes globales Modul statt in CalendarModule", "rationale": "Vier Module importierten CalendarModule nur fuer die Verschluesselung, was eine Abhaengigkeit vom Kalender vortaeuschte, die es nie gab", "phase": null},
{"decision": "Backfill der Verschluesselung zur Laufzeit beim Bootstrap statt in der Migration", "rationale": "SQL kann nicht verschluesseln — der Schluessel liegt in der Anwendungsumgebung; die Migration benennt nur die Spalte um", "phase": null}
],
"uncommitted_files": [],
"next_action": "docker compose up -d --build api web; then run the 3 UAT checks in 10-VERIFICATION.md; if green, /gsd-discuss-phase 11",
"context_notes": "Phase 10 code+tests complete (22 commits, API 74/74 + Web 111/111 green, tsc clean). Verifier status=human_needed only because the live container is stale. Local DB stack was down 2 days after a reboot; started it (docker compose up -d db api) and applied 2 pending migrations from host via prisma against the db container IP (tender-radar + an older LDAP migration never run locally). DB has no host port; reach it at postgresql://tessera:tessera_dev@<db-container-ip>:5432/tessera (IP ephemeral, currently 172.19.0.2). See memory project_local_db_migrations. No blocking anti-patterns hit during execution. NOTE: the no-docker-rebuild boundary in memory is about the TEST SERVER (192.168.13.12); this session's stack start was the LOCAL dev machine."
"next_action": "Mit dem User klaeren, welcher der vier Backlog-Punkte drankommt oder ob ein neuer Meilenstein nach v1.2 geplant wird. Die drei groesseren Punkte brauchen zuerst seine Entscheidungen (siehe human_actions_pending), der vierte (Vorgabewert + Doku) ist ohne Rueckfrage machbar.",
"context_notes": "v1.2 Plattform-Berechtigungen ist inhaltlich fertig: Phase 15 (8/8) und Phase 16 (5/5) abgeschlossen, beide in ROADMAP.md und STATE.md nachgezogen. Kein Phase-Work in Arbeit, Arbeitsverzeichnis sauber, alles auf origin/main. Die Sitzung war UAT-getrieben und hat dabei einen kritischen Fehler gefunden, der ohne den einen ausfuehrbaren Test unbemerkt in Produktion gegangen waere. Roter Faden fuer die Fortsetzung: die vier Backlog-Punkte sind alle 'vor dem Verkauf an externe Kunden', keiner davon draengt im internen Betrieb."
}