gwoe-antragspruefer/docs/reference/zugriffsrechte.md
Dotty Dotter 2dec009b5c docs+ops: ADRs 0006/0008, DDD-Bewertung, Zugriffsrechte, Smoke-Test, Cron-Scripts
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>
2026-04-25 20:55:57 +02:00

141 lines
6.6 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.

# 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=false` in .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/register` angelegt sind aber noch nicht von einem Admin via `/api/auth/approve-user` freigeschaltet wurden, können sich einloggen, aber keine `require_auth`-Features nutzen (Keycloak verweigert Token-Ausgabe). Siehe `docs/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)
1. User klickt „Anmelden" → Modal öffnet
2. POST `/api/auth/login` mit `username`+`password`
3. Server ruft Keycloak `grant_type=password` gegen Client `gwoe-antragspruefer`
4. Setzt `access_token` (HttpOnly-Cookie) + `rt` (Refresh-Token, Path `/api/auth/refresh`)
5. 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:
1. Realm `collaboration`**Roles** → Rolle `admin` anlegen (oder `gwoe-admin`)
2. User → dem jeweiligen Nutzer die Rolle zuweisen
3. 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.