Files
tessera-ctl/.planning/phases/17-eigene-ausschreibungs-quellen-je-nutzer/17-03-SUMMARY.md
T
schalli 4453e86626
Tessera CI/CD / Lint & Type Check (push) Successful in 46s
Tessera CI/CD / Tests (push) Successful in 53s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m58s
docs(17-03): complete UI-Aufteilung Meine Quellen vs. Administration plan
2026-08-12 12:06:31 +02:00

204 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 17-eigene-ausschreibungs-quellen-je-nutzer
plan: 03
subsystem: ui
tags: [nextjs, next-intl, zustand, vitest, testing-library]
# Dependency graph
requires:
- phase: 17-01
provides: "TenderEmailConfig per-user, /modules/tender-radar/my-sources (Seite mit Postfach-Abschnitt)"
- phase: 17-02
provides: "RssFeedSource.isPlatformWide-Vertrag (GET/POST /rss-feeds, scope-Wunsch, Besitz-basierter Loeschschutz)"
provides:
- "my-sources/page.tsx vollstaendig: Postfach + eigene Feeds + Digest-Intervall auf einer Seite"
- "RssFeedListForm mit scope-Prop (personal/platform) — eine Komponente fuer beide Seiten"
- "DigestIntervalForm als eigenstaendige Komponente (aus settings/page.tsx herausgeloest)"
- "settings/page.tsx auf reine Administration reduziert, Anzeige-Rollenpruefung ueber useAuthStore"
- "Zahnrad auf der Modulseite fuehrt zu /my-sources statt /settings"
- "REQUIREMENTS.md SRC-01..05 Sektion + Traceability (fehlte bisher trotz Nutzung in 17-01/17-02-SUMMARY)"
affects: [dkv-fleet-settings-restructuring, future-per-user-module-settings]
# Actuals (#2632)
actuals:
tokens: 18180
tasks: 3
commits: 3
tech-stack:
added: []
patterns:
- "Eine Formkomponente mit einem scope-Prop (personal/platform) statt zwei fast identischer Komponenten — der Server entscheidet ueber Berechtigung, das Prop entscheidet nur ueber Darstellung und den scope-Wunsch im Request"
- "Anzeige-Rollenpruefung ueber useAuthStore in der Seite selbst (drei Zustaende: unbekannt/Platzhalter, erlaubt/Inhalt, verweigert/Hinweis+Verweis) statt eines Guards oder Redirects — verbindliche Pruefung bleibt serverseitig"
- "Verhaltensunveraendertes Herausloesen einer Komponente aus einer Seite ohne neue i18n-Schluessel, wenn nur der Ort wechselt, nicht das Verhalten (DigestIntervalForm)"
key-files:
created:
- "apps/web/src/app/(portal)/modules/tender-radar/settings/components/DigestIntervalForm.tsx"
- "apps/web/src/app/(portal)/modules/tender-radar/my-sources/my-sources.test.tsx"
- "apps/web/src/app/(portal)/modules/tender-radar/settings/settings-roles.test.tsx"
modified:
- apps/web/src/lib/tender-radar-api.ts
- "apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.tsx"
- "apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.test.tsx"
- "apps/web/src/app/(portal)/modules/tender-radar/my-sources/page.tsx"
- "apps/web/src/app/(portal)/modules/tender-radar/settings/page.tsx"
- "apps/web/src/app/(portal)/modules/tender-radar/page.tsx"
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
- .planning/REQUIREMENTS.md
key-decisions:
- "[Rule 3] settings/page.tsx auf RssFeedListForm scope=\"platform\" vorgezogen bereits in Task 1, statt erst in Task 2 — Task 1s eigener Type-Check-Verify verlangt eine kompilierbare RssFeedListForm-Prop-Signatur ueber das ganze Projekt hinweg, gleiches Muster wie in 17-01/17-02"
- "[Rule 1] createRssFeed()-Antwort traegt kein isPlatformWide (nur GET /rss-feeds mappt es serverseitig, T-17-12) — RssFeedListForm setzt das Feld nach dem Anlegen lokal aus dem verwendeten scope, sonst waere ein frisch angelegter plattformweiter Feed bis zum naechsten Neuladen aus seiner eigenen Liste verschwunden"
- "page.settingsTitle bleibt bestehen und wird als Verweistext auf der Nutzerseite fuer Administratoren wiederverwendet (Task 1/2), statt eines separaten neuen Schluessels — neuer Schluessel page.mySourcesTitle nur fuer das umgehaengte Zahnrad"
- "REQUIREMENTS.md um die SRC-01..05-Sektion und Traceability-Zeilen ergaenzt — Luecke aus Plan 17-01/17-02 (dort bereits requirements-completed im SUMMARY-Frontmatter gefuehrt, aber nie in REQUIREMENTS.md selbst nachgezogen), gehoert inhaltlich zum Requirements-Traceability-Schritt dieses Plans"
requirements-completed: [SRC-04, SRC-05]
coverage:
- id: D1
description: "\"Meine Quellen\" traegt alle drei nutzereigenen Abschnitte (Postfach, eigene Feeds, Benachrichtigung) auf einer Seite; ein neu angelegter eigener Feed erscheint sofort in der eigenen Liste; plattformweite Feeds erscheinen darunter als nicht bedienbare Aufzaehlung mit Administrations-Hinweis"
requirement: "SRC-04"
verification:
- kind: unit
ref: "apps/web/src/app/(portal)/modules/tender-radar/my-sources/my-sources.test.tsx (5 Tests)"
status: pass
- kind: unit
ref: "apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.test.tsx (scope=personal-Block, 6 Tests inkl. Mischliste mit/ohne Entfernen-Knopf)"
status: pass
human_judgment: false
- id: D2
description: "Die Administrationsseite zeigt nur noch Abrufintervall und plattformweite Feeds; ein Konto ohne ADMIN/SUPER_ADMIN-Rolle sieht dort keine Bedienelemente mehr, sondern Hinweis + Verweis auf \"Meine Quellen\"; waehrend die Rolle noch unbekannt ist, erscheint weder das eine noch das andere"
requirement: "SRC-05"
verification:
- kind: unit
ref: "apps/web/src/app/(portal)/modules/tender-radar/settings/settings-roles.test.tsx (5 Tests: USER/ADMIN/SUPER_ADMIN/unbekannt/entfernte Ueberschriften)"
status: pass
- kind: unit
ref: "apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.test.tsx (scope=platform-Block, 2 Tests: eigene Feeds tauchen dort nicht auf, scope-Parameter im Request)"
status: pass
human_judgment: false
- id: D3
description: "Das Zahnrad auf der Modulseite fuehrt jeden Nutzer nach /my-sources statt zur admin-only Administrationsseite; Administratoren erreichen die Administrationsseite von dort mit einem Klick"
requirement: "SRC-04"
verification: []
human_judgment: true
rationale: "Browser-Gegenprobe (Klick auf das Zahnrad, Navigationsziel im echten Router pruefen) nicht ausgefuehrt — kein Browser-Tool in dieser Session verfuegbar (WINDOWS.md #8/#9). Der Link selbst ist per Testing-Library gegen den gerenderten href geprueft (my-sources.test.tsx, settings-roles.test.tsx), nicht aber die tatsaechliche Client-seitige Navigation im Next.js-Router."
- id: D4
description: "Alle neuen Beschriftungen liegen in Deutsch und Englisch vor; keine mehr verwendete Beschriftung bleibt verwaist"
requirement: "SRC-04"
verification:
- kind: unit
ref: "Node-Skript-Schluesselvergleich beider Sprachdateien (in allen drei Task-<verify>-Bloecken gelaufen)"
status: pass
human_judgment: false
duration: 62min
completed: 2026-08-12
status: complete
---
# Phase 17 Plan 03: UI-Aufteilung — "Meine Quellen" vs. Administration Summary
**Ausschreibungs-Radar-Oberflaeche in zwei Seiten getrennt: "Meine Quellen" traegt jetzt Postfach, eigene RSS-Feeds und Digest-Intervall auf einer Seite fuer jeden Modulnutzer, die Administrationsseite schrumpft auf Abrufintervall und plattformweite Feeds mit einer Anzeige-Rollenpruefung — der urspruengliche Anlass des Backlog-Punkts ist damit geschlossen.**
## Performance
- **Duration:** 62 min
- **Started:** 2026-08-12T09:58:00Z
- **Completed:** 2026-08-12T11:00:00Z
- **Tasks:** 3
- **Files modified:** 13 (3 neu, 10 geaendert) + Backlog-Punkt verschoben + REQUIREMENTS.md ergaenzt
## Accomplishments
- `RssFeedSource` bekommt das serverseitig gelieferte `isPlatformWide`-Kennzeichen, `createRssFeed` einen `scope`-Parameter (`personal`/`platform`, Vorgabe `personal`) — der Server entscheidet ueber Berechtigung (T-17-08), das Frontend nur ueber Darstellung
- `RssFeedListForm` bedient jetzt beide Seiten ueber ein `scope`-Prop: `scope="personal"` zeigt die eigenen Feeds editierbar und plattformweite darunter als schlichte, nicht bedienbare Liste mit Administrations-Hinweis; `scope="platform"` zeigt nur plattformweite Feeds editierbar, eigene Feeds tauchen dort gar nicht auf
- `DigestIntervalForm` unveraendert aus `settings/page.tsx` herausgeloest — dieselbe Logik, dieselben Beschriftungen, jetzt eine eigenstaendige Komponente, die beide Seiten nutzen
- `/modules/tender-radar/my-sources` traegt jetzt alle drei nutzereigenen Abschnitte (Postfach, eigene Feeds, Benachrichtigung) auf einer Seite; Administratoren sehen zusaetzlich einen Verweis auf die Administrationsseite
- `/modules/tender-radar/settings` zeigt nur noch Abrufintervall und plattformweite Feeds; eine Anzeige-Rollenpruefung ueber den vorhandenen Anmelde-Speicher blendet die Bedienelemente fuer Konten ohne ADMIN/SUPER_ADMIN-Rolle aus (Hinweis + Verweis auf "Meine Quellen" stattdessen) — die verbindliche Pruefung bleibt serverseitig unveraendert
- Das Zahnrad auf der Modulseite fuehrt jetzt zu "Meine Quellen" statt zur Administrationsseite
- Backlog-Punkt `2026-08-11-tender-radar-einstellungen-mischen-rollen.md` nach `todos/completed/` verschoben, mit Resolution-Abschnitt, der beide vom User im Gespraech getroffenen Entscheidungen (eigene Quellen je Nutzer, Trefferliste bleibt plattform-global) und die Antwort auf den offenen Punkt 4 (eigene nutzerseitige Modulseite als Vorbild fuer DKV-Fleet und kuenftige Module) dokumentiert
- `REQUIREMENTS.md` um die SRC-01..05-Sektion und Traceability-Zeilen ergaenzt (Luecke aus 17-01/17-02 geschlossen)
## Task Commits
Jede Aufgabe wurde einzeln committet:
1. **Task 1: "Meine Quellen" wird vollstaendig — Postfach, eigene Feeds, Benachrichtigung** — `4100bb5` (feat)
2. **Task 2: Die Administrationsseite schrumpft auf das, was Administration ist** — `150046e` (feat)
3. **Task 3: Tests fuer beide Seiten und der Backlog-Punkt wird zugemacht** — `809afbc` (test)
**Plan metadata:** wird mit diesem SUMMARY committet (docs)
## Files Created/Modified
- `apps/web/src/lib/tender-radar-api.ts` — `RssFeedSource.isPlatformWide`, `createRssFeed(payload, scope)`
- `apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.tsx` — `scope`-Prop, editierbare/nicht-editierbare Teillisten, lokale `isPlatformWide`-Ableitung nach dem Anlegen
- `apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.test.tsx` — auf `scope` umgestellt, Mischlisten-Faelle fuer beide Scopes ergaenzt
- `apps/web/src/app/(portal)/modules/tender-radar/settings/components/DigestIntervalForm.tsx` — neu, unveraendert aus `settings/page.tsx` herausgeloest
- `apps/web/src/app/(portal)/modules/tender-radar/my-sources/page.tsx` — Abschnitte "Meine Feeds" und "Benachrichtigung" ergaenzt, Verweis auf Administrationsseite fuer ADMIN/SUPER_ADMIN
- `apps/web/src/app/(portal)/modules/tender-radar/my-sources/my-sources.test.tsx` — neu, 5 Tests
- `apps/web/src/app/(portal)/modules/tender-radar/settings/page.tsx` — Postfach-/Benachrichtigungsabschnitt entfernt, Anzeige-Rollenpruefung ueber `useAuthStore`
- `apps/web/src/app/(portal)/modules/tender-radar/settings/settings-roles.test.tsx` — neu, 5 Tests
- `apps/web/src/app/(portal)/modules/tender-radar/page.tsx` — Zahnrad zeigt auf `/my-sources`, neue Beschriftung
- `apps/web/src/messages/de.json`, `apps/web/src/messages/en.json` — neue `mySources.*`/`settings.*`/`page.mySourcesTitle`-Schluessel, drei verwaiste `settings.*`-Schluessel entfernt
- `.planning/todos/completed/2026-08-11-tender-radar-einstellungen-mischen-rollen.md` — verschoben, mit Resolution-Abschnitt
- `.planning/REQUIREMENTS.md` — SRC-01..05-Sektion + Traceability ergaenzt
## Decisions Made
- `settings/page.tsx` bereits in Task 1 auf `RssFeedListForm scope="platform"` vorgezogen (Rule 3), volle Rollenpruefung + Abschnittsreduktion folgte in Task 2
- `createRssFeed`s Antwort traegt kein `isPlatformWide` — Komponente leitet es lokal aus dem verwendeten `scope` ab (Rule 1, sonst verschwaende ein frisch angelegter plattformweiter Feed bis zum Neuladen)
- `page.settingsTitle` bleibt bestehen und dient jetzt als Verweistext auf der Nutzerseite; neuer Schluessel `page.mySourcesTitle` nur fuer das umgehaengte Zahnrad
- `REQUIREMENTS.md` um SRC-01..05 ergaenzt (gehoert zum Requirements-Traceability-Schritt dieses Plans, schliesst eine Luecke aus 17-01/17-02)
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 3 - Blocking] `settings/page.tsx` auf `RssFeedListForm scope="platform"` vorgezogen aus Task 2 nach Task 1**
- **Found during:** Task 1 (Type-Check nach Aenderung der `RssFeedListForm`-Prop-Signatur)
- **Issue:** Task 1s eigener Verify verlangt einen fehlerfreien projektweiten Type-Check; `settings/page.tsx` (Task 2s Datei) rief `<RssFeedListForm />` noch ohne das neue Pflicht-Prop `scope` auf
- **Fix:** Minimale Ergaenzung `scope="platform"` an der bestehenden Aufrufstelle — die vollstaendige Umgestaltung der Seite (Rollenpruefung, Abschnittsreduktion) blieb Task 2 vorbehalten
- **Files modified:** apps/web/src/app/(portal)/modules/tender-radar/settings/page.tsx
- **Verification:** `pnpm --filter @tessera/web type-check` fehlerfrei ab Task 1
- **Committed in:** 4100bb5 (Task 1 commit)
**2. [Rule 1 - Bug] `RssFeedListForm` leitet `isPlatformWide` nach dem Anlegen lokal ab**
- **Found during:** Task 1 (beim Entwurf von `handleAdd` fuer beide Scopes)
- **Issue:** `POST /rss-feeds` mappt `isPlatformWide` nicht (nur `GET /rss-feeds` tut das serverseitig, T-17-12) — ein frisch angelegter Eintrag haette das Feld `undefined`, wodurch ein neu angelegter plattformweiter Feed (`scope="platform"`) faelschlich aus der eigenen editierbaren Liste gefallen waere, bis zum naechsten Neuladen
- **Fix:** Nach erfolgreichem `createRssFeed(...)` wird `isPlatformWide` clientseitig aus dem verwendeten `scope` gesetzt (`scope === 'platform'`), statt sich auf ein vom Server nicht geliefertes Feld zu verlassen
- **Files modified:** apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.tsx
- **Verification:** RssFeedListForm.test.tsx deckt beide Scopes explizit ab ("die neue Feed landet sofort in der editierbaren Liste, mit funktionierendem Entfernen-Knopf")
- **Committed in:** 4100bb5 (Task 1 commit)
---
**Total deviations:** 2 auto-fixed (1× Rule 3 Kompilierfaehigkeit, 1× Rule 1 Bugfix)
**Impact on plan:** Beide Anpassungen waren fuer die Korrektheit der eigentlichen Plan-Aenderung zwingend notwendig. Kein Scope Creep — Deviation 1 ist eine minimale Vorziehung der ohnehin geplanten Aenderung, Deviation 2 behebt eine waehrend der Implementierung entdeckte Inkonsistenz zwischen POST- und GET-Antwortform derselben Ressource.
## Issues Encountered
- `REQUIREMENTS.md` enthielt keine SRC-Kategorie, obwohl 17-01/17-02-SUMMARY bereits `requirements-completed: [SRC-01, SRC-03]` bzw. `[SRC-02, SRC-03]` fuehrten — die Datei war seit dem Anlegen von Phase 17 nie nachgezogen worden (nur ROADMAP.md hatte die SRC-Beschreibungen). Ergaenzt als Teil des Requirements-Traceability-Schritts dieses Plans, keine separate Aenderung noetig.
## User Setup Required
None — keine externe Dienstkonfiguration erforderlich.
## Next Phase Readiness
- Phase 17 ist inhaltlich abgeschlossen: alle drei Plaene liefern D-01 bis D-05 vollstaendig, der Backlog-Punkt ist geschlossen, SRC-01..05 sind erledigt
- Web 205/205 Tests gruen, API `src/tenders` 362/362 gruen, beide Typpruefungen (API + Web) fehlerfrei
- Offen: die Browser-Gegenprobe aus den `human-check`-Schritten aller drei Plaene (17-01 bis 17-03) — kein Browser-Tool in den jeweiligen Sitzungen verfuegbar, festgehalten in WINDOWS.md (#7, #8, #9), vor `/gsd-ship` nachzuholen
- Offen: Rollout beider Migrationen (17-01, 17-02) auf dem Testserver (192.168.13.12) bleibt bewusst Nutzeraktion (Projektregel: kein `docker compose pull/up/rebuild` durch Claude auf dem Testserver)
## Self-Check: PASSED
Alle im SUMMARY genannten Dateien existieren auf der Festplatte; alle drei Task-Commit-Hashes (`4100bb5`, `150046e`, `809afbc`) sind im Git-Log auffindbar.
---
*Phase: 17-eigene-ausschreibungs-quellen-je-nutzer*
*Completed: 2026-08-12*