xPulse
🇩🇪 DE

Chat Device – Concept

Status: CONCEPT · Erstellt April 2026 Übergeordnet: TOOL_chat_roadmap.md Verwandt: TOOL_chat_concept-identity.md, TOOL_chat_concept-peer-sync.md Geplant ab: v1.11.0


Warum ein eigenes Konzept?

xPulse Chat ist privacy-by-design und serverless. Trotzdem soll ein User seine Chats auf mehreren Geräten nutzen können – ohne Server, ohne zentrale Autorität. Dieses Konzept legt fest wie Geräte vertrauenswürdig hinzugefügt werden, wie sie sich synchronisieren und wie der User die Kontrolle behält.


Grundprinzip

userId → identifiziert den User – geräteübergreifend stabil
clientId → identifiziert das Gerät – pro Gerät unique
Ein User, mehrere Geräte:
userId: xyz... ← immer gleich
clientId: abc... ← iPhone
clientId: ghi... ← MacBook
clientId: jkl... ← Desktop

Alle Geräte desselben Users teilen dieselbe userId – sie sind gleichwertige Peers untereinander. Kein Master, kein Slave.


Device-Liste

Jeder User hat eine Liste seiner Geräte:

// xpulse_chat_{userId}_devices
[
{
clientId: String, // Geräte-ID – immer angezeigt
name: String|null, // optional – vom User vergeben
founder: Boolean, // erstes Gerät das userId generiert hat
addedAt: Number, // Unix ms – wann hinzugefügt
lastSeen: Number, // Unix ms – letzte bekannte Aktivität
},
...
]

Founder-Gerät

Das erste Gerät das die userId generiert hat ist der Founder.

Founder-Nachfolge:

Founder > 30 Tage inaktiv →
User kann manuell "Gerät existiert nicht mehr" bestätigen
→ ältestes Additional-Gerät rückt nach als neuer Founder
→ alle online Geräte werden informiert
Oder automatisch nach 30 Tagen ohne lastSeen-Update →
Nachfolge wird beim nächsten Connect eines Additional-Geräts angeboten

UI – Profil → Geräte

Meine Geräte
📱 abc-1234 [Founder] [dieses Gerät]
"iPhone Johnny" ✏️
💻 ghi-5678 [zuletzt: heute] [x]
– kein Name – ✏️
🖥️ jkl-9012 [zuletzt: gestern] [x]
"Desktop Work" ✏️
[ + Gerät hinzufügen ]

Login-Screen

Der Login-Screen hat zwei Tabs:

┌─────────────────────────────────────┐
│ xPulse Chat │
│ │
[ Login ] [ Gerät hinzufügen ]
│ ───────── │
│ │
│ Benutzername │
│ ┌─────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────┘ │
│ │
│ Passwort │
│ ┌─────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────┘ │
│ │
[ Anmelden ]
│ │
└─────────────────────────────────────┘

Tab "Gerät hinzufügen" – das neue Gerät ist passiv, wartet auf Code:

┌─────────────────────────────────────┐
│ xPulse Chat │
│ │
│ [ Login ] [ Gerät hinzufügen ] │
│ ───────────────────── │
│ │
Code eingeben │
│ (vom bestehenden Gerät) │
│ │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ │ │ │ │ │ │ │ │
│ └────┘ └────┘ └────┘ └────┘ │
│ │
│ Öffne auf deinem bestehenden │
│ Gerät: Profil → Geräte → │
│ Gerät hinzufügen │
│ │
│ [ Verbinden ] │
│ │
└─────────────────────────────────────┘

Pairing-Flow

Das bestehende Gerät ist aktiv – es generiert den Code und bestätigt. Das neue Gerät ist passiv – es wartet und empfängt.

Bestehendes Gerät (aktiv) Neues Gerät (passiv)
───────────────────────── ────────────────────
Profil → Geräte Tab "Gerät hinzufügen"
"Gerät hinzufügen" → gibt Code ein: 4829
→ generiert Code: 4829 → klickt "Verbinden"
→ zeigt Code an → wartet...
→ wartet auf Verbindung...
←──── WebRTC Handshake ────→
"Neues Gerät möchte → wartet auf
hinzugefügt werden" Bestätigung...
→ User bestätigt ✅
←──── Trust etabliert ────→
→ userId sicher übertragen → empfängt userId
→ Gerät in Device-Liste → generiert eigene clientId
→ userId mit eigenem
Passwort verschlüsseln
→ Erst-Sync startet
→ Passwort setzen

Code-Eigenschaften


Erst-Sync (neues Gerät)

Nach erfolgreichem Pairing bekommt das neue Gerät alle Daten:

1. userId übertragen (E2EE, einmalig)
2. Profil sync → ProfileSyncer
3. Alle Chats sync → ChatSyncer.syncAll()
4. Graveyard sync pro Chat
5. Device-Liste sync
6. Passwort setzen → privateKey lokal verschlüsseln

Der Erst-Sync läuft über den DeviceSyncer:

xpulse-chat/src/syncer/device/
DeviceProvider.js
DeviceReceiver.js
DeviceConverter.js
DeviceComparator.js
DeviceSyncer.js

Laufender Sync (nach Erst-Sync)

Nach dem Erst-Sync verhält sich das neue Gerät wie jeder andere Peer:

Johnny schreibt auf iPhone →
Online Peers empfangen sofort
Offline Peers (MacBook) → sync beim nächsten Connect

Gerät entfernen

Profil → Geräte → [x] MacBook →
MacBook aus lokaler Device-Liste entfernen
sync:device:removean alle online Geräte
MacBook beim nächsten Connect informiert:
"Dieses Gerät wurde entfernt"
→ MacBook: alle lokalen Daten löschen – sauberer Schnitt

Keine Rückfrage, kein "behalten" – Privacy first. Entferntes Gerät löscht vollständig alle lokalen Daten beim nächsten Connect.


Erst-Sync Sperrbildschirm

Nach erfolgreichem Pairing startet der Erst-Sync. Das neue Gerät zeigt einen Sperrbildschirm – analog zu GLOBAL_adr-015-migration-strategy.md:

┌─────────────────────────────────────┐
│ │
│ Erste Datenübertragung
│ │
│ Deine Chats werden übertragen.
Dieser Vorgang ist einmalig.
│ │
│ ⚠️ Browser nicht schließen
│ │
│ [████░░░░░░░░] 40% │
│ │
└─────────────────────────────────────┘

Bei Unterbrechung (Browser-Close, Stromausfall): → Beim nächsten Start Erst-Sync fortsetzen → ADR-015 Prinzip: Backup + Validation + Atomic Switch


Maximale Geräte

Max. 5 Geräte pro User – erweiterbar wenn Bedarf entsteht.


Sicherheit

Was der Peer sieht

Peer sieht: userId → wer du bist
Peer sieht NICHT: clientId → welches Gerät
Anzahl Geräte → intern
privateKeys → niemals

Nach außen immer nur userId – wie viele Geräte dahinter stecken bleibt vollständig intern. Auch wenn ein User auf zwei Geräten gleichzeitig online ist, sieht der Peer nur eine userId.

→ Details zu Verschlüsselung und Signing: TOOL_chat_concept-crypto.md

de/concept/device.md 2026-04-17