ADRs: - 0006 Embedding-Modell-Migration v3->v4 (#123) - 0008 DDD-Lightweight-Migration (#136) Analysen: - ddd-bewertung.md (1237 Zeilen) — vollstaendige DDD-Analyse mit Tages-Roadmap - protokoll-parser-v6-machbarkeit.md (418 Zeilen) — #106 Phase 2 Vorbereitung Reference: - zugriffsrechte.md — 63 Routes x 3 User-Status, UI-Sichtbarkeits-Matrix Ops: - scripts/deploy.sh — mit Uptime-Kuma-Wartungsmodus (#149) - scripts/run-digest.sh — taeglicher Mail-Digest-Cron - scripts/run-monitoring-scan.sh — Monitoring-Scan-Cron (noch nicht aktiv) - scripts/smoke-test.sh — Gesamt-Funktionspruefung - pytest.ini: integration/slow/e2e Markers, addopts not-integration Tests/integration/: Live-Adapter-Tests + Frontend-XRef + Citation-Substring + Wahlprogramm-Indexed (4 Live-Test-Suites, marker-opt-in) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.6 KiB
Zugriffsrechte & User-Status
Abgeleitet direkt aus dem Code (app/main.py, app/auth.py, Templates). Stand des Generats: 2026-04-20.
Drei User-Status
| Status | Signal | Guard im Code |
|---|---|---|
Gast (anonymous) |
Kein gültiger access_token-Cookie |
— |
Registriert (authenticated) |
Gültiger Keycloak-JWT, Rolle beliebig | Depends(require_auth) |
| Admin | Keycloak-JWT mit Rolle admin oder gwoe-admin |
Depends(require_admin) |
Zwei Sonder-Modi:
- Dev-Modus (
AUTH_ENABLED=falsein .env): jede Anfrage wird als Anonymous+Admin ausgegeben, sämtliche Guards fallen. Nur lokal, nie in Prod. Siehe ADR 0005. - Approval-pending: Nutzer:innen, die über
/api/auth/registerangelegt sind aber noch nicht von einem Admin via/api/auth/approve-userfreigeschaltet wurden, können sich einloggen, aber keinerequire_auth-Features nutzen (Keycloak verweigert Token-Ausgabe). Siehedocs/how-to/keycloak-setup.md.
Endpoint × Status-Matrix (63 Routes)
Admin-only (5)
Nur Nutzer:innen mit Rolle admin/gwoe-admin erreichen diese:
| Methode | Pfad | Zweck |
|---|---|---|
| POST | /api/batch-analyze |
Batch-Bewertung starten |
| POST | /api/programme/index |
Wahlprogramm indexieren |
| POST | /api/auth/approve-user |
User-Freischaltung |
| GET | /api/auth/pending-users |
Liste offener Freischaltungs-Anträge |
| DELETE | /api/assessment/delete |
Bewertung löschen (für Re-Analyse) |
Authenticated (8)
Jede:r eingeloggte:r Nutzer:in:
| Methode | Pfad | Zweck |
|---|---|---|
| POST | /analyze |
Freitext-Upload bewerten |
| POST | /api/analyze-drucksache |
Antrag aus Landtag bewerten |
| POST | /api/bookmark |
Merklisten-Eintrag toggeln |
| POST | /api/comment |
Kommentar anlegen |
| DELETE | /api/comment/{id} |
Eigenen Kommentar löschen |
| POST | /api/subscriptions |
E-Mail-Abo anlegen |
| DELETE | /api/subscriptions/{id} |
E-Mail-Abo löschen |
| POST | /api/vote |
Antrag-Bewertung votieren |
Optional-User (5)
Funktionieren auch ohne Login, aber personalisieren mit User-Daten wenn eingeloggt:
| Methode | Pfad | Verhalten |
|---|---|---|
| GET | /api/auth/me |
Gibt Auth-Status zurück |
| GET | /api/bookmarks |
Liste eigener Bookmarks (wenn eingeloggt), sonst [] |
| GET | /api/comments?drucksache=X |
Öffentliche + eigene Kommentare |
| GET | /api/subscriptions |
Eigene Abos |
| GET | /api/votes?drucksache=X |
Alle Votes + eigenes Vote-Flag |
Public (45)
Alle Lese-Endpoints und statische Seiten sind offen. Darunter u.a.:
- Seiten:
/,/antrag/{ds},/classic,/auswertungen,/methodik,/quellen,/impressum,/datenschutz,/health,/v2/{merkliste,tags,cluster,neu,batch} - API-Listen:
/api/assessments,/api/assessment,/api/clusters,/api/bundeslaender,/api/programme,/api/search,/api/search-landtag,/api/feed.xml,/api/wahlprogramm-cite - Auswertungen:
/api/auswertungen/{matrix,zeitreihe,themen-matrix,export.csv,export.json} - Auth-Flow:
/api/auth/login,/api/auth/register,/api/auth/callback,/api/auth/login-url,/api/auth/refresh,/unsubscribe/{sub}/{token} - Jobs:
/api/analyze-drucksache-Ergebnisse via/status/{job_id},/result/{job_id},/result/{job_id}/pdf,/api/queue/status
Das heißt: Lesen und Navigieren braucht keinen Account. Erst Aktionen (Merken, Kommentieren, Bewerten, neue Analyse starten) erfordern Login.
UI-Sichtbarkeit — was sieht wer
v2-Frontend (/, /antrag/*, /v2/*)
| UI-Element | Gast | Registriert | Admin |
|---|---|---|---|
| Sidebar-Gruppe „Lesen" (Durchsuchen / Merkliste / Tags / Cluster) | ✓ | ✓ | ✓ |
| Sidebar-Gruppe „Prüfen" (Neuer Antrag / Batch-Analyse) | ✓ Links | ✓ funktional | ✓ funktional |
| Sidebar-Gruppe „Daten" (Auswertungen / Export / Feed) | ✓ | ✓ | ✓ |
| Sidebar-Gruppe „Administration" (Freischaltungen / Queue / Abos) | — | — | ✓ (via {% if is_admin %} in base.html:61) |
| Topbar „Klassische Ansicht" + Theme-Toggle | ✓ | ✓ | ✓ |
/v2/merkliste Bookmark-Liste |
Login-CTA | eigene Liste | eigene Liste |
| Bookmark-Stern auf Antragsdetail | Login-CTA | ✓ | ✓ |
| Kommentar-Form | Login-CTA | ✓ | ✓ |
| Vote-Buttons | Login-CTA | ✓ | ✓ |
| Re-Analyze-Button | — | ✓ (nach Ablauf) | ✓ jederzeit |
| Delete-Assessment-Button | — | — | ✓ |
Classic-Frontend (/classic)
| UI-Element | Gast | Registriert | Admin |
|---|---|---|---|
| Listenansicht + Detail | ✓ | ✓ | ✓ |
| Hamburger → Anmelden/Registrieren | ✓ (öffnet Modal) | — | — |
| Hamburger → Auswertungen / Quellen / Methodik | ✓ | ✓ | ✓ |
| Merkliste-Tab | ✓ (localStorage, gerätegebunden) | ✓ (synced mit Server) | ✓ |
| Kommentare anlegen | Login-CTA | ✓ | ✓ |
| Admin-Tab | — | — | ✓ (Freischaltungen, Queue, Batch) |
Login-/Auth-Flows
Zwei Varianten koexistieren:
Direct Access Grant (Default in v2 + /classic-Modal)
- User klickt „Anmelden" → Modal öffnet
- POST
/api/auth/loginmitusername+password - Server ruft Keycloak
grant_type=passwordgegen Clientgwoe-antragspruefer - Setzt
access_token(HttpOnly-Cookie) +rt(Refresh-Token, Path/api/auth/refresh) - Modal schließt, UI refreshed via
/api/auth/me
Voraussetzung: Keycloak-Client gwoe-antragspruefer hat directAccessGrantsEnabled: true (ist gesetzt seit 2026-04-20).
OIDC Redirect (Fallback)
/api/auth/login-url → Keycloak-Login-Seite → /api/auth/callback → Cookie gesetzt → Redirect auf /.
Wurde mit der Direct-Access-Variante überflüssig, bleibt für Notfall erhalten.
Admin-Rollen definieren
Im Keycloak-Admin:
- Realm
collaboration→ Roles → Rolleadminanlegen (odergwoe-admin) - User → dem jeweiligen Nutzer die Rolle zuweisen
- Code prüft in
auth.py:220:"admin" in roles or "gwoe-admin" in roles
Kein Fein-Granular-Rollen-Modell vorgesehen — admin ist alles-oder-nichts.
Dev-Bypass
In .env: AUTH_ENABLED=false setzt alle Guards auf Bypass. require_auth gibt Dev-Modus-User zurück (sub=anonymous, roles=[]), require_admin gibt roles=["admin"]. Nur für lokale Entwicklung ohne Keycloak-Stack. In Prod immer auf true.
Änderung gegenüber alter Doku
docs/reference/api.md hatte eine stale „Auth"-Spalte mit „Keycloak (geplant)". Diese Doku ersetzt sie inhaltlich — das api.md könnte zusammengelegt oder auf diese Seite verlinken.
Wartungshinweis
Diese Doku wird nicht automatisch generiert. Bei neuen Routes / Guards manuell nachpflegen oder via docs/reference/scan-zugriffsrechte.py (TODO: hat bisher keiner geschrieben) regenerieren.