feat(backend): implement phases 0-6 (auth, kc, wahl, files, chat, sync)

Full NestJS backend for the KC-App platform:
- auth: Authentik OIDC resource-server strategy + guest invite-code JWT
  login, plus TokenVerificationService for the WS handshake path
- kc: Leitungsteam-only KC (event) creation/listing
- wahl: Wahl/Workshop admin, Force-Zuteilung overrides, ZuteilungService
  (port of the WP plugin's kc_run_zuteilung), CSV export
- files: LT-only upload with visibility tiers; list/download filtered by
  caller tier; StorageProvider abstraction (WebDAV/Nextcloud default, S3)
- chat: Gemeinde group / DM / LT-wide / broadcast channels; REST + raw ws
  gateway sharing ChatService access rules
- sync: append-only SyncLogEntry replication log + local<->cloud
  push/pull scheduler, shared-secret guarded
- common: Role enum, @Roles decorator, KC-scoped RolesGuard (LT global)
- serves client/web/ interim static web client under / (API under /api)

Typecheck, nest build and boot test pass; needs real Postgres/Authentik/
Nextcloud to run end to end.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-09 16:23:45 +02:00
co-authored by Claude Sonnet 5
parent 327ce43404
commit 8ec127c0fb
42 changed files with 2648 additions and 78 deletions
+26
View File
@@ -8,3 +8,29 @@ AUTHENTIK_ISSUER_URL="https://authentik.example.org/application/o/kc-app"
GUEST_JWT_SECRET="change-me"
PORT=3000
# File storage: defaults to Nextcloud via WebDAV; set STORAGE_PROVIDER=s3 to
# use an S3-compatible bucket instead (see S3_* vars below).
STORAGE_PROVIDER="webdav"
WEBDAV_URL="https://nextcloud.example.org/remote.php/dav/files/kc-app"
WEBDAV_USERNAME="kc-app"
WEBDAV_PASSWORD="change-me"
# Only used when STORAGE_PROVIDER=s3
S3_BUCKET="kc-app"
S3_REGION="auto"
S3_ENDPOINT=""
S3_FORCE_PATH_STYLE="false"
S3_ACCESS_KEY_ID=""
S3_SECRET_ACCESS_KEY=""
# Unique id for THIS server instance (local on-site vs. cloud); used to tag
# replication log entries and avoid echoing changes back to their origin.
SERVER_ID="change-me-uuid"
# Local/cloud sync: set on the LOCAL (on-site) server to periodically push/
# pull against the cloud instance's API base URL. Leave SYNC_ENABLED=false
# on the cloud server (it only needs to expose /sync/ingest + /sync/export).
SYNC_ENABLED="false"
SYNC_PEER_URL="https://kc-app-cloud.example.org/api"
SYNC_SHARED_SECRET="change-me"