9.7 KiB
9.7 KiB
Team-Chat: v1-Produkt- und UX-Vertrag
Stand: 2026-07-15
Ticket: AK-P15b / HIVEGRID-45
Architektur: Bespoke WebSocket-Chat nach AD-9, kein Hocuspocus
Dieses Dokument konkretisiert die bereits beauftragten Chat-Funktionen als belastbaren Produktvertrag. Es trennt notwendige Ausführungsqualität von späteren Erweiterungen und verhindert, dass die Interim-UI einen technisch vollständigen, aber im Alltag hakeligen Chat verdeckt.
1. Produktprinzipien
- Sofort reagieren, serverseitig entscheiden. Senden, Reactions und Pins erscheinen optimistisch. Die Datenbank bleibt autoritativ; Fehler bleiben am betroffenen Element sichtbar und können dort erneut versucht werden.
- Kein Verlust und keine Duplikate. Jeder Schreibvorgang besitzt vor dem ersten Versuch eine stabile Client-ID. Wiederholungen mit derselben ID liefern dasselbe Resultat.
- Realtime ist ein Beschleuniger, nicht die Datenbank. Redis verteilt Events; nach Reconnect werden Lücken per Cursor aus PostgreSQL geschlossen.
- Ruhe beim Lesen. Neue Nachrichten reißen Nutzer nicht ans Listenende. Wer hochgescrollt hat, sieht einen Hinweis mit Anzahl und Sprungaktion.
- Mobile und Tastatur sind Primärpfade. Alle Aktionen funktionieren per Touch, Tastatur und Screenreader.
2. Nachrichten- und Reconnect-Vertrag
Optimistisches Senden
- UI-Zustände:
sending → sentodersending → failed. Einen erfundenen gerätebezogenendelivered-Zustand gibt es in v1 nicht. clientMessageIdwird vor dem ersten Versuch erzeugt und bei Retry wiederverwendet. Der Server hält(tenantId, authorUserId, clientMessageId)eindeutig und antwortet bei Wiederholung mit derselben Nachricht.- Die Local-Echo-Nachricht erscheint sofort mit dezentem Sendestatus. Server-Antwort und WebSocket-Echo werden gegen die Client-ID abgeglichen und dürfen weder doppelte Zeilen noch doppelte Reaktionen erzeugen.
- Fehler entfernen den Text nicht. Direkt an der Nachricht stehen „Erneut versuchen" und „Verwerfen"; kein
Toast-Spam. Automatischer Retry gilt nur für Timeout,
429mitRetry-Afterund5xx, mit Backoff und Jitter. - Innerhalb eines Channels/Threads bleibt die Reihenfolge stabil; unabhängige Channels dürfen parallel senden.
Verbindung und Gap-Fill
- Sichtbare Zustände:
connecting,online,reconnecting,offline,blocked. - Nach Reconnect sendet der Client den letzten bestätigten Cursor und erhält verpasste persistente Events in stabiler Reihenfolge. Erst danach gilt die Verbindung als vollständig synchronisiert.
- Presence, Typing und Transportstatus sind flüchtig und werden nicht als Chat-Historie gespeichert.
- Queue-Grenzen und
WebSocket.bufferedAmountwerden überwacht, weil der klassische Browser-WebSocket keine Backpressure bereitstellt. - Vollständiges Offline-Senden über Reload oder Background Sync ist nicht Teil von v1. Entwürfe bleiben lokal erhalten; ein offline ausgelöster Send bleibt sichtbar fehlgeschlagen und kann nach Reconnect wiederholt werden.
3. Lesen, Scrollen und Entwürfe
- History wird cursorbasiert paginiert. Beim Nachladen älterer Nachrichten bleibt der visuelle Scroll-Anker stabil.
- Automatisches Scrollen ans Ende erfolgt nur, wenn der Nutzer bereits am Ende ist oder selbst sendet. Sonst erscheint „N neue Nachrichten".
- Read-Cursor sind monoton. Eine Nachricht wird nur als gelesen gewertet, wenn Channel und Dokument aktiv sind und die Nachricht sichtbar war; Updates werden gebündelt. Eigene Nachrichten erzeugen kein Unread.
- Channel zeigen getrennt Gesamt-Unread und Mention-Marker. Mute unterdrückt Benachrichtigungen, aber niemals
Unread; direkte User-Mentions und DMs umgehen Mute gemäß aktivem Chat-Vertrag (
AK-P15b). - Der Composer speichert Textentwürfe debounced pro
Tenant + User + Channellokal und tenant-isoliert. Ein Entwurf wird erst nach erfolgreichem Server-Ack gelöscht. Datei-Binaries landen nicht im Local Storage.
4. Composer und Nachrichten-QoL
Entersendet,Shift+Entererzeugt eine neue Zeile. Während IME-Composition darfEnternicht senden.- Markdown bleibt auf den freigegebenen Umfang beschränkt und wird serverseitig sanitisiert.
- Eigene Nachrichten können innerhalb von 24 Stunden editiert werden; Änderungen tragen einen „bearbeitet"-Marker. Löschen erzeugt einen Tombstone, damit Threads und Antworten verständlich bleiben.
- Hover-Aktionen sind identisch per Fokus und Mobile-Long-Press erreichbar: Reaktion, Thread, Bearbeiten, Löschen, Pin und Als-Aufgabe-markieren gemäß Berechtigung.
- Mentions verwenden eine zugängliche Combobox mit Pfeiltasten,
EnterundEscape. Autocomplete und Benachrichtigung zeigen beziehungsweise adressieren nur Nutzer, die den Channel lesen dürfen. - Reactions werden optimistisch gesetzt und bei Fehler zurückgerollt. Gleiche Reaktion eines Users auf dieselbe Nachricht ist eindeutig.
- Voice Notes sind einfache Audio-Anhänge mit Aufnahme-/Upload-Fortschritt, Dauer, Abspielen, Abbrechen und Retry. Es gibt kein Transkript und keine KI-Verarbeitung.
- Uploads nutzen die bestehende Files-Pipeline inklusive AV-Prüfung. Bilder unterstützen Vorschau und verständlichen Alternativtext; Mobile bietet den direkten Kamera-Input.
5. Presence, Typing, Threads und Pins
- Typing startet erst nach echter Eingabe, wird gedrosselt, läuft nach kurzer TTL aus und endet bei Senden, Leeren, Channelwechsel oder Disconnect. Die UI zeigt höchstens zwei Namen plus „N weitere".
- Presence wird aus aktiven Sessions abgeleitet und läuft über TTL aus; sie ist kein belastbarer Arbeitszeitnachweis.
- Threads haben genau eine Ebene. Desktop nutzt ein Seitenpanel, Mobile eine eigene Detailansicht. Wer erstellt, antwortet oder erwähnt wird, folgt dem Thread automatisch.
- Message-Pins sind in Group- und Projekt-Channels auf 50 begrenzt. Nach bestätigtem Produktentscheid gibt es in DMs keine Message-Pins. Der persönliche Channel-Pin bleibt ein getrenntes Modell.
6. Benachrichtigungen und bestätigte v1-Grenzen
- Mentions, DMs und Thread-Antworten laufen über
notify()und öffnen per Deep Link die exakte Nachricht. - Der allgemeine Browser-Web-Push inklusive Permission-Prompt bleibt bei
VA-P27a; Chat-v1 liefert In-App- Notifications und Deep Links. - Tenant-Admin-Audit liegt unter
/settings/chat/audit. Eine kurzlebige Audit-Session verlangt einen Grund; jeder fremde Lesezugriff wird auditiert und DMs zeigen den Audit-Banner. FileEntityTypewird minimal umchat_messageerweitert, damit Anhänge die bestehendeFileEntityLink- Pipeline nutzen und kein paralleles Datei-System entsteht.
7. Accessibility und Mobile
- Die Nachrichtenliste ist ein benanntes
role="log"ohne pauschales Live-Announcement. Separate, dosiertearia-live="polite"-Statusbereiche melden nur neue fremde Nachrichten; initial geladene Historie und eigene Local Echoes werden nicht doppelt angesagt. - Verbindungs- und Sendestatus verwenden einen separaten Statusbereich und nie nur Farbe.
- Fokus bleibt nach Send im Composer; Drawer/Dialog geben Fokus kontrolliert zurück. Channel-, Message- und Picker-Listen sind vollständig per Tastatur bedienbar.
- Mobile verwendet Master/Detail-Navigation, mindestens 44 Pixel große Touch-Ziele, Safe-Area am sticky Composer und behält Draft sowie Scrollposition beim Channelwechsel.
8. Wiederverwendung des HiveGrid-UI-Baukastens
| Fläche | Vorhandene Bausteine | Neuer chat-spezifischer Verbund |
|---|---|---|
| Shell | SubframeAppShell, PageShell, SidebarInside, ResizablePanel |
ChatWorkspace |
| Channel-Liste | SearchInput, Avatar, BadgeFeedback, DropdownMenu, ContextMenu, Tooltip |
ChatChannelRow |
| Verlauf | Avatar, Button, IconButton, ContextMenu, ScrollArea, Skeleton |
ChatMessageList, ChatMessageRow |
| Composer | TextArea, IconButton, Progress, BannerOffline |
ChatComposer, ChatAttachmentTray |
| Threads | Drawer, Dialog, Accordion |
ThreadDrawer |
| Mentions/Suche | SearchInput, Command, Avatar |
MentionAutocomplete, ChatSearchResults |
| States | EmptyState, Alert, BannerOffline, Skeleton, LoadingIndicatorSkeleton |
nur Chat-Kompositionen |
| Medien | uploadFileInChunks, AudioOrVideoPlayer, Progress |
Voice-Note- und Attachment-Steuerung |
Die bestehenden visuellen Primitives werden direkt genutzt. Nicht wiederverwendet werden die rein visuellen,
nicht interaktiven FileUpload-/Combobox-Attrappen und der für Chat zu schwere Legacy-Rich-Text-Editor.
9. Bewusst später
- persistente Offline-Outbox und Background Sync über Reload
- Scheduled Messages, Erinnerungen und „Für später speichern"
- gerätebezogener
delivered-Status und Read-Receipt-Privacy-Schalter - Slack-Power-Shortcuts, frei konfigurierbares Sendeverhalten und Pop-out-Threads
- server-/geräteübergreifend synchronisierte Drafts
- GIF-/Sticker-Apps, Huddles, Audio-/Videoanrufe und KI-Transkription