test(17): Browser-Gegenproben #7/#8/#9 nachgeholt — Phase 17 auf passed

Die drei human-check-Punkte aus Phase 17 waren am 2026-08-12 offen geblieben,
weil in der Ausfuehrungssitzung kein Browser-Tool verfuegbar war. Sie wurden
jetzt gegen frisch gebaute Images aus main (79015dd) mit echtem Chrome und
leerer Datenbank durchgeklickt.

#7 (17-01 Task 2): nutzer1 speichert sein Postfach, die Werte ueberleben den
Reload; nutzer2 sieht ein leeres Formular statt der Werte von nutzer1. Danach
zwei TenderEmailConfig-Zeilen mit je eigenem userId.

#8 (17-03 Task 1): Meine Quellen zeigt alle drei Abschnitte, ein eigener
RSS-Feed erscheint sofort mit Entfernen-Knopf, der plattformweite service-bund
steht darunter ohne, und das Digest-Intervall "Woechentlich" ueberlebt den
Reload.

#9 (17-03 Task 2): USER sieht auf /settings keine Bedienelemente, nur Hinweis
und Verweis; SUPER_ADMIN sieht Abrufintervall und plattformweite Feeds, aber
kein Postfach und keine Benachrichtigung mehr. Das Zahnrad fuehrt in beiden
Faellen nach Meine Quellen.

Zusaetzlich am laufenden Server gemessen, weil eine ausgeblendete Schaltflaeche
kein Beweis fuer eine serverseitige Sperre ist: als nutzer2 liefert GET
/rss-feeds nur den plattformweiten Feed, DELETE auf den plattformweiten wie auf
den fremden Feed antwortet 404 ohne die Zeile anzufassen, und POST mit
scope=platform wird mit 403 abgewiesen.

