feat: user onboarding flow — first-login profile capture (t-paliad-019)
New users were stuck on the dashboard with a dead-end "Bitte schließen Sie das Onboarding ab" message because nothing created the paliad.users row that all matter-management features depend on. This adds the missing Phase D flow. Backend - UserService.Create: validates display_name / office / role, inserts the paliad.users row with (id, email) from the verified JWT claims (never from the request body — prevents onboarding as someone else). - Admin bootstrap: only the very first paliad.users row may self-assign role='admin'; subsequent requests get ErrAdminBootstrapOnly (403). Guarded by pg_advisory_xact_lock so two concurrent first-logins can't race past the count=0 check under READ COMMITTED. - POST /api/onboarding + GET /onboarding; the page is authenticated but NOT behind the onboarding gate (it's the one page users without a paliad.users row may reach). - gateOnboarded middleware wraps the matter-management pages (Dashboard, Akten, Fristen, Termine, Einstellungen/CalDAV) and 302s to /onboarding when the caller has no paliad.users row. Knowledge-platform pages (Kostenrechner, Glossar, Links, Downloads, Gerichte, Gebührentabellen, Checklisten, Fristenrechner) stay ungated. - auth.VerifiedClaims now carries the email claim; auth.ClaimsFromContext exposes it to handlers. GET /api/me includes the email in the 404 body so the onboarding form can pre-fill the display name from the local-part. Frontend - frontend/src/onboarding.tsx + src/client/onboarding.ts: centred card on the existing .login-card styling. Fields: display_name (required, pre-filled from email local-part), office (dropdown from /api/offices), role (dropdown, default associate), practice_group (optional). - Dashboard client: toggleOnboardingHint now redirects to /onboarding instead of showing the dead-end hint — belt-and-braces behind the server gate in case the DB lookup fell through. - DE + EN i18n keys for every label, placeholder, and error. - Added onboarding to build.ts. Tests: internal/services/user_service_test.go covers the valid path, per-field validation, duplicate (ErrUserAlreadyOnboarded), and the admin-bootstrap gate. Follows the existing TEST_DATABASE_URL skip pattern.
This commit is contained in:
@@ -238,8 +238,17 @@ function renderActivity(items: ActivityEntry[]): void {
|
||||
}
|
||||
|
||||
function toggleOnboardingHint(user: DashboardUser | null): void {
|
||||
// Belt-and-braces: the server-side gate (gateOnboarded in handlers.go)
|
||||
// already redirects users without a paliad.users row to /onboarding before
|
||||
// the dashboard HTML is served. If the gate ever misses (e.g. DB lookup
|
||||
// errored and we fell through), push the user to /onboarding here so they
|
||||
// don't get stuck on a blank dashboard.
|
||||
if (!user) {
|
||||
window.location.href = "/onboarding";
|
||||
return;
|
||||
}
|
||||
const onboarding = document.getElementById("dashboard-onboarding")!;
|
||||
onboarding.style.display = user ? "none" : "block";
|
||||
onboarding.style.display = "none";
|
||||
}
|
||||
|
||||
function setCount(id: string, n: number): void {
|
||||
|
||||
Reference in New Issue
Block a user