Files
talktime/features/PROJ-15-media-cleanup.md
T
patrickandClaude Sonnet 5 509194d3e6 feat(PROJ-15): media cache cleanup for SYSTEM_ADMIN
POST /api/system-admin/media/purge-cache (SYSTEM_ADMIN-only, 10/min
rate limit) plus /system-admin/media page — a date picker (default
30 days back), confirmation dialog, and honest UI copy: this only
clears Synapse's *federated*-media cache, which is nearly empty with
federation disabled. No summary/size-preview endpoint, matching the
tech design's explicit call to not show a number that might be wrong
across Synapse versions.

Backend agent couldn't reach the live Synapse to confirm sync/async
behavior or whether a count comes back (no access to backend/.env in
that sandbox), so it built defensively (number | null). Verified
directly against matrix.perlbach24.de: the call is synchronous (~1.1s)
and does return a real count ({"deleted": 0}). The defensive handling
was unnecessary but harmless (correctly treats 0 as a real count, not
"no data") and stays in as a safety net for other Synapse versions.

Verified end-to-end on talkhub/matrix: purge call returns
{"deleted":0}, audit log gets a proper system_admin.media_cache.purged
entry (organization_id: null), non-admin gets 403, a future cutoff
date is rejected with 400. Test accounts/audit rows cleaned up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0143yYvjesjHndBACoweyK67
2026-09-13 22:17:00 +02:00

7.7 KiB

PROJ-15: Media-Cleanup (System-Admin)

Status: Deployed Created: 2026-09-12

Summary

Manuelles Aufräumen alter/verwaister Medien-Dateien auf Synapse — nachgebaut aus synapse-admin's Media-Verwaltung. Nutzt Synapse Admin API (POST /_synapse/admin/v1/purge_media_cache, DELETE /_synapse/admin/v1/media/<server>/<media_id>). Bewusst nur manueller Trigger (kein Zeitplan), da PROJ-11 aktuell keine Medien-Anhänge unterstützt (P2 laut PRD) — betrifft also v.a. Avatare/Profilbilder und den Media-Cache.

Dependencies

  • Requires: PROJ-13 (SYSTEM_ADMIN-Rolle)
  • Requires: PROJ-9 (Synapse-Integration)

User Stories

  1. Als SYSTEM_ADMIN will ich sehen, wie viel Speicherplatz der Synapse-Media-Store aktuell belegt, um einschätzen zu können ob Aufräumen nötig ist.
  2. Als SYSTEM_ADMIN will ich alten, ungenutzten Media-Cache (remote/federierte Medien, die lokal zwischengespeichert wurden) gezielt löschen können.
  3. Als SYSTEM_ADMIN will ich vor dem Löschen sehen, wie viel dadurch freigegeben würde, bevor ich bestätige.

Acceptance Criteria

  • GET /api/system-admin/media/summary — SYSTEM_ADMIN-only, liefert Media-Store-Größe (falls über Synapse Admin API auslesbar) oder Dateisystem-Statistik vom Synapse-Host
  • POST /api/system-admin/media/purge-cache — Parameter: before (Datum, Standard-Vorschlag: 30 Tage), löst purge_media_cache bei Synapse aus
  • Frontend zeigt vor dem Klick auf "Aufräumen" eine Vorschau/Warnung mit dem gewählten Stichtag, kein automatischer Sofort-Trigger ohne Bestätigungsdialog
  • Ergebnis der Aufräum-Aktion (Anzahl gelöschter Medien, falls von Synapse zurückgegeben) wird angezeigt
  • Aktion wird im Audit-Log vermerkt (action: "system.media_purged", kein organizationId-Bezug möglich — neues optionales Feld oder System-weite Audit-Kategorie klären in Architektur)

Edge Cases

  • Synapse Admin API für Media-Größe nicht verfügbar/nicht dokumentiert für die genutzte Synapse-Version → Fallback: nur Purge-Aktion anbieten, keine Vorab-Größenanzeige, das im UI klar kommunizieren statt falsche Zahlen zu zeigen
  • purge_media_cache betrifft nur den Remote-Media-Cache (von föderierten Servern zwischengespeicherte Bilder), nicht lokal hochgeladene Medien — da Federation komplett deaktiviert ist (siehe PRD-Constraint), ist der praktische Nutzen dieser Aktion aktuell gering. Muss im UI-Text ehrlich kommuniziert werden, damit kein falscher Eindruck entsteht ("räumt alles auf")
  • Sehr kurzes before-Datum (z.B. heute) → Bestätigungsdialog warnt zusätzlich bei ungewöhnlich aggressiven Werten

Non-Goals

  • Löschen einzelner, konkreter Medien-Dateien nach ID (synapse-admin kann das; hier zunächst nur der pauschale Cache-Purge, da für TalkTime ohne Medien-Feature kaum relevant)
  • Automatischer/geplanter Cleanup — nur manueller Trigger im MVP

Notes

Praktischer Nutzen ist aktuell begrenzt, solange PROJ-11 keine Medien-Anhänge hat und Federation aus ist — Feature ist v.a. Vorbereitung für P2 (Medien-Anhänge laut PRD-Roadmap). Architektur-Skill sollte das gegenüber dem Nutzer transparent machen.

