204 lines
16 KiB
Markdown
204 lines
16 KiB
Markdown
---
|
||
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*
|