GET /api/system-admin/rooms and DELETE /api/system-admin/rooms/:roomId, both gated on requireSystemAdmin from PROJ-13. No new DB table — reads Synapse's room list directly, cross-references the existing chat_rooms table for org/team attribution via one inArray join. deleteRoom() uses the v2 async purge endpoint (not v1, which blocks until the purge finishes and would time out on a large room). normalizeCreationTs() handles Synapse versions that return seconds instead of documented milliseconds — moot on this deployment's Synapse version, which omits creation_ts from the rooms list entirely; verified live, code already treats a missing value as null rather than guessing. Known gap: audit_logs.organization_id is NOT NULL, so deleting an unassigned room can't get a proper audit entry (falls back to a server log warning). Flagged rather than silently worked around. Verified end-to-end on talkhub/matrix: 403 without the SYSTEM_ADMIN flag, 200 with it, and used the new delete endpoint to clean up a genuinely orphaned test room left over from earlier QA. Frontend (/system-admin route, rooms table, delete dialog) still outstanding — the nav button added in PROJ-13 stays a dead link until that lands. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0143yYvjesjHndBACoweyK67
6.1 KiB
PROJ-14: Synapse Raum-Übersicht (System-Admin)
Status: In Progress Created: 2026-09-12
Implementation Notes (Backend, 2026-09-12)
Backend umgesetzt, Frontend-Seite (/system-admin Route + Tabelle + Lösch-Dialog) steht noch aus.
backend/src/services/synapse.ts:listRooms()(GET /_synapse/admin/v1/rooms,from/limit/search_termdurchgereicht),deleteRoom()(v2 async Delete mitpurge: true— v1 blockiert bei großen Räumen bis zum HTTP-Timeout),normalizeCreationTs()(Synapse liefert je nach Version Sekunden statt Millisekunden).backend/src/routes/system-admin.ts(neu, inserver.tsregistriert):GET /api/system-admin/rooms+DELETE /api/system-admin/rooms/:roomId, beidepreHandler: [app.authenticate, requireSystemAdmin].- Keine neue Tabelle, keine Migration:
chat_rooms.matrix_room_idist bereitsunique(Index vorhanden), Zuordnung via eineminArray-JOIN gegenorganizations/teams(kein N+1). - Abweichung/Einschränkung:
audit_logs.organization_idist NOT NULL — das Löschen eines nicht zugeordneten Raums kann daher nicht ins Audit-Log, nur ins Server-Log (app.log.warn). Zugeordnete Räume werden regulär alssystem_admin.room.deletedauditiert. - Edge Cases: Synapse nicht erreichbar → 502 mit Fehlertext (nie leere Liste); Raum bereits gelöscht (404 von Synapse) → lokale Zuordnung wird trotzdem aufgeräumt, dann 404.
Summary
Liste aller Matrix-Räume auf der angebundenen Synapse-Instanz für SYSTEM_ADMIN, unabhängig von TalkTime-Team-/Vereinszuordnung — nachgebaut aus synapse-admin's Raum-Übersicht. Nutzt Synapse Admin API (GET /_synapse/admin/v1/rooms), keine neue TalkTime-Datenbanktabelle nötig.
Dependencies
- Requires: PROJ-13 (SYSTEM_ADMIN-Rolle) — Zugriffsschutz
- Requires: PROJ-9 (Synapse-Integration) — nutzt bestehenden
services/synapse.ts-Wrapper
User Stories
- Als SYSTEM_ADMIN will ich alle Matrix-Räume sehen (Name, Mitgliederzahl, Erstellungsdatum), um einen Überblick über die Gesamtnutzung zu haben.
- Als SYSTEM_ADMIN will ich erkennen, welcher Raum zu welchem TalkTime-Team/Verein gehört (Abgleich mit
chat_rooms-Tabelle), um Zuordnung nachvollziehen zu können. - Als SYSTEM_ADMIN will ich einen verwaisten Raum (keine TalkTime-Zuordnung mehr, z.B. nach Datenbereinigung) direkt löschen/purgen können.
Acceptance Criteria
GET /api/system-admin/rooms— SYSTEM_ADMIN-only, ruft_synapse/admin/v1/roomsab, reichert um TalkTime-Zuordnung an (JOIN gegen lokalechat_rooms-Tabelle übermatrix_room_id)- Frontend-Tabelle: Raumname, Mitgliederzahl, TalkTime-Zuordnung (Vereinsname + Team, oder "nicht zugeordnet"), Erstellungsdatum
DELETE /api/system-admin/rooms/:roomId— purged den Raum bei Synapse; falls inchat_roomsverzeichnet, wird der lokale Eintrag ebenfalls gelöscht (kaskadiert nicht automatisch, da externe ID)- Bestätigungsdialog vor dem Löschen (destruktive Aktion, analog Mitglied-Löschen aus PROJ-3)
- Pagination (Synapse Admin API liefert selbst paginiert,
from/limit-Parameter durchreichen)
Edge Cases
- Raum ist ein aktiver Team-Raum (in
chat_roomsverzeichnet, Team existiert noch) → Löschen weiterhin technisch möglich, aber Warnhinweis im Dialog ("Dieser Raum ist aktiv einem Team zugeordnet — Team-Chat wird dadurch zerstört") - Synapse nicht erreichbar → Fehleranzeige, keine leere Liste vortäuschen
- Sehr viele Räume (>1000) → Pagination zwingend, nicht alles auf einmal laden
- Raum bereits gelöscht (Race Condition, zwei Admins gleichzeitig) → Synapse liefert Fehler, Frontend zeigt generische Fehlermeldung statt Absturz
Non-Goals
- Raum-Inhalte einsehen (Nachrichten lesen) — reine Metadaten-Übersicht, kein Nachrichten-Zugriff für Admin
- Raum-Einstellungen ändern (Name, History-Visibility) über dieses Panel — nur Übersicht + Löschen
Tech Design (Solution Architect)
A) Komponenten-Struktur
System-Admin-Bereich (NEU, "/system-admin")
└── Seite "Räume"
├── Tabelle: Raumname | Mitglieder | Zuordnung (Verein/Team oder "nicht zugeordnet") | Erstellt am | Aktion
├── "Weiter"/"Zurück"-Paginierung (analog Mitgliederliste aus PROJ-3)
└── Löschen-Bestätigungsdialog (analog Mitglied-Löschen aus PROJ-3)
Erste Unterseite im neuen System-Admin-Bereich — die Navigation dorthin (aktuell ein Button, der ins Leere zeigt, siehe PROJ-13) bekommt jetzt ein echtes Ziel.
B) Datenfluss (in einfachen Worten)
Es wird keine neue Tabelle in der TalkTime-Datenbank angelegt. Der Ablauf:
- Backend fragt Synapse nach der Liste aller Räume (Name, Mitgliederzahl, Erstellungsdatum) — das ist reine Server-Information, die Synapse selbst schon führt.
- Backend gleicht diese Liste gegen die bereits vorhandene TalkTime-Tabelle ab, in der steht, welcher Matrix-Raum zu welchem Team/Verein gehört (dieselbe Tabelle, die auch der Chat aus PROJ-11 nutzt).
- Ergebnis: eine kombinierte Liste, die sowohl "reine Synapse-Info" als auch "TalkTime-Zuordnung, falls vorhanden" zeigt.
- Löschen eines Raums geht direkt an Synapse; falls der Raum in der TalkTime-Zuordnung stand, wird dieser Eintrag ebenfalls entfernt, damit keine verwaiste Zuordnung auf einen nicht mehr existierenden Raum zurückbleibt.
C) Tech-Entscheidungen (Begründung)
- Keine eigene Datenspeicherung der Raumliste: Synapse ist bereits die "Quelle der Wahrheit" für Räume — eine Kopie in TalkTime pflegen hieße, zwei Datenstände synchron halten zu müssen, ohne echten Nutzen.
- Zugriffsschutz über die in PROJ-13 gebaute Prüfung: Kein neuer Berechtigungsmechanismus, konsistent mit allen anderen System-Admin-Funktionen.
- Löschen bricht Chat für aktive Teams bewusst nicht automatisch ab: Ein Löschen-Button, der aktive Team-Chats stillschweigend verschont, wäre für einen Admin verwirrend ("warum lässt sich das nicht löschen?"). Stattdessen: löschen ist möglich, aber mit deutlicher Warnung vorher.
D) Abhängigkeiten (neue Pakete)
Keine — nutzt die bestehende Synapse-Anbindung aus PROJ-9/PROJ-11.
Offene Voraussetzung
Erfordert PROJ-13 (Berechtigungsprüfung) als Grundlage — bereits umgesetzt.