Add Host Dashboard for event and guest management, accessible at /host.
Backend — new /api/v1/host/* endpoints (RequireHost auth):
- GET /host/event → event name + lock/release state
- POST /host/event/close|open → lock or unlock uploads; SSE broadcast
- POST /host/gallery/release → set release timestamp, enqueue export jobs
- GET /host/users → all guests with upload count & bytes
- POST /host/users/{id}/ban → ban with optional upload-hide choice
- POST /host/users/{id}/unban → lift ban
- PATCH /host/users/{id}/role → promote guest→host or demote host→guest
- DELETE /host/upload/{id} → host-level soft-delete + SSE
- DELETE /host/comment/{id} → host-level soft-delete
Frontend — /host page:
- Event controls: lock/unlock toggle and release-gallery button with status badges
- Guest table: display name, role badge, upload count, storage used
- Ban flow: modal asking whether to keep or hide the user's uploads
- Promote/demote buttons respecting caller role (host can promote guests; admin can demote hosts)
- auth.ts: getRole() decodes JWT payload client-side to gate the route
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- AppConfig, AppError, AppState modules for shared infrastructure
- JWT creation/verification with HS256 (jsonwebtoken crate)
- Session management: SHA-256 token hashing, DB-backed sessions
- Auth middleware: AuthUser, RequireHost, RequireAdmin extractors
- POST /api/v1/join: name-only registration, 4-digit PIN + bcrypt hash
- POST /api/v1/recover: PIN-based recovery with 3-attempt lockout (15 min)
- POST /api/v1/admin/login: bcrypt password verification
- DELETE /api/v1/session: logout (session invalidation)
- Migration 006: user PIN lockout columns (failed_pin_attempts, pin_locked_until)
- Models: Event, User (with role enum), Session with all CRUD methods
Frontend:
- api.ts: typed fetch wrapper with automatic Bearer token injection
- auth.ts: JWT/PIN localStorage management with Svelte store
- /join: name entry form with PIN display modal and copy button
- /recover: name + PIN recovery form with saved PIN pre-fill
- /feed: placeholder gallery page with logout
- Root layout: auth initialization on mount
- Root page: redirect to /join or /feed based on auth state
All responses use German language strings as specified.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>