15 KiB
phase, plan, subsystem, tags, requires, provides, affects, actuals, tech-stack, key-files, key-decisions, requirements-completed, coverage, duration, completed, status
| phase | plan | subsystem | tags | requires | provides | affects | actuals | tech-stack | key-files | key-decisions | requirements-completed | coverage | duration | completed | status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 17-eigene-ausschreibungs-quellen-je-nutzer | 01 | api |
|
|
|
|
|
|
|
|
|
76min | 2026-08-12 | complete |
Phase 17 Plan 01: Eigenes Alert-Postfach je Nutzer Summary
TenderEmailConfig-Besitz per Handmigration von tenantId auf userId umgezogen (Bestandszeilen dem aeltesten aktiven Admin zugeordnet), Service/Controller/Adapter auf Nutzer-Scoping umgestellt, neue Seite /modules/tender-radar/my-sources mit dem unveraenderten Postfach-Formular.
Performance
- Duration: 76 min (inkl. Checkpoint-Wartezeit auf Nutzerfreigabe)
- Started: 2026-08-12T08:08:41Z
- Completed: 2026-08-12T09:25:00Z
- Tasks: 3 (Checkpoint-Entscheidung, Tracer-Task durchgehende Bahn, Test-Erweiterung Adapter)
- Files modified: 12 (3 neu, 9 geaendert)
Bestandsaufnahme aus dem Checkpoint (Task 1)
Vor der Freigabe wurde gezaehlt, wie viele TenderEmailConfig-Zeilen tatsaechlich existieren:
- Lokale Entwicklungsdatenbank: 0 Zeilen
- Testserver alpha.tessera.ctl.de (192.168.13.12): 0 Zeilen (lesend per SSH/psql gezaehlt, keine Aenderung dort vorgenommen)
Die im Plan beschriebene Umzugsregel ("aeltester aktiver Administrator uebernimmt die Bestandszeile, sonst wird sie geloescht") hatte damit keine echten Daten zu bewegen — sie ist als Logik in der Migrationsdatei angelegt und per Text-Spec abgesichert, griff aber bei der tatsaechlichen Anwendung ins Leere. Der Nutzer hat auf dieser Grundlage mit "weiter" beide Datenbank-Umbauten der Phase (dieser Plan + Plan 17-02) freigegeben.
Accomplishments
TenderEmailConfig.userId @uniqueersetzttenantId @unique— zwei Nutzer desselben Mandanten koennen jetzt gleichzeitig je ein eigenes Alert-Postfach hinterlegen (D-01)- Handgeschriebene Migration mit korrekter Backfill-Reihenfolge (Zuordnung vor Loeschung, Pflicht erst nach Befuellung), lokal angewendet und per Index-Abfrage verifiziert
TenderEmailConfigServiceund dieGET/PUT /email-config-Endpunkte lesen/schreiben ausschliesslich nachuserIdaus dem Auth-Kontext — nie aus Query/Body (IDOR-Schutz)EmailAlertAdapterholt weiterhin alle aktiven Postfaecher mandantenuebergreifend in einem Zug ab (Mechanik unveraendert), jetzt nachweislich auch mehrere Postfaecher desselben Mandanten; ein kaputtes Postfach blockiert die anderen nicht- Neue Seite
/modules/tender-radar/my-sources("Meine Quellen") mit dem unveraendertenEmailAlertConfigFormund einem Hinweistext, der D-05 ehrlich benennt (eingelesene Ausschreibungen bleiben mandantenweit sichtbar) Tenderbleibt unveraendert plattform-global — keine Sichtbarkeitstrennung eingefuehrt (D-05, harte Grenze eingehalten)
Task Commits
Jede Aufgabe wurde einzeln committet:
- Task 1: Freigabe fuer die beiden Datenbank-Umbauten dieser Phase — Checkpoint, kein eigener Commit (Entscheidung "weiter" durch den Nutzer, dokumentiert oben und in STATE.md)
- Task 2: Ein eigenes Postfach je Nutzer — durchgehend von der Datenbank bis zur Seite —
05b1d29(feat) - Task 3: Der Abruf holt alle Postfaecher — und beweist es mit Tests —
55ceb24(test)
Plan metadata: wird mit diesem SUMMARY committet (docs)
Files Created/Modified
apps/api/prisma/schema.prisma—TenderEmailConfig.userId @uniqueergaenzt,tenantIdauf gewoehnliches Feld zurueckgestuft,@@index([userId])ergaenztapps/api/prisma/migrations/20260812100000_tender_email_config_per_user/migration.sql— Handmigration: Spalte anlegen, Bestandszeilen dem aeltesten aktiven Admin zuordnen, unbesetzte Zeilen loeschen, Eindeutigkeit von tenantId auf userId umziehenapps/api/src/tenders/email-config-migration-sql.spec.ts— neuer Text-Spec (kein DB-Zugriff), prueft die Reihenfolge der Handmigrationapps/api/src/tenders/tender-email-config.service.ts—getConfigForApi(userId),saveConfig({userId, tenantId}, dto), tenantId auf create UND update mitgeschriebenapps/api/src/tenders/tender-email-config.service.spec.ts— auf userId-Schluessel umgestellt, plus zwei neue Faelle (tenantId beim Anlegen, zwei Nutzer = zwei Zeilen)apps/api/src/tenders/tenders.controller.ts— email-config-Routen von@Roles(ADMIN,SUPER_ADMIN)auf@UseModule('tender-radar'),userId/tenantIdausextractTriageContext(req), Route-Reihenfolge vor@Get(':id')unveraendertapps/api/src/tenders/tenders.controller.spec.ts— Fake-Service-Signaturen + Tests an userId-Schluessel angepasst (Rule 3, nicht im Plan gelistet), plus neuer IDOR-Testapps/api/src/tenders/adapters/email-alert.adapter.ts— Warnmeldung nennt Zeilen-id + Besitzer statt Mandant (T-17-03); Sammelabfrage-Mechanik und Fehlerbehandlung je Zeile unangetastetapps/api/src/tenders/adapters/email-alert.adapter.spec.ts— Config-Fixtures umid/userIdergaenzt, drei neue Faelle (Mehrfach-Postfach-Fanout, Warnmeldungs-Inhalt, ownerTenantId-Divergenz)apps/web/src/app/(portal)/modules/tender-radar/my-sources/page.tsx— neue Seite "Meine Quellen"apps/web/src/messages/de.json,apps/web/src/messages/en.json—tenderRadar.mySources.*Schluessel ergaenzt
Decisions Made
- Checkpoint 1 (gate=blocking): "weiter" — Freigabe fuer beide Datenbank-Umbauten der Phase, gestuetzt auf gemessene 0 Bestandszeilen (lokal und alpha)
- tenantId bleibt denormalisiert, wird bei jedem Save (create UND update) neu geschrieben
- email-config-Endpunkte wechseln von rollenbasiert auf modulbasiert (D-01 beabsichtigt, T-17-06 disposition=accept)
- Eigene Seite statt Erweiterung von
/settings/general/account(D-01 offener Punkt 4) - Adapter-Warnmeldung nennt Zeilen-id + userId statt tenantId, da ein Mandant jetzt mehrere Postfaecher haben kann
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] tenders.controller.spec.ts an neue Service-Signatur angepasst
- Found during: Task 2 (Type-Check nach Controller-Umstellung)
- Issue: Die bestehenden Controller-Tests riefen
getConfigForApi(tenantId)/saveConfig(tenantId, dto)mit der alten Signatur auf — nicht im Plan gelistet, aber ohne Anpassung kompiliert das Projekt nicht und die Tests schlagen fehl - Fix: Fake-Service-Signaturen und die zwei email-config-Tests auf
getConfigForApi(userId)/saveConfig({userId,tenantId}, dto)umgestellt; einen zusaetzlichen IDOR-Test ergaenzt (zwei Nutzer loesen unterschiedliche userIds auf) - Files modified: apps/api/src/tenders/tenders.controller.spec.ts
- Verification:
pnpm --filter @tessera/api type-checkfehlerfrei, 49/49 Tests in der Datei gruen - Committed in:
05b1d29(Task 2 commit)
2. [Rule 3 - Blocking] tender-email-config.service.spec.ts vollstaendig auf userId umgeschrieben, bereits in Task 2
- Found during: Task 2 (Type-Check —
saveConfigerwartet jetzt ein Objekt statt eines Strings) - Issue: Die Plan-Zuordnung dieser Datei zu Task 3 haette den Type-Check von Task 2 nicht bestehen lassen — der Compiler kennt keine Task-Grenzen
- Fix: Datei bereits in Task 2 auf die neue Signatur umgeschrieben (inkl. der beiden von Task 3 verlangten neuen Faelle: tenantId beim Anlegen, zwei Nutzer = zwei Zeilen), damit beide Tasks durchgaengig kompilieren
- Files modified: apps/api/src/tenders/tender-email-config.service.spec.ts
- Verification: 8/8 Tests gruen in Task 2 wie in Task 3
- Committed in:
05b1d29(Task 2 commit, vorgezogen aus Task 3)
Total deviations: 2 auto-fixed (beide Rule 3 — Kompilierfaehigkeit) Impact on plan: Beide Anpassungen waren fuer die Korrektheit der eigentlichen Plan-Aenderung zwingend notwendig (der Controller/Service-Vertrag aendert sich, angrenzende Tests muessen mitziehen). Kein Scope Creep — beide Dateien testen ausschliesslich das, was der Plan ohnehin verlangt.
Issues Encountered
- Lokaler Postgres-Container (
tessera-ctl-db-1) lief zu Sessionbeginn nicht — gestartet und ueber die dokumentierte Container-IP (172.19.0.2,tessera:tessera_dev) angebunden, wie in den Projektnotizen vorgesehen - Zwei bereits vorhandene, noch nicht angewendete Migrationen (
20260811120000_doe_notice_url_backfill,20260811140000_encrypt_ldap_bind_password) mussten vor der neuen Migration permigrate deploynachgezogen werden — kein Blocker, nur Reihenfolge
User Setup Required
None — keine externe Dienstkonfiguration erforderlich. Die Migration ist bisher nur lokal angewendet; das Ausrollen auf dem Testserver (192.168.13.12) bleibt bewusst Nutzeraktion beim naechsten Deploy (Projektregel: kein docker compose pull/up/rebuild durch Claude auf dem Testserver).
Next Phase Readiness
- Die duenne Bahn (Datenbank -> Migration -> Dienst -> Endpunkt -> Seite) steht und ist bewiesen (335/335
src/tenders-Tests, 603/603 API gesamt, 192/192 Web gesamt, beide Typpruefungen fehlerfrei) - Plan 17-02 (RSS-Feeds, Besitzer-Feld) kann auf denselben Checkpoint-Freigaben aufbauen — die Nutzerfreigabe deckte explizit beide Datenbank-Umbauten der Phase ab
- Offen: Browser-Gegenprobe fuer
/modules/tender-radar/my-sourcesmit zwei Konten desselben Mandanten (WINDOWS.md #7, unrun-verify) — vor/gsd-shipnachzuholen - Offen: Rollout auf dem Testserver bleibt Nutzeraktion; die Migration liegt bereit, ist aber dort noch nicht angewendet
Self-Check: PASSED
Alle im SUMMARY genannten Dateien existieren auf der Festplatte; beide Task-Commit-Hashes (05b1d29, 55ceb24) sind im Git-Log auffindbar.
Phase: 17-eigene-ausschreibungs-quellen-je-nutzer Completed: 2026-08-12