Files
talktime/docs/vereinschat/architecture.md
T
patrickandClaude Sonnet 5 5e6ee2c456 feat: build TalkTime MVP backend/frontend, rename from VereinsChat
- Generic org/team/member data model (renamed from club-specific naming)
- Auth, organizations, invitations with mail + Matrix provisioning
- Teams with automatic Matrix room creation, sync-job retry, reconciliation
- Departments, seasons, roles (RBAC with privilege-escalation guard), audit log
- Dashboard, members list, org switcher on the frontend
- Synapse setup docs (Docker + bare-metal) and generalized PRD/architecture docs

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBf3yfnnHzMQ5qhLV2285A
2026-09-11 15:07:47 +02:00

8.3 KiB

Architektur: TalkTime

Voraussetzung: Starter-Kit noch nicht lokal analysiert. Diese Architektur ist die Zielarchitektur gemäß Master-Prompt; Abgleich mit tatsächlichem Starter-Kit-Code steht aus.

1. Grundarchitektur

                    ┌─────────────────────────┐
                    │       TalkTime        │
                    │       Web Frontend       │
                    │  React + TypeScript      │
                    └────────────┬─────────────┘
                                 │ HTTPS
                                 ▼
                    ┌─────────────────────────┐
                    │     TalkTime API      │
                    │  Fastify + TypeScript    │
                    │  Auth / Vereine /        │
                    │  Mitglieder / Mannsch.   │
                    │  Rollen / Gruppen /      │
                    │  Invitations / Synapse   │
                    └──────┬───────────┬───────┘
                           ▼           ▼
                     PostgreSQL     Synapse
                                       │
                                       ▼
                                    Matrix

Prinzip: PostgreSQL hält Vereins-/Verwaltungsdaten und die Zuordnung Vereinsobjekt ↔ Matrix-Objekt. Nachrichteninhalte liegen ausschließlich in Synapse.

2. Kernabstraktion

Verein → Abteilung → Mannschaft → Mitglied → Kommunikationsgruppe → Matrix Room

Diese Kette zieht sich durch Datenmodell, API, Frontend und Sync-Logik.

3. SynapseService (Adapter-Schicht)

Browser darf niemals direkt mit Synapse Admin API sprechen:

Browser → TalkTime Backend → Synapse Admin API

SynapseService kapselt:

  • Benutzer anlegen/suchen/aktivieren/deaktivieren/abrufen
  • Räume erstellen/verwalten
  • Mitglieder zu Räumen hinzufügen/entfernen
  • Health Check

Admin-Token verlässt das Backend nie (nicht in Frontend, Logs, API-Responses, Git).

4. Matrix User Provisioning

Vereinsmitglied → TalkTime Account → Matrix Account

Matrix-ID-Schema: @vorname.nachname:chat.vereinschat.de (Domain pro Deployment konfigurierbar).

Regeln:

  • Namenskonflikt: Suffix mit fortlaufender Nummer (@max.mustermann2:...), Zuordnung bleibt stabil über Lebenszeit des Mitglieds.
  • Matrix-ID wird nach Erstellung nicht mehr geändert, auch nicht bei Namensänderung (Anzeige-Name in Matrix wird aktualisiert, ID bleibt).
  • E-Mail-Änderung: aktualisiert Matrix-Account-Metadaten, nicht die ID.
  • Deaktivierung/Reaktivierung: über Synapse Admin API (deactivate/reactivate), Datensatz in synapse_users bleibt für Referenzintegrität.
  • Löschung: Deaktivierung + DSGVO-konforme Datenminimierung, keine harte Matrix-Account-Löschung (Synapse unterstützt das ohnehin nur eingeschränkt), stattdessen Anonymisierung der Metadaten.

5. Chatgruppen / Räume

Automatische Raumerstellung: 1 Mannschaft → 1 Matrix-Raum (Standard). Zusätzlich Abteilungs- und Vereinsräume optional/automatisch je nach Konfiguration.

Mannschaft erstellt → Matrix Raum erstellen → Trainer hinzufügen → Mitglieder hinzufügen

Entfernen:

Mitglied aus Mannschaft entfernt → TalkTime aktualisieren → Matrix Membership aktualisieren (async Job)

6. Synchronisierung

Asynchrone Sync-Jobs statt synchroner Matrix-Calls im Request-Pfad, um UI nicht zu blockieren und Teilausfälle zu isolieren.

  • Outbox Pattern: Jede Vereinsdaten-Änderung, die Matrix-Seiteneffekte hat, erzeugt einen Eintrag in sync_jobs (Typ, Payload, Status) in derselben DB-Transaktion wie die fachliche Änderung.
  • Worker verarbeitet sync_jobs idempotent, mit Retry (exponential backoff) und Statusfeldern (pending, processing, failed, done).
  • Reconciliation: periodischer Abgleich TalkTime-Soll-Zustand vs. Synapse-Ist-Zustand (Health-Check-Job), meldet Abweichungen ins Audit Log, erlaubt manuellen Resync über Admin-UI.
  • Fachliche Operation (z. B. Mannschaft erstellen) schlägt NICHT komplett fehl, wenn Matrix-Call fehlschlägt — Datensatz wird angelegt, Sync-Job bleibt pending/failed und wird retried bzw. manuell resynct.

