Files
patrickandClaude Sonnet 5 8f6e05481b fix(PROJ-11): address QA BUG-2/3/4, partially mitigate BUG-1
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
2026-09-11 20:21:07 +02:00
..

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.local für Dev, chat.example.org für Prod) — das ist SYNAPSE_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 wie SYNAPSE_DB_PASSWORD
  • registration_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 refused auf 8008: Docker: docker compose logs synapse. Bare-Metal: journalctl -u matrix-synapse -f.
  • Registrierung schlägt fehl: enable_registration: false korrekt? Nutzer nur via register_new_matrix_user oder Admin API anlegen.
  • Postgres-Verbindung schlägt fehl: Docker: host: synapse-db muss dem Compose-Service-Namen entsprechen. Bare-Metal: host: localhost und pg_hba.conf erlaubt lokale Verbindung mit Passwort-Auth.