MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 8s
5.5 KiB
5.5 KiB
📡 WebSocket & Echtzeit-Synchronisation
MindSift implementiert eine bidirektionale Echtzeit-Synchronisationsschicht auf Basis von WebSockets (internal/ws/hub.go). Sie sorgt dafür, dass Änderungen an Aufgaben, Triage-Karten, Notizen und geteilten Einkaufslisten ohne manuelles Neuladen sofort auf allen geöffneten Geräten und bei allen Kollaborationspartnern sichtbar werden.
🔌 1. Verbindung & Handshake
Verbindungs-Endpunkte
wss://<domain>/api/v1/ws?token=<jwt-token>
wss://<domain>/api/v1/ws/lists/<listId>?token=<jwt-token>
Authentifizierung & Upgrade
- Die Authentifizierung erfolgt über das JWT-Token im Query-Parameter
?token=...oder denAuthorization: Bearer-Header während des HTTP-Upgrade-Requests. - Der Server extrahiert die
userIDund registriert die Verbindung im internenHub. - Der
Upgraderakzeptiert alle Origins (CheckOrigin: return true), um volle Kompatibilität mit Reverse-Proxies (Traefik, Nginx, Caddy, Cloudflare) und Docker-Netzwerken zu gewährleisten.
🏛️ 2. Hub-Architektur & Rooms
Der WebSocket-Hub unterteilt Verbindungen in drei Abstraktionsebenen:
┌─────────────────────────────────────────────────────────────────┐
│ WebSocket Hub │
├─────────────────┬─────────────────────────────┬─────────────────┤
│ allClients │ userRooms │ rooms │
│ (Alle aktiven │ (Pro Benutzer-ID) │ (Pro Liste/ │
│ Verbindungen) │ Cross-Device Sync für │ Space) │
│ │ Tasks, Triage & Workspace │ Geteilte Liste │
└────────┬────────┴──────────────┬──────────────┴────────┬────────┘
▼ ▼ ▼
Presence Stats TASK_CREATED ITEM_TOGGLED
DOC_LOCKED TASK_UPDATED ITEM_CREATED
DOC_UNLOCKED DOC_UPDATED LIST_UPDATED
allClients(Global): Hält jede aktive Client-Verbindung. Ermöglicht Broadcasts systemweiter Ereignisse (z.B. globale Dokument-Sperrungen).userRooms[userID](Benutzer-Räume): Sendet Events an alle Geräte desselben Benutzers (z.B. Desktop und Smartphone). Erzeugt ein Webhook oder Quick Dump auf dem Smartphone einen Eintrag, taucht dieser zeitgleich auf dem Desktop auf.rooms[listID](Kollaborations-Räume): Multiplexing für geteilte Listen. Alle Mitglieder einer Liste empfangen Aktionen (wie Abhaken, Löschen, Umsortieren) in Echtzeit.
📨 3. Nachrichten-Format (Envelope)
Alle WebSocket-Nachrichten werden als JSON mit einheitlicher Hülle übertragen:
{
"event": "ITEM_TOGGLED",
"listId": "lst_12345",
"payload": {
"itemId": "itm_987",
"isCompleted": true,
"completedBy": "usr_sandro",
"completedByName": "Sandro"
},
"timestamp": "2026-10-26T13:30:00Z"
}
🔒 4. Dokument-Sperrsystem (Document Locking)
Um Schreibkonflikte bei Notizen im Workspace zu vermeiden, verwendet MindSift ein serverseitiges Lease-Locking mit Heartbeat:
sequenceDiagram
autonumber
actor UserA as Benutzer A
participant WS as WebSocket Hub
actor UserB as Benutzer B
UserA->>WS: LOCK_DOC (docId: "doc_123")
WS-->>UserA: Lock bestätigt (30s TTL)
WS->>UserB: DOC_LOCKED (docId: "doc_123", lockedBy: "Benutzer A")
Note over UserB: Editor gesperrt (Schreibschutz aktiv)
loop Alle 15 Sekunden
UserA->>WS: HEARTBEAT_DOC (docId: "doc_123")
WS-->>UserA: TTL um 30s verlängert
end
alt Reguläres Schließen
UserA->>WS: UNLOCK_DOC (docId: "doc_123")
WS->>UserB: DOC_UNLOCKED (docId: "doc_123")
Note over UserB: Editor wieder freigegeben
else Verbindungsabbruch / Tab geschlossen
Note over WS: Heartbeat bleibt aus (TTL läuft ab)
WS->>UserB: DOC_UNLOCKED (Automatisch nach Ablauf)
end
Locking-Events
LOCK_DOC(Client ➔ Server): Fordert eine 30-Sekunden-Sperre für ein Dokument an.HEARTBEAT_DOC(Client ➔ Server): Verlängert die Sperre alle 15 Sekunden, solange der Benutzer das Dokument geöffnet hat.UNLOCK_DOC(Client ➔ Server): Gibt die Sperre beim Verlassen des Dokuments frei.DOC_LOCKED(Server ➔ Clients): Informiert andere Benutzer, dass das Dokument schreibgeschützt ist.DOC_UNLOCKED(Server ➔ Clients): Hebt den Schreibschutz auf.
🔄 5. Fallback-Strategie & Reconnect
In strikten Firmennetzwerken oder bei Proxy-Problemen (z.B. fehlende Upgrade-Header bei HTTP/1.1) kann eine WebSocket-Verbindung fehlschlagen:
- Exponentielles Backoff: Das Frontend (
frontend/src/lib/api.ts) versucht automatisch die Wiederverbindung nach 1s, 2s, 4s, 8s, bis maximal 30s. - HTTP-Polling Fallback: Geteilte Listen und Notizen aktivieren im Hintergrund ein periodisches Polling (5s Intervall), falls der WebSocket-Status nicht
CONNECTEDist. - Status-Indikator: Ein dezenter grüner bzw. gelber Indikator oben rechts im Header zeigt dem Benutzer jederzeit den aktuellen Live-Verbindungsstatus an.