Files
tessera-ctl/.planning/phases/15-modul-berechtigungen-gruppen-user-grants/15-UAT-2026-09-07.md
T
schalli 0645cac618 docs(15): WINDOWS #10 geschlossen — Browser-Gegenprobe nach dem Fix bestanden
Der am Vormittag gefundene Zugriffs-Guard-Defekt ist behoben (260907-e8k) und im
echten Browser gegen ein frisch gebautes Web-Image nachgeprueft.

nutzer2 ohne Freigabe bekommt jetzt auf /modules/tender-radar, dessen Unterseiten
my-sources und settings sowie auf /modules/dkv-fleet die 403-Seite als
Serverantwort. Auf /modules/cert-manager, wo er eine Freigabe hat, kommt er
weiterhin durch — das ist die Gegenprobe dagegen, dass die Sperre zu weit greift.
admin sieht alle vier Adressen unveraendert, nutzer1 sieht Meine Quellen mit allen
drei Abschnitten; die Phase-17-Funktion ist unbeschaedigt.

Im Bericht zusaetzlich festgehalten, dass ein erster Messversuch per fetch() aus der
laufenden Seite heraus faelschlich alle Seiten als gesperrt meldete, auch fuer den
Administrator. Der Aufruf fuehrt die Sitzung nicht wie eine echte Navigation mit.
Alle berichteten Zahlen stammen aus echten Seitenaufrufen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
2026-09-07 10:40:48 +02:00

156 lines
9.9 KiB
Markdown