7. RBAC

Rollenhierarchie im Code (generisch, siehe PRD Abschnitt 0 für die Sportverein/Firma/NGO-Begriffszuordnung): SYSTEM_ADMIN > ORG_ADMIN > ORG_MANAGER > DEPARTMENT_ADMIN > TEAM_MANAGER > TEAM_LEAD/ASSISTANT_LEAD/SUPERVISOR > MEMBER/GUARDIAN.

Prinzipien:

  • Rollenvergabe nur durch Rolle mit strikt höherem Rang im selben oder übergeordneten Scope.
  • Ein Nutzer kann sich selbst keine höherwertige Rolle zuweisen (serverseitige Prüfung, nicht nur UI).
  • Rollen sind scope-gebunden (Verein/Abteilung/Mannschaft) — Prüfung immer hasRole(user, role, scopeId), nie global außer SYSTEM_ADMIN.

8. Multi-Tenant

Jede Tabelle mit Organisationsbezug trägt organization_id (im Code weiterhin organizationId, Tabellenname organizations — generisch statt clubs, siehe PRD Abschnitt 0). Jede Query wird durch eine zentrale Query-Scoping-Schicht (z. B. Repository-Methode erzwingt WHERE organization_id = :currentOrganizationId) gefiltert — nie durch reine Anwendungslogik im Controller. API-Guards prüfen organization_id aus Session/Token gegen angefragte Ressource (IDOR-Schutz). SYSTEM_ADMIN-Zugriff über explizite, auditierte Ausnahme-Rolle, nicht Standardpfad.

9. Chat-Client-Strategie

Empfehlung (vorläufig, bis UX-Validierung): eigene, schlanke Chat-Oberfläche im TalkTime-Frontend über Matrix Client-Server API (z. B. matrix-js-sdk), kein vollständiger Matrix-Client eingebettet.

Begründung:

  • Eingebetteter Client (z. B. Element Web via iframe) ist schnell integriert, aber UX wirkt "fremd" und schwer an Vereinsstruktur/Terminologie anzupassen.
  • Eigene Oberfläche mit SDK erlaubt, nur Verein-relevante Räume zu zeigen, Vereins-Terminologie zu verwenden, und Matrix komplett zu verstecken (siehe Produktvision).
  • Nachteil: höherer Aufwand, E2EE/Threads/Reaktionen müssen selbst integriert werden — für MVP bewusst nur Basis-Messaging + Bilder/Dateien, Threads/Reaktionen als V1/V2.
  • Alternative "Kombination" (Reactions/Threads via SDK, Media via Matrix Content Repo direkt) für V1 vorgesehen.

Detaillierte Abwägung siehe ADR-007.

10. ADRs

ADR-001 — Matrix als Messaging-Backend Begründung: föderationsfähig, offener Standard, self-hostbar, aktive Entwicklung, E2EE-Unterstützung vorhanden. Alternative (eigenes Chat-Backend) verworfen wegen Aufwand für E2EE/Föderation/Mobile-Clients.

ADR-002 — Synapse Admin API nur Backend-seitig Begründung: Admin-Token darf nie ins Frontend. Alternative (Client ruft Synapse direkt mit User-Token) verworfen, da Vereinslogik (RBAC, Tenant-Scoping) dann nicht zentral durchsetzbar wäre.

ADR-003 — PostgreSQL für Vereinsdaten Begründung: passt zu Starter-Kit (Drizzle ORM), relationales Modell passt zur hierarchischen Vereinsstruktur. Keine Duplikation von Matrix-Nachrichteninhalten in Postgres.

ADR-004 — Multi-Tenant-Architektur (Shared DB, organization_id-Spalte) Begründung: einfacher zu betreiben als DB-pro-Tenant bei erwarteter Vereinsgröße (Hunderte, nicht Zehntausende Mitglieder pro Verein). Alternative (Schema-pro-Tenant) verworfen wegen Migrationsaufwand bei vielen Vereinen.

ADR-005 — Matrix-IDs werden persistent gespeichert und nicht geändert Begründung: Matrix-ID-Änderung ist in Matrix nicht nativ vorgesehen (faktisch neuer Account) und würde Raumhistorie/Mitgliedschaften zerreißen.

ADR-006 — Synchronisierung über asynchrone Jobs (Outbox Pattern) Begründung: entkoppelt Vereinsverwaltung von Synapse-Verfügbarkeit, verhindert inkonsistente Teiltransaktionen zwischen zwei Systemen ohne verteilte Transaktion.

ADR-007 — Chat-Client: eigene Oberfläche mit Matrix Client-Server API Begründung: siehe Abschnitt 9. Re-evaluieren nach MVP-Nutzerfeedback, insbesondere E2EE-Aufwand.

11. Offene Punkte

  • Exakte Synapse-Version und API-Kompatibilität noch zu klären (Referenz: aktuelle offizielle Synapse-/Matrix-Doku zum Zeitpunkt der Implementierung).
  • Starter-Kit-Auth-Mechanismus (Session vs. JWT) noch unbekannt — beeinflusst Abschnitt "Authentifizierung" in PRD.