BUG-4 (High, failed acceptance criterion) — per-tile unread badges: new use-team-unread-counts.ts runs one app-level Matrix client (separate from useTeamChat's detail-view client) that syncs every room GET /api/teams now resolves (matrixRoomId added via leftJoin on chat_rooms) and reports unread counts per team. TeamsPage tiles show the badge without the chat tab being open. Side fix: createMatrixClient() now dynamic-imports matrix-js-sdk instead of a static import, so the new always-mounted hook doesn't drag the SDK (and its 7.8MB crypto WASM) back into TeamsPage's main bundle — verified via build output (TeamDetail chunk 853KB -> 27KB, SDK now in its own on-demand chunk). BUG-3 (High) — kick-while-open: use-team-chat.ts now listens for RoomEvent.MyMembership; leaving/removal flips status to a new "removed" state instead of leaving history and the composer usable. BUG-2 (High, partially mitigated) — minted tokens are unscoped Matrix credentials by nature (Matrix has no token scoping). Disabled user_directory search on Synapse (config + live matrix.perlbach24.de instance), verified empty results instead of cross-club user listing. Direct addressing by known Matrix ID is still possible — full tenant isolation needs an explicit decision (one Synapse per club vs. an isolation module on a shared homeserver), documented as an open item in the spec rather than silently declared fixed. BUG-1 (Critical, not fixed) — backend/.env.example is outside my permission sandbox (can't read or write .env* files). Documented the required block in the spec for manual addition; talkhub's real .env already has the values. Verified end-to-end on talkhub/matrix test LXCs. Not addressed in this pass (lower priority per QA): BUG-5/6/7/8/9/10. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0143yYvjesjHndBACoweyK67
Synapse Setup (lokal/Server)
Minimal-Setup für einen Matrix-Synapse-Homeserver als Backend für TalkTime. Installationswege:
- Option A — Docker (empfohlen, einfacher zu warten)
- Option B — Bare-Metal/Proxmox-LXC, per eigenem
install.sh(universell, setzt gleich alle TalkTime-Defaults richtig) oder manuell Schritt für Schritt - Option C — externer Autoinstaller (bashclub/zamba-lxc-toolbox), falls Nginx+Element Web gleich mit dabei sein sollen
Option C: Externer Autoinstaller (bashclub/zamba-lxc-toolbox)
Alternative zu install.sh, wenn zusätzlich Nginx+Element Web (eigenständiger Matrix-Webclient, nicht Teil von TalkTime) gleich mit installiert werden sollen. install-service.sh installiert Synapse (apt-Repo) + PostgreSQL + nginx + Element Web, stellt auf Postgres um, setzt registration_shared_secret, legt per register_new_matrix_user einen Admin-User an, generiert Self-Signed-TLS.
Skript vor Ausführung selbst prüfen (Repo-README/zamba.conf lesen) — nicht ungeprüft als root laufen lassen. Nach Lauf trotzdem SYNAPSE_ADMIN_TOKEN wie in Option B "Admin-Zugang" beschrieben ziehen und in TalkTime eintragen; enable_registration danach auf false setzen, da TalkTime die Benutzeranlage selbst übernimmt.
Für ein schlankeres Setup ohne extra Nginx/Element: install.sh in Option B unten.
Voraussetzungen (beide Varianten)
- Eine Domain oder lokaler Hostname (z. B.
chat.talktime.localfür Dev,chat.example.orgfür Prod) — das istSYNAPSE_SERVER_NAME, später Teil jeder Matrix-ID, danach nicht mehr änderbar ohne Neuaufsetzen - PostgreSQL 13+ (SQLite reicht nur für allerkleinste Tests, nicht produktiv)
Option A: Docker (empfohlen)
Zusätzlich nötig: Docker + Docker Compose
1. Verzeichnis anlegen
mkdir -p synapse/data
2. docker-compose.yml
Liegt bereits als docker-compose.yml in diesem Ordner. Server-Name und DB-Passwort per .env neben der Datei überschreiben (sonst greifen die Defaults chat.talktime.local / changeme):
# synapse/.env (nicht committen)
SYNAPSE_SERVER_NAME=chat.example.org
SYNAPSE_DB_PASSWORD=<starkes-passwort>
SYNAPSE_SERVER_NAME ist der Homeserver-Name — später Teil jeder Matrix-ID (@user:chat.example.org). Danach nicht mehr änderbar, ohne den Server neu aufzusetzen.
3. Konfiguration generieren
cd synapse
docker compose run --rm synapse generate
Erzeugt data/homeserver.yaml und data/*.signing.key.
4. Datenbank umstellen, Registrierung absichern
generate legt standardmäßig SQLite an und lässt offene Registrierung zu. Vorlage homeserver.yaml.sample benutzen:
cp homeserver.yaml.sample data/homeserver.yaml
Danach in data/homeserver.yaml die Platzhalter <...> ersetzen:
server_name/ Pfade zur.signing.key— Name aus Schritt 3 (Standard:chat.talktime.local)database.args.password— dasselbe Passwort wieSYNAPSE_DB_PASSWORDregistration_shared_secret,macaroon_secret_key,form_secret— je ein langer Zufalls-String (openssl rand -hex 32)
Mit enable_registration: false läuft Benutzeranlage ausschließlich über TalkTime → Synapse Admin API (kein Selfservice-Signup).
5. Starten
docker compose up -d
Health-Check:
curl http://localhost:8008/health
6. Admin-Zugang für TalkTime einrichten
Ersten Admin-User anlegen:
docker compose exec synapse register_new_matrix_user \
-c /data/homeserver.yaml http://localhost:8008
Bei der Abfrage "Make admin? [no]" → yes beantworten.
Für die Admin API (die TalkTime nutzt) braucht das Backend keinen Passwort-Login, sondern ein Access Token dieses Admin-Users:
curl -XPOST -d '{"type":"m.login.password","user":"<admin-user>","password":"<passwort>"}' \
"http://localhost:8008/_matrix/client/v3/login"
Das zurückgegebene access_token in backend/.env als SYNAPSE_ADMIN_TOKEN eintragen. Nie committen, nie ins Frontend.
Option B: Bare-Metal (Debian/Ubuntu oder Proxmox-LXC, kein Docker)
Schnellweg: install.sh
Eigener, universeller Installer — macht alle Schritte unten automatisch inklusive TalkTime-Sicherheits-Defaults (Registrierung/Föderation aus, eigene Secrets, Systemd-Service, Admin-User+Token):
sudo ./synapse/install.sh chat.example.org
Läuft identisch in einem Proxmox-LXC (Debian-Template) und auf echtem Bare-Metal — beides ist aus Sicht des Skripts nur ein Debian-Userland mit apt-get. Am Ende gibt es SYNAPSE_BASE_URL/SYNAPSE_ADMIN_TOKEN/SYNAPSE_SERVER_NAME fix und fertig zum Eintragen in backend/.env aus.
Optionale Env-Vars: INSTALL_DIR (default /opt/synapse), DB_PASSWORD, ADMIN_USER, ADMIN_PASSWORD (sonst zufällig generiert), SYNAPSE_PORT (default 8008). Nutzt homeserver.yaml.sample aus diesem Ordner als Vorlage — bei Änderungen an der Vorlage (siehe oben) übernimmt der Installer sie automatisch.
Danach direkt weiter zu "Reverse Proxy + TLS" unten.
Manuell, Schritt für Schritt (falls install.sh nicht passt, z. B. anderer Linux-Flavor)
1. Systempakete + venv
sudo apt update
sudo apt install -y python3-dev python3-pip python3-venv \
libpq-dev build-essential libffi-dev libssl-dev libjpeg-dev libxslt1-dev \
postgresql
sudo -u postgres createuser synapse -P
sudo -u postgres createdb -O synapse synapse -E UTF8 --locale=C --template=template0
-P fragt beim Anlegen nach dem Passwort für den synapse-DB-User.
2. Synapse installieren
sudo mkdir -p /opt/synapse
sudo chown $USER:$USER /opt/synapse
python3 -m venv /opt/synapse/venv
/opt/synapse/venv/bin/pip install --upgrade pip
/opt/synapse/venv/bin/pip install "matrix-synapse[postgres]"
3. Konfiguration generieren
cd /opt/synapse
./venv/bin/python -m synapse.app.homeserver \
--server-name=chat.talktime.local \
--config-path=homeserver.yaml \
--generate-config \
--report-stats=no
Erzeugt homeserver.yaml + Signing-Key im aktuellen Verzeichnis.
4. Datenbank umstellen, Registrierung absichern
Wie Option A, Abschnitt 4 — homeserver.yaml.sample nach /opt/synapse/homeserver.yaml kopieren und Platzhalter ersetzen, nur database.args.host: localhost statt synapse-db.
5. Als systemd-Dienst starten
# /etc/systemd/system/matrix-synapse.service
[Unit]
Description=Matrix Synapse Homeserver
After=network.target postgresql.service
[Service]
Type=simple
User=synapse
WorkingDirectory=/opt/synapse
ExecStart=/opt/synapse/venv/bin/python -m synapse.app.homeserver -c /opt/synapse/homeserver.yaml
Restart=on-failure
[Install]
WantedBy=multi-user.target
sudo useradd -r -d /opt/synapse synapse
sudo chown -R synapse:synapse /opt/synapse
sudo systemctl daemon-reload
sudo systemctl enable --now matrix-synapse
Health-Check:
curl http://localhost:8008/health
6. Admin-Zugang für TalkTime einrichten
/opt/synapse/venv/bin/register_new_matrix_user \
-c /opt/synapse/homeserver.yaml http://localhost:8008
Rest identisch zu Option A, Abschnitt 6 (Access Token per Login-Call holen).
Gemeinsame Schritte (beide Optionen)
TalkTime-Backend verbinden
In backend/.env:
SYNAPSE_BASE_URL=http://localhost:8008
SYNAPSE_ADMIN_TOKEN=<access_token aus Admin-Setup>
Reverse Proxy + TLS (Produktion)
Für Produktivbetrieb Synapse hinter nginx mit TLS terminieren (Port 8008 nicht direkt exponieren). homeserver.yaml.sample deaktiviert Föderation standardmäßig (resources: [client], federation_domain_whitelist: []) — TalkTime betreibt einen privaten Homeserver, kein öffentliches Matrix-Netz-Mitglied:
server {
listen 443 ssl;
server_name chat.example.org;
ssl_certificate /etc/letsencrypt/live/chat.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.org/privkey.pem;
location ~ ^(/_matrix|/_synapse/client) {
proxy_pass http://127.0.0.1:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
client_max_body_size 50M;
}
}
Föderation aktivieren (nur falls mit anderen Matrix-Homeservern föderiert werden soll): in homeserver.yaml resources.names um federation ergänzen und federation_domain_whitelist entfernen, zusätzlich Port 8448 (TLS, gleiches Proxy-Ziel wie oben) freischalten und .well-known/matrix/server unter https://chat.example.org/.well-known/matrix/server mit {"m.server": "chat.example.org:443"} bereitstellen.
Troubleshooting
Connection refusedauf 8008: Docker:docker compose logs synapse. Bare-Metal:journalctl -u matrix-synapse -f.- Registrierung schlägt fehl:
enable_registration: falsekorrekt? Nutzer nur viaregister_new_matrix_useroder Admin API anlegen. - Postgres-Verbindung schlägt fehl: Docker:
host: synapse-dbmuss dem Compose-Service-Namen entsprechen. Bare-Metal:host: localhostundpg_hba.conferlaubt lokale Verbindung mit Passwort-Auth.