---
phase: 15-modul-berechtigungen-gruppen-user-grants
kind: uat-nachtrag
date: 2026-09-07
windows_addressed: [1, 2, 3]
windows_opened: [10]
windows_closed_later: [10]
result: 2 von 3 bestanden, 1 mit Befund — Befund am selben Tag behoben und gegengeprueft
---
# Phase 15 — Browser-Gegenproben, nachgeholt am 2026-09-07
Die drei Browser-Durchläufe aus den Plänen 15-06, 15-07 und 15-08 waren seit dem
2026-08-04 offen, weil in den damaligen Ausführungssitzungen kein Browser-Tool
verfügbar war (WINDOWS.md #1, #2, #3). Sie wurden jetzt nachgeholt.
**Aufbau:** frisch gebaute Images aus `main` (`79015dd`), lokaler Docker-Stack,
leere Datenbank, echter Chrome über Playwright. Testdaten über die Oberfläche
angelegt: Modul im Marktplatz aktiviert, zwei USER-Konten (`nutzer1`, `nutzer2`)
im selben Mandanten, Gruppen und Freigaben über die Administrationsseiten.
## WINDOWS #1 — Gruppenverwaltung (15-06) — BESTANDEN
| Schritt aus dem Plan | Beobachtung |
|---|---|
| Gruppe anlegen | „Vertrieb" erscheint in der Liste, Spalte AD-Bindung „Manuell", 0 Mitglieder |
| Umbenennen | Auf „Vertrieb Innendienst" geändert, Liste zieht nach |
| Standardmarkierung setzen | Markierung wandert exklusiv: „Alle Benutzer" wechselt auf „Als Standardgruppe festlegen", die neue Gruppe trägt „Standardgruppe" |
| Standardmarkierung wieder abschalten | Durch Setzen bei „Alle Benutzer" zurückgewandert |
| Mitglied hinzufügen | „Nutzer Eins" erscheint mit Herkunfts-Badge „Manuell"; seine Auswahl-Checkbox ist danach gesperrt, ein Doppel-Hinzufügen also nicht möglich |
| Mitglied entfernen | Liste wieder leer, Checkbox wieder frei |
| Löschdialog mit gefüllter Gruppe | „Diese Gruppe hat 1 Mitglieder und 1 Modul-Freigaben." — beide Zahlen konkret genannt (D-17) |
| Löschvorgang bei gestoppter API | Sichtbare deutsche Klartextmeldung „Gruppe konnte nicht gelöscht werden. Bitte erneut versuchen.", Löschen-Knopf danach gesperrt, Gruppe bleibt in der Liste |
**Nicht mehr prüfbar, weil bewusst geändert:** Der Plan verlangte „an eine
AD-Gruppe binden und Bindung lösen" sowie die AD-Suche bei gestoppter API. Beides
gibt es an dieser Stelle nicht mehr. Phase 16 hat den Anlegen-Dialog umgebaut: er
trägt jetzt den Hinweis „AD-Gruppen werden im LDAP-Bereich importiert, nicht hier
angelegt." samt Link dorthin. Die Prüfpunkte sind damit gegenstandslos, nicht
übersprungen.
**Kleiner Sprachbefund:** Der Löschdialog schreibt „1 Mitglieder" statt
„1 Mitglied" — Plural auch bei Eins.
## WINDOWS #2 — Freigaben-Matrix und Direkt-Grants (15-07) — BESTANDEN
| Schritt aus dem Plan | Beobachtung |
|---|---|
| Freigabe in der Matrix setzen | Checkbox für „Vertrieb Innendienst" gesetzt, Beschriftung wechselt von „freigeben" auf „entziehen" |
| Freigabe wieder entziehen und Wirkung gegenprüfen | Entzug für „Alle Benutzer" führte dazu, dass `nutzer2` den Zugriff sofort verlor — belegt über alle vier Ebenen unter #3 |
| Aktivierungsdialog, Weg „Sofort freigeben" | Cert Manager aktiviert; Grant an die Standardgruppe „Alle Benutzer" entstand (D-10) |
| Aktivierungsdialog, Weg „Später konfigurieren" | DKV-Rechnung aktiviert; **kein** Grant entstanden (0 Freigaben in der Datenbank) |
| Direkt-Grant neben Gruppen-Grant | Im Benutzer-Detail von `nutzer1` zeigt die Spalte „Über Gruppe(n)" beide freigebenden Gruppen an, während die Spalte „Direkt" unabhängig davon gesetzt werden kann |
| Matrix-Zelle bei gestoppter API | Fehlermeldung erscheint **und** die Checkbox springt in ihren alten Zustand zurück; die Datenbank zeigt danach unveränderte Freigaben — kein optimistischer Zustand überlebt den fehlgeschlagenen Request. Beleg: `uat-2026-09-07/w2-matrix-rollback-api-aus.png` |
| Direkt-Kästchen bei gestoppter API | Fehlermeldung im Dialog, Grant unverändert in der Datenbank |
| Sehr langer Gruppenname | Kopfzeile schneidet mit Ellipse ab („Abteilung Zentraler Einkauf und Vergabemanagement…"), Spaltenbreiten bleiben, die Seite scrollt nicht horizontal. Beleg: `uat-2026-09-07/w2-matrix-lange-namen.png` |
**Befunde ohne Blockerwirkung:**
- Die Fehlermeldung bei gestoppter API lautet in Matrix und Benutzer-Detail roh
„500: Internal Server Error". Der Löschdialog der Gruppenseite kann es besser
(deutscher Klartext) — die Behandlung ist also uneinheitlich.
- Wird eine Matrix-Seite bei bereits gestoppter API frisch geladen, meldet sie dem
Administrator „Zugriff verweigert" statt „Server nicht erreichbar". Das ist eine
irreführende Diagnose: der Administrator vermutet ein Rechteproblem statt eines
Serverausfalls.
- Der Aktivierungsdialog duzt („möchtest du die Freigaben separat konfigurieren?"),
während die übrige Oberfläche siezt.
- Das Deaktivieren eines Moduls entfernt seine Freigaben nicht. Beim
Wiederaktivieren sind die alten Freigaben sofort wieder wirksam. Das wirkt
gewollt, ist aber nirgends festgehalten.
## WINDOWS #3 — Sperrung ohne Freigabe über alle vier Ebenen (15-08) — DURCHGEFÜHRT, MIT BEFUND
Geprüft mit `nutzer2` (Rolle USER, Freigabe für Ausschreibungs-Radar entzogen)
gegen `nutzer1` (Freigabe über Gruppe) und `admin`.
| Ebene | Ergebnis |
|---|---|
| 1. Sidebar | Kategorie „procurement" fehlt für `nutzer2` vollständig; nur „security tools" (Cert Manager, dort freigegeben) erscheint ✓ |
| 2. Direkte URL `/modules/procurement/tender-radar` | 403-Seite „Kein Zugriff auf dieses Modul" mit Handlungsanweisung und Weg zurück ✓ (D-07) |
| 3. Marketplace | Karte trägt „Aktiviert" **und** das Sperr-Badge „Kein Zugriff", ist nicht anklickbar; der Klick löst den Toast „Kein Zugriff auf dieses Modul — wende dich an deinen Administrator." aus und navigiert **nicht** ✓ (D-08). Modul wird gekennzeichnet, nicht ausgeblendet |
| 4. API | `nutzer2` erhält auf `/modules/tender-radar` und allen geprüften Unterendpunkten (`saved-searches`, `rss-feeds`, `email-config`) durchgehend HTTP 403; `nutzer1` durchgehend 200 ✓ |
**Der Nachweis von PERM-04 gelingt damit auf drei von vier Ebenen nicht
vollständig — siehe WINDOWS #10.**
### WINDOWS #10 (neu) — der Zugriffs-Guard greift nicht auf modul-eigenen Routen
Ebene 2 ist nur für die generische Route abgesichert. Der Guard sitzt in
`modules/[category]/[moduleSlug]/page.tsx`. Vier Module haben daneben fest
verdrahtete eigene Routen:
```
apps/web/src/app/(portal)/modules/cert-manager/
apps/web/src/app/(portal)/modules/dkv-fleet/
apps/web/src/app/(portal)/modules/domaincheck/
apps/web/src/app/(portal)/modules/tender-radar/
```
Diese laufen am Guard vorbei. Im Browser als `nutzer2` **ohne** Freigabe gemessen:
| Adresse | Ergebnis |
|---|---|
| `/modules/procurement/tender-radar` | 403-Seite ✓ (generische Route, abgesichert) |
| `/modules/tender-radar` | **volle Seite** — Überschrift, Filter, Suchprofil-Formular, Trefferliste, Zahnrad-Link |
| `/modules/tender-radar/my-sources` | **volle Seite** — Postfach-Formular, Feed-Formular, Digest-Auswahl, alle Knöpfe bedienbar |
| `/modules/dkv-fleet` | **volle Seite** — inklusive Knopf „Jetzt pruefen" und Link zu den Moduleinstellungen |
**Es werden keine Daten preisgegeben.** Die API antwortet auf jedem Endpunkt mit
403, die Listen bleiben leer. Der Defekt liegt auf der Anzeigeebene:
1. Der Nutzer sieht eine Seite, die er nicht benutzen darf, statt der 403-Seite.
2. Die Bedienelemente sind anklickbar und laufen ins Leere — genau das, was
Plan 17-03 auf der Einstellungsseite des Ausschreibungs-Radars abgeschafft hat.
3. Statt einer verständlichen Meldung erscheinen rohe englische Techniktexte
mitten in der deutschen Oberfläche: „Module 'tender-radar' is not accessible
for this user", „Failed to fetch tenders", „Failed to fetch saved searches",
„Failed to fetch notification preference".
Beleg: `uat-2026-09-07/befund-modul-eigene-route-ohne-freigabe.png`
**Behoben am 2026-09-07** (Quick-Task `260907-e8k`, Commits `4a23e13`, `69b6418`).
Umgesetzt wurde nicht ein einzelnes Layout mit Pfadauflösung, sondern je ein `layout.tsx`
pro Modulverzeichnis mit fest eingetragenem Slug — ein Layout deckt in Next.js alle
verschachtelten Unterrouten automatisch mit ab, und der Slug steht damit explizit im Code
statt aus dem Pfad geraten zu werden. Das 403-Markup liegt jetzt einmal als gemeinsame
Komponente vor, die generische Route nutzt dieselbe. Ein Test liest das Modulverzeichnis
aus und verlangt für jedes nicht-dynamische Unterverzeichnis eine `layout.tsx`, damit ein
künftiges Modul die Lücke nicht erneut aufreißt.
### Gegenprobe im Browser nach dem Fix (2026-09-07)
Frisch gebautes Web-Image, echter Chrome, dieselben Konten:
| Konto | Adresse | Ergebnis |
|---|---|---|
| `admin` (SUPER_ADMIN) | `/modules/tender-radar`, `/modules/tender-radar/my-sources`, `/modules/dkv-fleet`, `/modules/procurement/tender-radar` | alle **unverändert offen** — die Sperre trifft niemanden zu viel |
| `nutzer1` (Freigabe über Gruppe) | `/modules/tender-radar/my-sources` | offen, alle drei Abschnitte da — Phase-17-Funktion unbeschädigt |
| `nutzer2` (keine Freigabe) | `/modules/tender-radar`, `/modules/tender-radar/my-sources`, `/modules/tender-radar/settings`, `/modules/dkv-fleet` | alle **gesperrt**, 403-Seite als Serverantwort |
| `nutzer2` auf `/modules/cert-manager` (dort **hat** er eine Freigabe) | | **offen** — die Gegenprobe gegen Überschießen |
Beleg: `uat-2026-09-07/w10-fix-my-sources-gesperrt.png`
**Messhinweis für spätere Prüfungen:** Ein erster Versuch, die Adressen per `fetch()` aus der
laufenden Seite heraus zu prüfen, meldete fälschlich *alle* Seiten als gesperrt — auch für den
Administrator. Der Aufruf führt die Sitzung nicht so mit, wie eine echte Navigation es tut. Die
Zahlen oben stammen ausschließlich aus echten Seitenaufrufen. Wer das nachprüft, sollte nicht
per `fetch` messen.
## Ergebnis
WINDOWS #1 und #2 sind geschlossen. #3 ist als Durchlauf erledigt. Der dabei gefundene
Defekt wurde als #10 erfasst, am selben Tag behoben und im Browser gegengeprüft — er ist
damit ebenfalls geschlossen.