feat(backend): self-registration for Gemeinde Verantwortliche
New onboarding/ module. A prospective Verantwortliche/r signs in with their
Konfi-Castle-ID (Authentik), looks up a KC by invite code, picks an existing
Gemeinde, and registers:
- GET /api/onboarding/kc/:inviteCode -> KC name + its Gemeinden (public;
the invite code is the shared secret)
- POST /api/onboarding/verantwortliche -> verifies the raw Authentik bearer
token's claims (no local Membership required yet via new
TokenVerificationService.verifyAuthentikClaims), JIT-provisions the local
User, and creates a Membership with status PENDING. Idempotent per
(user, kc, gemeinde).
- GET /api/onboarding/requests?kcId= (LT) list pending
- POST /api/onboarding/requests/:id/approve|reject (LT) approve flips to
ACTIVE, reject deletes.
Schema: Membership gains status (enum MembershipStatus { ACTIVE, PENDING },
default ACTIVE). AuthentikStrategy / TokenVerificationService / TeamAuthService
now load only ACTIVE memberships, so a pending request grants nothing until
approved. Membership create/update/delete flow through the sync log.
Tests: onboarding.service.spec.ts (14 cases); npm test green at 46.
Docs (plan + backend README) updated.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,15 @@ client's host - no separate web server is needed.
|
||||
or a Verantwortliche/r for their own Gemeinde (enforced in `TeamerService`,
|
||||
since `RolesGuard` only scopes by `kcId`). Files/chat read endpoints accept
|
||||
`'team'` tokens too, so Teamer see non-Konfi files and chat.
|
||||
- `onboarding/` — self-registration for Gemeinde Verantwortliche.
|
||||
`GET /onboarding/kc/:inviteCode` (public) returns the KC name + its
|
||||
Gemeinden to pick from. `POST /onboarding/verantwortliche` takes the
|
||||
caller's raw Authentik bearer token (no local `Membership` needed yet),
|
||||
JIT-provisions the local `User` from the token claims, and creates a
|
||||
`Membership` with `status = PENDING`. Leitungsteam reviews via
|
||||
`GET /onboarding/requests?kcId=` and `POST /onboarding/requests/:id/approve`
|
||||
or `.../reject`. Auth strategies only load `ACTIVE` memberships, so a
|
||||
pending request grants nothing until approved.
|
||||
- `wahl/` — Wahl/Workshop administration (Leitungsteam-only), guest
|
||||
Teilnehmer submission, Force-Zuteilung overrides, and `ZuteilungService`:
|
||||
a faithful port of the WP plugin's `kc_run_zuteilung` (force-assignments →
|
||||
@@ -96,7 +105,8 @@ client's host - no separate web server is needed.
|
||||
Leitungsteam roles are global across all KCs).
|
||||
|
||||
All planned backend phases are implemented. `npm test` runs Jest unit tests
|
||||
(`ZuteilungService`, `TeamAuthService`, `TeamerService`; Prisma mocked).
|
||||
Remaining work: the Flutter clients (see repo root README), Authentik
|
||||
provisioning for LT/Verantwortliche, and the first real Prisma migration
|
||||
(`ZuteilungService`, `TeamAuthService`, `TeamerService`, `OnboardingService`;
|
||||
Prisma mocked). Remaining work: the Flutter clients (see repo root README),
|
||||
Authentik JIT provisioning for LT (Verantwortliche already self-provision via
|
||||
`onboarding/`), invite email delivery, and the first real Prisma migration
|
||||
(only `schema.prisma` exists so far).
|
||||
|
||||
Reference in New Issue
Block a user