WINDOWS.md #7/#8/#9 auf fixed (open_count 9 -> 6), Verifikationsbericht mit
Nachtrag und Screenshots auf passed, ROADMAP auf Complete, STATE nachgezogen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
This commit is contained in:
2026-09-07 09:53:02 +02:00
parent 79015dd3f4
commit 72d0ba7e48
8 changed files with 122 additions and 48 deletions
@@ -1,35 +1,42 @@
---
phase: 17-eigene-ausschreibungs-quellen-je-nutzer
verified: 2026-08-12T15:10:00Z
status: human_needed
reverified: 2026-09-07T07:55:00Z
status: passed
score: 7/7 must-haves verified
behavior_unverified: 0
overrides_applied: 0
human_verification:
- test: "17-01 Task 2 human-check: Als normaler Nutzer (Rolle USER, Modulzugang) /modules/tender-radar/my-sources oeffnen, Postfach speichern, neu laden — Werte stehen noch. Mit zweitem Konto desselben Mandanten anmelden — Formular ist leer, nicht die Werte des ersten Nutzers."
expected: "Jeder Nutzer sieht und speichert ausschliesslich sein eigenes Postfach; kein Nutzer sieht das Formular des anderen vorausgefuellt."
why_human: "Erfordert echte Browser-Session mit zwei unterschiedlichen angemeldeten Konten; aus dem Code/Tests allein nicht zu beobachten. Als WINDOWS.md #7 (unrun-verify, status open) erfasst."
- test: "17-03 Task 1 human-check: Als normaler Nutzer /modules/tender-radar/my-sources oeffnen — drei Abschnitte sichtbar, eigenen RSS-Feed anlegen (erscheint sofort in eigener Liste), service.bund.de-Feed steht darunter ohne Entfernen-Knopf, Digest-Intervall auf 'Woechentlich' stellen, neu laden — Wert bleibt."
expected: "Alle drei Abschnitte funktionieren durchgehend im echten Browser, kein Verweis auf die Administrationsseite fuer einen normalen Nutzer."
why_human: "Kein Browser-Tool in der Ausfuehrungssitzung verfuegbar. Als WINDOWS.md #8 (unrun-verify, status open) erfasst."
- test: "17-03 Task 2 human-check: Als Konto mit Rolle USER /modules/tender-radar/settings direkt aufrufen — keine Bedienelemente, nur Hinweis + Verweis. Als Administrator dieselbe Adresse — Abrufintervall + plattformweite Feeds da, Postfach/Benachrichtigung nicht mehr. Zahnrad fuehrt in beiden Faellen nach 'Meine Quellen'."
expected: "Rollentrennung greift im echten Browser identisch zu den Komponententests; Navigation ueber das Zahnrad funktioniert im echten Next.js-Router."
why_human: "Kein Browser-Tool in der Ausfuehrungssitzung verfuegbar. Als WINDOWS.md #9 (unrun-verify, status open) erfasst."
human_verification: []
human_verification_completed:
- test: "17-01 Task 2 human-check — zwei Konten desselben Mandanten, je eigenes Postfach"
result: passed
completed: 2026-09-07
evidence: "WINDOWS.md #7 fixed; uat-2026-09-07/w7-nutzer2-leer.png; DB: zwei TenderEmailConfig-Zeilen mit je eigenem userId"
- test: "17-03 Task 1 human-check — Meine Quellen, drei Abschnitte, eigener Feed, Digest-Intervall"
result: passed
completed: 2026-09-07
evidence: "WINDOWS.md #8 fixed; uat-2026-09-07/w8-nutzer1-my-sources.png; DB: TenderNotificationPref digestInterval=weekly"
- test: "17-03 Task 2 human-check — Rollentrennung /settings, Zahnrad-Navigation"
result: passed
completed: 2026-09-07
evidence: "WINDOWS.md #9 fixed; uat-2026-09-07/w9-user-settings.png + w9-admin-settings.png"
---
# Phase 17: Eigene Ausschreibungs-Quellen je Nutzer — Verification Report
**Phase Goal:** Jeder Nutzer speist seine eigenen Ausschreibungs-Quellen ein — eigenes Alert-Postfach und eigene RSS-Feeds statt einer gemeinsamen Konfiguration. Die Einstellungsseite trennt danach sauber nach Zustaendigkeit: Plattform-Administration (Abrufintervall) bleibt Admin-Sache, Quellen und Digest-Intervall gehoeren dem Nutzer.
**Verified:** 2026-08-12
**Status:** human_needed
**Re-verification:** No — initial verification
**Verified:** 2026-08-12 — **re-verifiziert im Browser:** 2026-09-07
**Status:** passed
**Re-verification:** Yes — die drei offenen Browser-Gegenproben wurden am 2026-09-07 nachgeholt (siehe Nachtrag am Ende)
## Summary Verdict
**The phase goal is achieved in the codebase.** All backend and frontend mechanisms described in 17-CONTEXT.md (D-01..D-05), all five ROADMAP requirements (SRC-01..SRC-05), and all seven ROADMAP Success Criteria are implemented, migrated locally, and covered by 362/362 API `src/tenders` tests + 58/58 web tender-radar tests, both re-run fresh in this verification (not taken from SUMMARY claims). The one hard scope fence (D-05: `Tender` stays platform-global) holds — verified directly against the live database schema, not just against source comments. Test quality on inspection is genuinely good: hand-written expectations, evaluating Prisma fakes for ownership/delete-protection, no tautological "expectation built from the same helper as the code under test" pattern found.
**However, the phase cannot be marked `passed`.** Three `human-check` items from the plans (17-01 Task 2, 17-03 Task 1, 17-03 Task 2) were never executed in a real browser — this is honestly disclosed in the SUMMARYs and in WINDOWS.md (#7/#8/#9, all `status: open`), not glossed over. This verifier ran the same programmatic checks the SUMMARYs claim (test suites, type-checks, migration status, DB index/content inspection) and confirms all of them pass, but the actual click-through UX (form pre-fill, save-then-reload persistence, role-based visibility in a live Next.js router, navigation via the gear icon) remains genuinely unproven. Per the routing rules, this makes the phase `human_needed`, not `passed`.
**Stand 2026-08-12 konnte die Phase nicht auf `passed` gesetzt werden**, weil drei `human-check`-Punkte aus den Plaenen (17-01 Task 2, 17-03 Task 1, 17-03 Task 2) nie in einem echten Browser ausgefuehrt worden waren — offen ausgewiesen in den SUMMARYs und in WINDOWS.md (#7/#8/#9). Die programmatischen Pruefungen liefen damals schon alle gruen; unbewiesen blieb allein der tatsaechliche Durchklick (Formular-Vorbefuellung, Speichern-und-Neuladen, Rollensichtbarkeit im echten Next.js-Router, Navigation ueber das Zahnrad).
**Am 2026-09-07 wurden genau diese drei Punkte im echten Browser nachgeholt und alle drei bestanden** — Aufbau, Beobachtungen und Belege stehen im Nachtrag am Ende dieses Berichts. WINDOWS.md #7/#8/#9 stehen auf `fixed`. Damit wechselt die Phase auf `passed`.
## Goal Achievement
@@ -127,7 +134,8 @@ Inspected `tender-rss-feed.service.spec.ts`, `email-alert.adapter.spec.ts`, `Rss
None. Grep for `TBD|FIXME|XXX|TODO|HACK|PLACEHOLDER` (and case-insensitive `placeholder`/`not yet implemented`) across all 15 phase-modified backend/frontend files returned only pre-existing, benign uses of the word "placeholder" (documenting the `portals: ['rss']` symbolic constant, and the loading-skeleton UI state) — none indicate unfinished work.
### Human Verification Required
### Human Verification Required — am 2026-09-07 vollstaendig nachgeholt (alle drei bestanden)
1. **17-01 Task 2 human-check (WINDOWS.md #7, open)**
**Test:** As a normal USER-role account with module access, open `/modules/tender-radar/my-sources`, fill and save the mailbox form, reload — values persist. Then log in as a second account of the same tenant — the form is empty, not pre-filled with the first user's values.
@@ -150,9 +158,80 @@ All three items are honestly recorded as `open`/`unrun-verify` in `.planning/WIN
No implementation gaps found. All must-haves at the mechanism level (schema, migration, service, controller, adapter, frontend wiring, tests, i18n, requirements traceability, backlog closure) are verified directly against the live codebase and a live local database — not inferred from SUMMARY claims. The phase's own scope fence (D-05, `Tender` stays platform-global) is independently confirmed intact.
The only open item is the disclosed set of three real-browser click-throughs, which the phase's own artifacts already flag as unrun rather than passed. This is a verification-completeness gap, not an implementation gap — routed here as `human_needed` per the standard decision tree (a non-empty human-verification section always overrides `passed`, even when every other truth is independently verified).
Der einzige offene Punkt war die Gruppe der drei echten Browser-Durchlaeufe — eine Luecke in der Vollstaendigkeit der Pruefung, keine Luecke in der Umsetzung. Sie wurde am 2026-09-07 geschlossen (siehe Nachtrag); es sind keine offenen Punkte mehr verzeichnet.
---
*Verified: 2026-08-12*
*Verifier: Claude (gsd-verifier)*
---
## Nachtrag: Browser-Gegenprobe vom 2026-09-07
Die drei am 2026-08-12 offen gebliebenen `human-check`-Punkte wurden nachgeholt. Aufbau: frisch
gebaute Images aus `main` (`79015dd`), lokaler Docker-Stack, leere Datenbank, echter Chrome
ueber Playwright. Testdaten ueber die Oberflaeche angelegt — Modul im Marktplatz aktiviert,
Freigabe in der Matrix an die Standardgruppe erteilt, zwei USER-Konten (`nutzer1`, `nutzer2`)
im selben Mandanten.
### WINDOWS #7 — eigenes Postfach je Nutzer (17-01 Task 2) — BESTANDEN
| Schritt | Beobachtung |
|---|---|
| `nutzer1` oeffnet `/modules/tender-radar/my-sources` | Postfach-Formular leer, Hinweis „Noch nicht gespeichert" |
| Postfach ausfuellen und speichern | „Einstellungen gespeichert.", Hinweis verschwindet |
| Seite neu laden | `imap.nutzer1.test`, `alerts@nutzer1.test`, Benutzername `nutzer1-postfach` stehen wieder da |
| `nutzer2` oeffnet dieselbe Seite | Formular **leer**, Hinweis „Noch nicht gespeichert" — nicht die Werte von `nutzer1` |
| `nutzer2` speichert sein eigenes Postfach | Zweite Zeile entsteht, erste bleibt unveraendert |
Datenbank danach: zwei `TenderEmailConfig`-Zeilen, je ein eigener `userId`, beide mit gefuelltem
`encryptedInboxCreds`. Beleg: `uat-2026-09-07/w7-nutzer2-leer.png`.
### WINDOWS #8 — Meine Quellen, alle drei Abschnitte (17-03 Task 1) — BESTANDEN
| Schritt | Beobachtung |
|---|---|
| Seitenaufbau | Drei Abschnitte: „Mein Postfach", „Meine Feeds", „Benachrichtigung" |
| Eigenen RSS-Feed anlegen | „Mein Testfeed" erscheint **sofort** in der eigenen Liste, mit Entfernen-Knopf |
| Plattformweiter Feed | `service-bund` steht darunter unter „Diese Feeds werden von der Administration gepflegt und gelten fuer alle." — **ohne** Entfernen-Knopf |
| Digest-Intervall auf „Woechentlich", dann neu laden | Wert steht noch (`TenderNotificationPref.digestInterval = weekly`, nur fuer `nutzer1`) |
| Verweis auf die Administrationsseite | Fuer das USER-Konto **nicht** vorhanden |
`nutzer2` sieht in „Meine Feeds" nur „Noch keine RSS-Feeds hinterlegt" plus den plattformweiten
Feed — der Feed von `nutzer1` taucht bei ihm nicht auf. Beleg:
`uat-2026-09-07/w8-nutzer1-my-sources.png`.
### WINDOWS #9 — Rollentrennung der Einstellungsseite (17-03 Task 2) — BESTANDEN
| Rolle | `/modules/tender-radar/settings` direkt aufgerufen |
|---|---|
| USER (`nutzer1`) | Keine Bedienelemente. Nur „Diese Seite verwaltet plattformweite Einstellungen und ist Administratoren vorbehalten." plus Verweis „Meine Quellen →" |
| SUPER_ADMIN (`admin`) | Abrufintervall (60 Min.), Aktiv-Schalter, Speichern, plus plattformweite RSS-Feeds **mit** Entfernen-Knopf. Postfach und Benachrichtigung sind auf dieser Seite **nicht** mehr vorhanden |
Das Zahnrad auf der Modulseite fuehrt in **beiden** Faellen nach `/modules/tender-radar/my-sources`
— als Link angeklickt, nicht nur im Markup gelesen. Belege:
`uat-2026-09-07/w9-user-settings.png`, `uat-2026-09-07/w9-admin-settings.png`.
### Zusatzbeleg: Schutz gegen fremde und plattformweite Feeds am laufenden Server
Der Verifikationsbericht hatte SC 3 aus dem Quelltext belegt. Die Oberflaeche blendet den
Entfernen-Knopf nur aus — das ist kein Beweis, dass der Server ihn auch verweigert. Deshalb
zusaetzlich gegen die laufende API gemessen, angemeldet als `nutzer2`:
| Aufruf | Antwort | Wirkung |
|---|---|---|
| `GET /modules/tender-radar/rss-feeds` | 200, genau ein Eintrag: `service-bund`, `isPlatformWide: true` | Der Feed von `nutzer1` ist fuer `nutzer2` unsichtbar |
| `DELETE .../rss-feeds/<plattformweiter Feed>` | 404 | Zeile bleibt bestehen |
| `DELETE .../rss-feeds/<Feed von nutzer1>` | 404 | Zeile bleibt bestehen |
| `POST .../rss-feeds` mit `scope: "platform"` | 403 „Nur Administratoren duerfen plattformweite RSS-Feeds anlegen." | Kein Eintrag entsteht |
Der Bestand war danach unveraendert: eine plattformweite Zeile, eine Zeile von `nutzer1`.
### Ergebnis
Alle sieben Erfolgskriterien sind jetzt nicht nur als Mechanismus, sondern auch im laufenden
System belegt. `WINDOWS.md` #7, #8 und #9 stehen auf `fixed`. Der Phasenstatus wechselt von
`human_needed` auf `passed`.
*Nachtrag verfasst: 2026-09-07*
Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB