docs: LT Wahl/Teamer admin + Verantwortlichen self-registration screens

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 10:10:07 +02:00
co-authored by Claude Sonnet 5
parent 2e3e62b896
commit 73ff55643f
2 changed files with 13 additions and 5 deletions
+11 -3
View File
@@ -44,9 +44,17 @@ Teamer login only).
access token refreshed on restart. `GET /auth/me` resolves the role. access token refreshed on restart. `GET /auth/me` resolves the role.
- **Home** (`lib/screens/home_screen.dart`) — identity card + navigation. - **Home** (`lib/screens/home_screen.dart`) — identity card + navigation.
- **Verwaltung** (`lib/screens/admin_screen.dart`, Leitungsteam only) — - **Verwaltung** (`lib/screens/admin_screen.dart`, Leitungsteam only) —
list/create KCs; per KC the Gemeinden (list/create) and pending list/create KCs; per KC:
Verantwortlichen self-registrations (`GET /onboarding/requests`, - Gemeinden (list/create); each opens **Teamer-Verwaltung**
approve / reject). (`teamer_admin_screen.dart`): local Teamer accounts + group-link / email
invites.
- **Workshop-Wahlen** (`wahl_admin_screen.dart`): create Wahlen, add
workshops, run the assignment, view the result table.
- pending Verantwortlichen self-registrations (approve / reject).
- **Als Verantwortliche/r registrieren**
(`verantwortliche_register_screen.dart`) — shown on the home screen to a
logged-in Authentik user without a membership: enter a KC invite code,
pick a Gemeinde, submit; a Leitungsteam member then approves.
- **Workshop-Wahl** (`lib/screens/wahl_screen.dart`, guests) — two tabs: - **Workshop-Wahl** (`lib/screens/wahl_screen.dart`, guests) — two tabs:
*Wünsche* (`GET /wahl/guest/overview`, tap workshops in order, max 3, *Wünsche* (`GET /wahl/guest/overview`, tap workshops in order, max 3,
`POST /wahl/:id/teilnehmer`) and *Ergebnis* (`GET /wahl/guest/results` `POST /wahl/:id/teilnehmer`) and *Ergebnis* (`GET /wahl/guest/results`
+2 -2
View File
@@ -116,7 +116,7 @@ Details, Setup-Anleitung und `.env`-Variablen: [backend/README.md](backend/READM
3b. Flutter-Client (`client/app/`): `flutter analyze` sauber, `flutter build web --release` erfolgreich, `flutter test` grün (Login-Screen-Smoke-Test); CORS-Preflight vom Browser-Origin ok. 3b. Flutter-Client (`client/app/`): `flutter analyze` sauber, `flutter build web --release` erfolgreich, `flutter test` grün (Login-Screen-Smoke-Test); CORS-Preflight vom Browser-Origin ok.
3c. Guest-Ergebnis: `/wahl/guest/results` gegen echtes Postgres in beiden Zuständen geprüft (PENDING nach Einreichung, ASSIGNED nach manuell gesetzter `Zuteilung` → Workshop-Name + Wunschrang). 3c. Guest-Ergebnis: `/wahl/guest/results` gegen echtes Postgres in beiden Zuständen geprüft (PENDING nach Einreichung, ASSIGNED nach manuell gesetzter `Zuteilung` → Workshop-Name + Wunschrang).
3d. WS-Chat: Zwei-Client-E2E gegen echtes Postgres (zwei lokale Teamer im selben `GEMEINDE_GRUPPE`-Kanal, `chat:send` → der andere empfängt `chat:message`). Dabei behoben: `ChatGateway` speicherte den Caller erst nach dem asynchronen Token-Check, wodurch ein sofortiges `chat:join` mit 4001 abgewiesen wurde — jetzt wartet der Handler auf das Caller-Promise. 3d. WS-Chat: Zwei-Client-E2E gegen echtes Postgres (zwei lokale Teamer im selben `GEMEINDE_GRUPPE`-Kanal, `chat:send` → der andere empfängt `chat:message`). Dabei behoben: `ChatGateway` speicherte den Caller erst nach dem asynchronen Token-Check, wodurch ein sofortiges `chat:join` mit 4001 abgewiesen wurde — jetzt wartet der Handler auf das Caller-Promise.
3e. LT-Admin gegen echtes Postgres mit einem `isLeitungsteam`-Account (Team-Token): `POST/GET /api/kc`, `POST /api/gemeinde`, `GET /api/onboarding/requests`, sowie eine PENDING-Verantwortlichen-Anfrage → `approve` Status `ACTIVE`, Liste danach leer. 3e. LT-Admin gegen echtes Postgres mit einem `isLeitungsteam`-Account (Team-Token): `POST/GET /api/kc`, `POST /api/gemeinde`, `GET /api/onboarding/requests` + PENDING-Anfrage → `approve``ACTIVE`; Wahl-Admin (`POST /api/wahl`, `POST /api/wahl/:id/workshops`, `POST .../zuteilung/run`, `GET .../zuteilung`); Teamer-Admin (`POST/GET /api/gemeinde/:id/teamer`, `POST /api/gemeinde/:id/teamer-invites`); `GET /api/onboarding/kc/:code`.
3f. **Echte Authentik verifiziert**: mit einem Password-Grant-Token für ein `KC-APP-LT`-Mitglied (`hermes`) gegen `https://sso.konfi-castle.com``GET /api/auth/me` liefert `isLeitungsteam: true` (JWKS-Prüfung, Trailing-Slash-Issuer, JIT-`User`, `groups`→LT), `POST /api/kc` → 201. Placeholder-E-Mail-Fallback, da `hermes` keine E-Mail hat. `AUTHENTIK_LEITUNGSTEAM_GROUP="KC-APP-LT"`. **Noch offen:** nur der In-Browser-Redirect-Roundtrip (Authentik-Loginseite → Code-Tausch). 3f. **Echte Authentik verifiziert**: mit einem Password-Grant-Token für ein `KC-APP-LT`-Mitglied (`hermes`) gegen `https://sso.konfi-castle.com``GET /api/auth/me` liefert `isLeitungsteam: true` (JWKS-Prüfung, Trailing-Slash-Issuer, JIT-`User`, `groups`→LT), `POST /api/kc` → 201. Placeholder-E-Mail-Fallback, da `hermes` keine E-Mail hat. `AUTHENTIK_LEITUNGSTEAM_GROUP="KC-APP-LT"`. **Noch offen:** nur der In-Browser-Redirect-Roundtrip (Authentik-Loginseite → Code-Tausch).
4. Jest-Unit-Tests (Prisma/Sync/Mail gemockt, `npm test` grün, 56 Tests): 4. Jest-Unit-Tests (Prisma/Sync/Mail gemockt, `npm test` grün, 56 Tests):
- `src/wahl/zuteilung.service.spec.ts`: Force-Vorrang, Wunschrunden-Fallback bei voller Kapazität, Unzugeteilt-Fall, Konsolidierung unterbesetzter Workshops, Sync-Capture-Anzahl. - `src/wahl/zuteilung.service.spec.ts`: Force-Vorrang, Wunschrunden-Fallback bei voller Kapazität, Unzugeteilt-Fall, Konsolidierung unterbesetzter Workshops, Sync-Capture-Anzahl.
@@ -130,7 +130,7 @@ Details, Setup-Anleitung und `.env`-Variablen: [backend/README.md](backend/READM
## 8. Nächste Schritte ## 8. Nächste Schritte
1. Flutter-Client: ✅ Authentik-PKCE-Login-Flow (`oidc.dart`) + LT-Admin-Screens (KC/Gemeinde anlegen, Onboarding-Anfragen freigeben). 🔜 Browser-Roundtrip einmal live testen (Redirect + Testaccount); Teamer-Verwaltungs-Screen (für Verantwortliche/LT: Teamer + Invites), Verantwortlichen-Selbstregistrierungs-Screen, Wahl-Verwaltung für LT, dann Mobile/Desktop-Targets. 1. Flutter-Client: ✅ Authentik-PKCE-Login (`oidc.dart`), LT-Admin (KC/Gemeinde), **Wahl-Verwaltung** (Wahlen/Workshops/Zuteilung ausführen + Ergebnis), **Teamer-Verwaltung** (Konten + Invites), **Verantwortlichen-Selbstregistrierung**. 🔜 Browser-OIDC-Roundtrip einmal live testen (Redirect + Testaccount durchklicken); Wahl schließen/öffnen + Force-Zuteilung im UI; Datei-Upload für LT; dann Mobile/Desktop-Targets.
2. Authentik-Provider so konfigurieren, dass das Access-Token den `groups`-Claim trägt (Scope „groups"), LT-Gruppe = `AUTHENTIK_LEITUNGSTEAM_GROUP`. (Ops/Config, Code ist fertig.) 2. Authentik-Provider so konfigurieren, dass das Access-Token den `groups`-Claim trägt (Scope „groups"), LT-Gruppe = `AUTHENTIK_LEITUNGSTEAM_GROUP`. (Ops/Config, Code ist fertig.)
3. SMTP konfigurieren (`MAIL_PROVIDER=smtp` + `SMTP_*`/`MAIL_FROM`/`APP_BASE_URL`) und Invite-Mail-Templates finalisieren (aktuell Plain-Text); optional Onboarding-Benachrichtigungen an LT. 3. SMTP konfigurieren (`MAIL_PROVIDER=smtp` + `SMTP_*`/`MAIL_FROM`/`APP_BASE_URL`) und Invite-Mail-Templates finalisieren (aktuell Plain-Text); optional Onboarding-Benachrichtigungen an LT.
4. Push-Benachrichtigungen (FCM/APNs) für Chat/Ankündigungen. 4. Push-Benachrichtigungen (FCM/APNs) für Chat/Ankündigungen.