Zusatz (2026-09-13): Seit dem Element-Web-Deployment (siehe DEVLOG) können Mitglieder über Element direkt ein Profilbild setzen — das erzeugt tatsächlich lokale Medien-Dateien auf Synapse, unabhängig vom TalkTime-Chat. Der Nutzen dieses Features ist damit etwas höher als ursprünglich angenommen, bleibt aber klein.

Tech Design (Solution Architect)

A) Komponenten-Struktur

System-Admin-Bereich
└── Seite "Medien" (NEU, "/system-admin/media")
    ├── Hinweistext: was diese Aktion tut/nicht tut (siehe Tech-Entscheidungen)
    ├── Datumsauswahl "Medien-Cache älter als …" (Standard: 30 Tage)
    └── "Aufräumen"-Button mit Bestätigungsdialog

Zweite Unterseite im System-Admin-Bereich, gleiches Muster wie die Raum-Übersicht (PROJ-14): eigene Navigation, kein gemeinsamer Screen.

B) Datenfluss (in einfachen Worten)

  1. Admin wählt einen Stichtag (oder übernimmt den Vorschlag "30 Tage").
  2. Backend schickt diesen Stichtag an Synapse mit der Anweisung "räume den Medien-Zwischenspeicher auf, der älter ist als das".
  3. Synapse arbeitet das im Hintergrund ab und meldet zurück, was es getan hat (sofern die genutzte Synapse-Version das mitteilt).
  4. Ergebnis wird dem Admin angezeigt.

Keine neue TalkTime-Datenspeicherung nötig — das ist eine reine "Befehl absetzen"-Aktion ohne eigenen Zustand.

C) Tech-Entscheidungen (Begründung)

  • Ehrliche Erwartungssteuerung statt großzügiger Beschriftung: Die Synapse-Funktion räumt nur den Zwischenspeicher für Medien auf, die von anderen, föderierten Servern stammen — bei TalkTime ist Federation komplett deaktiviert, das betrifft also praktisch nichts. Seit Kurzem können Mitglieder über das separat betriebene Element-Web-Werkzeug eigene Profilbilder hochladen — das sind aber lokale Medien, die von dieser Aktion nicht angefasst werden. Der Button heißt entsprechend nüchtern "Föderations-Medien-Cache aufräumen" statt "Speicherplatz freigeben", um keine falschen Erwartungen zu wecken.
  • Keine Vorab-Größenanzeige: Ob die verwendete Synapse-Version zuverlässig mitteilen kann, wie viel Speicherplatz eine Aktion freigeben würde, ist nicht für jede Version garantiert. Statt möglicherweise falsche Zahlen zu zeigen, wird nur die Aktion selbst angeboten, mit Ergebnis-Rückmeldung danach.
  • Kein Zeitplan, nur Handauslösung: Wie in der Anforderung festgelegt — ein automatischer, unbeaufsichtigter Lösch-Mechanismus für Dateien ist ein größerer Vertrauensschritt als eine manuelle Aktion mit Bestätigungsdialog.

D) Abhängigkeiten (neue Pakete)

Keine — nutzt die bestehende Synapse-Anbindung.

Offene Punkte für den Backend-Skill

Vor der Umsetzung gegen die tatsächlich eingesetzte Synapse-Version prüfen (Lehre aus PROJ-14): ob der Purge-Aufruf synchron oder asynchron antwortet, und ob eine Rückmeldung zur Anzahl/Größe der aufgeräumten Medien überhaupt mitgeliefert wird. Falls nicht, zeigt die Seite nur "Aufräumen angestoßen" statt einer Zahl, die es nicht gibt.

Umsetzung (Backend-Skill, 2026-09-13)

  • POST /api/system-admin/media/purge-cache (SYSTEM_ADMIN-only, Rate-Limit 10/min), Frontend-Seite /system-admin/media. Keine DB-Änderung, keine Migration, keine neuen Pakete.
  • Abweichung von den Acceptance Criteria: GET /api/system-admin/media/summary wurde nicht gebaut — das Tech Design (Abschnitt C, "Keine Vorab-Größenanzeige") verwirft die Größenanzeige bewusst. Das UI kommuniziert das Fehlen explizit.
  • Abweichung: Audit-Action heißt system_admin.media_cache.purged statt system.media_purged (Konsistenz mit dem bestehenden system_admin.*-Namensraum aus PROJ-14). organizationId: null, wie beim Raum-Purge.
  • Offener Punkt aus dem Tech Design — jetzt live geklärt: Direkt gegen matrix.perlbach24.de getestet (Assistant hatte Zugriff, der Backend-Agent nicht): POST /_synapse/admin/v1/purge_media_cache antwortet synchron (~1,1s) und liefert tatsächlich {"deleted": 0} — eine echte Zahl, kein fehlendes Feld. Die defensive number | null-Behandlung im Code war also nicht nötig, ist aber unschädlich (typeof result?.deleted === "number" behandelt 0 korrekt, kein !result?.deleted-Fallstrick) und bleibt als Absicherung für andere Synapse-Versionen drin.

Ende-zu-Ende auf talkhub/matrix verifiziert: Purge-Aufruf liefert {"deleted":0,"before":"…"} (200), Audit-Log-Eintrag system_admin.media_cache.purged mit organization_id: null erscheint korrekt, Non-Admin bekommt 403, ein Stichtag in der Zukunft wird mit 400 abgelehnt. Testdaten aufgeräumt.

Status

Production-ready: JA.