# KC-APP Multi-tenant event, election and communication platform for Konfi-Castle events (KCs), replacing the WordPress plugin "Workshop-Wahlen". See [plan-kcAppMultiTenantPlatform.prompt.md](plan-kcAppMultiTenantPlatform.prompt.md) for the full architecture and phased roadmap. ## Structure - `backend/` — NestJS API (Prisma/PostgreSQL, Authentik OIDC as resource server, guest/Konfi local accounts, roles/permissions foundation, file sharing, chat, local/cloud sync). See [backend/README.md](backend/README.md) for setup. Also serves the web client (see below) directly, so it's the single entry point for the web experience. - `client/app/` — the Flutter client (single codebase; **web** target enabled, mobile/desktop can be added later). Login (guest / local Teamer / invite redemption), role-aware home, guest Workshop-Wahl, file list, read-only chat. See [client/app/README.md](client/app/README.md). - `client/web/` — minimal dependency-free HTML/CSS/JS placeholder web client, served by the backend at `/`. Superseded by the Flutter web build; kept for now as a zero-dependency fallback. ## Status Phase 0/1 foundation implemented: monorepo skeleton, Prisma data model (Kc, Gemeinde, User, Membership, GuestAccount, Wahl/Workshop/Teilnehmer/Zuteilung, File, Chat), Authentik JWT resource-server strategy, guest invite-code login, Role-based guard scoped per KC. Phase 2 (Workshop-Wahl engine) implemented: Wahl/Workshop administration, guest Teilnehmer submission, Force-Zuteilung overrides, and the assignment algorithm ported from the WP plugin's `kc_run_zuteilung` (force-assignments → wish rounds 1-3 → random fill → consolidation of underfilled workshops), plus CSV export. Phase 3 (Dateifreigabe) implemented: Leitungsteam-only upload tagged with a visibility tier (alle / alle außer Konfis / nur LT), list/download for Authentik or guest callers filtered by their allowed tiers, storage behind a provider abstraction defaulting to Nextcloud/WebDAV (S3-compatible storage as an alternative via `STORAGE_PROVIDER=s3`). Phase 5 (Kommunikation) implemented: Gemeinde-Gruppenchat, 1:1-DMs, LT- kanalübergreifende Kanäle, Broadcast (read-only für Konfis); channel/history via REST, real-time send/receive via a raw WebSocket gateway authenticated with the same Authentik/guest tokens as the REST API. Phase 6 (Hybrid Lokal/Cloud-Server & Sync) implemented: an append-only replication log (`SyncLogEntry`) captured by every feature service after its writes; the local (on-site) server periodically pushes/pulls against the cloud server's `/sync/ingest` + `/sync/export` endpoints (shared-secret authenticated, not user auth). No conflict resolution needed by design - the local server is the sole source of truth while an event is live. Since then: local (non-Authentik) Gemeinde Teamer accounts + invites (`teamer/`, `auth/team-login`), Gemeinde CRUD (`gemeinde/`), Gemeinde Verantwortliche self-registration with LT approval (`onboarding/`), JIT `User` provisioning on first Authentik login, LEITUNGSTEAM derived from the Authentik `groups` claim, and an email module (`mail/`, log-only by default, SMTP opt-in) that sends personal Teamer invites. First Prisma migration is in (`backend/prisma/migrations/`); the backend has been run end to end against a local PostgreSQL 16. `npm test` covers the assignment algorithm and the new auth/onboarding services (56 tests). Phase 7 (Flutter client) started: `client/app/` is a single Flutter codebase with the **web** target enabled — login (guest / local Teamer / invite redemption), role-aware home, guest Workshop-Wahl, file list, read-only chat. `flutter build web` and `flutter test` pass. Mobile/desktop targets, the Authentik Authorization-Code flow, WebSocket chat send, and LT admin screens are still to come. The backend also serves the interim `client/web/` placeholder at `/` (API under `/api`). Running end to end still needs a real Authentik instance and Nextcloud/S3 credentials (see `backend/.env.example`).