Files
leocrm/docs/konzept-unified-messaging.md
T
Agent Zero cc3ac9a43d feat: Unified Messaging System — kommunikation plugin, AI/Proactive/System participants, MessageSidebar, Rich Content Renderer
Phase 1: Backend plugin kommunikation (13 files, 10 tables, REST API, WebSocket, RBAC, DMS Bridge, Participant Registry, Mini-App Registry, Search Provider)
Phase 2: AI plugins as participants (ai_assistant + ai_proactive dock as participants, heartbeat job)
Phase 3: system_notif plugin (system events → chat messages, pinned System room)
Phase 4: Frontend MessageSidebar (replaces AISidebar, same design, comm API client, WebSocket hook, commStore)
Phase 5: Rich Content Block Renderer (11 components: Markdown, HTML, Image, Audio, Video, File, ActionCard, ContactCard, MiniApp, BlockRenderer)
BasePlugin: added services property + _container in on_activate
2026-07-22 01:22:15 +02:00

625 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Konzept: Unified Messaging System für LeoCRM
## Vision
Alle Kommunikation in LeoCRM — KI-Chat, Mitarbeiter-Chat, System-Benachrichtigungen, externe Messenger — läuft über **ein einheitliches Messaging-System**, das als Plugin-Architektur realisiert wird.
**Kernprinzip:** Alles ist ein Teilnehmer. Die KI ist ein Teilnehmer. Das System ist ein Teilnehmer. Ein WhatsApp-Gateway ist ein Teilnehmer. Es gibt keine Sonderbehandlung.
---
## Plugin-Architektur
### Übersicht: Drei Plugin-Ebenen
```
┌─────────────────────────────────────────────────────────────┐
│ Frontend (MessageSidebar) │
│ Ein Feed, eine Konversations-Liste, ein Eingabefeld │
└──────────────────────────┬──────────────────────────────────┘
│ │ WebSocket │
┌──────────────────────────┴──────────────────────────────────┐
│ Plugin: kommunikation (Core) │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ conversations│ │ messages │ │ participants │ │
│ │ + Räume │ │ + Rich Cont.│ │ + Registrierung │ │
│ └─────────────┘ └──────────────┘ └────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Participant Registry (Hook) │ │
│ │ Andockpunkt für: ai_assistant, system_notif, │ │
│ │ whatsapp_gateway, telegram_gateway, ... │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────┘
│ │ EventBus │
┌──────────────────────────┴──────────────────────────────────┐
│ Plugin: ai_assistant │ Plugin: system_notif │ Plugin: │
│ dockt als Teilnehmer an │ dockt als Teilnehmer │ whatsapp │
│ @KI → AI-Response │ Events → Messages │ Gateway │
└─────────────────────────────────────────────────────────────┘
```
### 1. Plugin `kommunikation` (Core-Plugin)
**Verantwortung:** Chat-Infrastruktur — Konversationen, Nachrichten, Teilnehmer-Verwaltung, WebSocket, Rich Content Transport.
**Basiert auf:** AI Assistant Plugin (Sessions/Messages/Streaming) als Grundlage, erweitert um Multi-Teilnehmer und Rich Content.
**Manifest:**
```python
PluginManifest(
name="kommunikation",
version="1.0.0",
display_name="Kommunikation",
description="Unified Messaging: Chat, KI, System, Messenger",
dependencies=[],
routes=[
PluginRouteDef(path="/api/v1/comm", module="...routes", router_attr="router"),
],
events=["message.received", "conversation.created", "participant.joined"],
migrations=["0001_initial.sql"],
permissions=["comm:read", "comm:write", "comm:manage"],
is_core=True,
)
```
**Komponenten:**
- `models.py` — Conversation, Message, Participant, MessageAttachment, MessageReaction
- `schemas.py` — Pydantic-Schemas für API
- `routes.py` — REST-API + WebSocket
- `services.py` — Business Logic (Nachrichten senden, Konversationen verwalten)
- `participant_registry.py` — Registrierungs-Interface für andere Plugins
- `content_types.py` — Rich Content Type-Definitionen
- `websocket_manager.py` — WebSocket-Verbindungs-Manager
### 2. Participant Registry (Andockpunkt)
Das `kommunikation` Plugin stellt eine **Participant Registry** bereit — ein Interface, über das sich andere Plugins als Teilnehmer registrieren.
```python
# In kommunikation/participant_registry.py
class ParticipantType(Enum):
USER = "user"
AI = "ai"
SYSTEM = "system"
WHATSAPP = "whatsapp"
TELEGRAM = "telegram"
EMAIL = "email"
SLACK = "slack"
# Erweiterbar...
class ParticipantHandler(ABC):
"""Interface das Plugins implementieren um als Teilnehmer zu fungieren."""
@abstractmethod
async def on_message_received(self, conversation_id, message, context) -> Message | None:
"""Wird aufgerufen wenn eine neue Nachricht in einer Konversation
ankommt, an der dieser Teilnehmer beteiligt ist.
Rückgabe: Optional eine neue Message (z.B. AI-Response).
Für reine Leser (system) → return None.
Für reaktive Teilnehmer (ai) → return Message(...).
"""
pass
@abstractmethod
def get_participant_info(self) -> dict:
"""Metadaten: name, avatar_url, display_name, capabilities."""
pass
class ParticipantRegistry:
"""Global registry für Plugin-Teilnehmer."""
def register(self, participant_type: str, handler: ParticipantHandler) -> None:
"""Plugin registriert sich als Teilnehmer-Typ."""
def get_handler(self, participant_type: str) -> ParticipantHandler | None:
"""Handler für einen Teilnehmer-Typ abrufen."""
```
**Wie Plugins andocken:**
```python
# In ai_assistant/plugin.py on_activate():
from app.plugins.builtins.kommunikation.participant_registry import get_registry
class AIAssistantPlugin(BasePlugin):
async def on_activate(self, db, container, event_bus):
await super().on_activate(db, container, event_bus)
# Als AI-Teilnehmer registrieren
registry = get_registry()
registry.register("ai", AIParticipantHandler(self.services))
```
```python
# In system_notif/plugin.py on_activate():
class SystemNotificationPlugin(BasePlugin):
async def on_activate(self, db, container, event_bus):
await super().on_activate(db, container, event_bus)
# Als System-Teilnehmer registrieren
registry = get_registry()
registry.register("system", SystemParticipantHandler(...))
# Auf Events hören und Nachrichten erzeugen
event_bus.subscribe("lead.created", self.on_lead_created)
```
### 3. Plugin `ai_assistant` (Anpassung)
Das bestehende AI Assistant Plugin wird angepasst:
- Behält: Provider-Verwaltung, Modelle, Agents, Tools, Streaming
- Neu: Implementiert `ParticipantHandler` und registriert sich bei `kommunikation`
- Neu: Lauscht auf `message.received` Events → wenn `@KI` erwähnt wird oder Konversation AI als Teilnehmer hat → generiert Response
- Alt: Eigene `AIChatSession` / `AIChatMessage` Tabellen bleiben für Abwärtskompatibilität, werden langfristig migriert
- Neu: Schreibt Nachrichten in `kommunikation.messages` statt nur in eigene Tabellen
### 4. Plugin `system_notif` (Neu)
**Verantwortung:** System-Events in Nachrichten umwandeln.
- Registriert sich als `system` Teilnehmer
- Hört auf EventBus-Events (`lead.created`, `contact.created`, `task.overdue`, ...)
- Erzeugt Nachrichten in der System-Konversation des Users
- Notifications haben `metadata.action_url` und `metadata.severity`
- Bestehende Notification-Tabelle wird migriert
### 5. Messenger-Gateway Plugins (Später)
Jeder Messenger ist ein eigenes Plugin:
- `whatsapp_gateway` — registriert sich als `whatsapp` Teilnehmer
- `telegram_gateway` — registriert sich als `telegram` Teilnehmer
- `email_gateway` — registriert sich als `email` Teilnehmer
Jedes implementiert `ParticipantHandler` und ggf. Webhook-Routes.
---
## Datenmodell
### Tabelle `comm_conversations`
```
id UUID PK
tenant_id UUID NOT NULL
title TEXT NULL -- benannte Räume
title_set_by UUID NULL -- user_id der den Titel gesetzt hat
is_pinned BOOLEAN DEFAULT FALSE
is_direct BOOLEAN DEFAULT FALSE -- 1:1 vs Gruppe
created_by UUID NULL
last_msg_at TIMESTAMP
last_msg_preview TEXT NULL -- für Konversations-Liste
last_msg_sender_type TEXT NULL -- für Icon in Liste
metadata JSONB DEFAULT '{}' -- z.B. {"pinned_by": "user_id"}
created_at TIMESTAMP DEFAULT NOW()
updated_at TIMESTAMP DEFAULT NOW()
```
### Tabelle `comm_participants`
```
id UUID PK
conversation_id UUID FK → comm_conversations
participant_id UUID NULL -- user_id (NULL für ai/system/gateways)
participant_type TEXT NOT NULL -- 'user', 'ai', 'system', 'whatsapp', ...
display_name TEXT NULL -- override (z.B. WhatsApp-Kontakt-Name)
joined_at TIMESTAMP DEFAULT NOW()
left_at TIMESTAMP NULL
```
### Tabelle `comm_messages`
```
id UUID PK
tenant_id UUID NOT NULL
conversation_id UUID FK → comm_conversations
sender_id UUID NULL -- user_id (NULL für ai/system/gateways)
sender_type TEXT NOT NULL -- 'user', 'ai', 'system', 'whatsapp', ...
content TEXT NOT NULL -- Text-Inhalt (Markdown)
content_format TEXT DEFAULT 'text' -- 'text', 'markdown', 'html'
metadata JSONB DEFAULT '{}' -- typ-spezifische Daten
reply_to_id UUID NULL FK → comm_messages -- Thread-Antwort
created_at TIMESTAMP DEFAULT NOW()
read_at TIMESTAMP NULL
edited_at TIMESTAMP NULL
deleted_at TIMESTAMP NULL
```
### Tabelle `comm_message_attachments`
```
id UUID PK
message_id UUID FK → comm_messages
file_name TEXT NOT NULL
file_path TEXT NOT NULL -- Pfad im DMS oder S3
file_type TEXT NOT NULL -- MIME type
file_size BIGINT
thumbnail_path TEXT NULL -- für Bilder/Videos
metadata JSONB DEFAULT '{}' -- z.B. {"width": 1920, "height": 1080}
created_at TIMESTAMP DEFAULT NOW()
```
### Tabelle `comm_message_reactions`
```
id UUID PK
message_id UUID FK → comm_messages
user_id UUID NOT NULL
emoji TEXT NOT NULL
created_at TIMESTAMP DEFAULT NOW()
UNIQUE(message_id, user_id, emoji)
```
### Tabelle `comm_message_reads`
```
id UUID PK
conversation_id UUID FK
user_id UUID NOT NULL
last_read_msg_id UUID FK → comm_messages
last_read_at TIMESTAMP DEFAULT NOW()
```
### Tabelle `comm_message_blocks` (Rich Content / Mini-Apps)
```
id UUID PK
message_id UUID FK → comm_messages
block_type TEXT NOT NULL -- 'file', 'image', 'audio', 'video',
-- 'markdown', 'html', 'miniapp',
-- 'action_card', 'contact_card', ...
block_data JSONB NOT NULL -- typ-spezifische strukturierte Daten
sort_order INT DEFAULT 0
```
**Das ist der Schlüssel für Rich Content:**
Eine Nachricht hat einen `content` (Text) plus beliebig viele `blocks` (strukturierte Elemente).
---
## Rich Content Transport
### Block-Typen (erweiterbar durch Plugins)
| block_type | Beschreibung | block_data Beispiel |
|---|---|---|
| `text` | Reiner Text (Fallback) | `{"text": "..."}` |
| `markdown` | Markdown-Content | `{"markdown": "# Titel\n..."}` |
| `html` | HTML-Content (sanitized) | `{"html": "<div>...</div>"}` |
| `image` | Bild | `{"url": "...", "alt": "...", "width": 800}` |
| `audio` | Audio-Datei | `{"url": "...", "duration": 120, "waveform": [...]}` |
| `video` | Video-Datei | `{"url": "...", "duration": 60, "thumbnail": "..."}` |
| `file` | Allgemeine Datei | `{"url": "...", "name": "...", "size": 1024}` |
| `action_card` | Interaktive Karte mit Buttons | `{"title": "...", "body": "...", "actions": [{"label": "Öffnen", "url": "..."}]}` |
| `contact_card` | Kontakt-Referenz | `{"contact_id": "...", "name": "..."}` |
| `miniapp` | Eingebettete Mini-App | `{"app_id": "...", "config": {...}}` |
### Mini-App System
Mini-Apps sind kleine interaktive Komponenten, die **von Plugins registriert** und im Chat gerendert werden.
```python
# Plugin registriert eine Mini-App:
class MiniAppRegistry:
def register(self, app_id: str, component: dict) -> None:
"""Registriert eine Mini-App.
component = {
'name': 'Lead Qualifier',
'icon': 'clipboard',
'render_schema': {...}, # JSON-Schema für Frontend
'handler': async function # Backend-Handler
}
"""
```
**Beispiel:** Ein Plugin `lead_qualifier` registriert eine Mini-App. Ein User schickt `/miniapp lead_qualifier` im Chat → eine Mini-App-Block wird erzeugt → Frontend rendert das interaktive Formular → Ergebnis wird als Nachricht zurückgeschrieben.
### Nachricht mit Rich Content — Beispiel
```json
{
"id": "...",
"conversation_id": "...",
"sender_type": "ai",
"content": "Hier ist die Zusammenfassung der neuen Leads:",
"blocks": [
{
"block_type": "markdown",
"block_data": {
"markdown": "## 3 neue Leads\n- **Acme Corp** — €50k potential\n- **Globex** — €20k potential\n- **Initech** — €10k potential"
}
},
{
"block_type": "action_card",
"block_data": {
"title": "Nächste Schritte",
"body": "3 Leads warten auf Qualifizierung.",
"actions": [
{"label": "Alle öffnen", "action": "open_leads", "type": "primary"},
{"label": "Ignorieren", "action": "dismiss", "type": "secondary"}
]
}
}
]
}
```
---
## API
### REST Endpoints
```
# Konversationen
GET /api/v1/comm/conversations -- Liste (für aktuellen User)
POST /api/v1/comm/conversations -- Neue Konversation
GET /api/v1/comm/conversations/{id} -- Details + Teilnehmer
PATCH /api/v1/comm/conversations/{id} -- Titel ändern, pinnen
DELETE /api/v1/comm/conversations/{id} -- Löschen/Verlassen
# Teilnehmer
POST /api/v1/comm/conversations/{id}/participants -- Teilnehmer hinzufügen
DELETE /api/v1/comm/conversations/{id}/participants/{pid} -- Entfernen
# Nachrichten
GET /api/v1/comm/conversations/{id}/messages -- Nachrichten (paginiert)
POST /api/v1/comm/conversations/{id}/messages -- Nachricht senden
PATCH /api/v1/comm/messages/{id} -- Bearbeiten/Lesen
DELETE /api/v1/comm/messages/{id} -- Löschen
# Attachments
POST /api/v1/comm/messages/{id}/attachments -- Datei hochladen
GET /api/v1/comm/attachments/{id} -- Datei herunterladen
# Reaktionen
POST /api/v1/comm/messages/{id}/reactions -- Reaktion hinzufügen
DELETE /api/v1/comm/messages/{id}/reactions/{emoji} -- Reaktion entfernen
# Read State
POST /api/v1/comm/conversations/{id}/read -- Als gelesen markieren
# Mini-Apps
GET /api/v1/comm/miniapps -- Verfügbare Mini-Apps
POST /api/v1/comm/conversations/{id}/miniapps -- Mini-App starten
```
### WebSocket
```
WS /api/v1/comm/ws
# Client → Server
{"type": "subscribe", "conversation_id": "..."}
{"type": "typing", "conversation_id": "...", "is_typing": true}
{"type": "ping"}
# Server → Client
{"type": "message.new", "conversation_id": "...", "message": {...}}
{"type": "message.updated", "message": {...}}
{"type": "message.deleted", "id": "..."}
{"type": "participant.joined", "conversation_id": "...", "participant": {...}}
{"type": "participant.left", "conversation_id": "...", "participant_id": "..."}
{"type": "typing", "conversation_id": "...", "user_id": "...", "is_typing": true}
{"type": "reaction.added", "message_id": "...", "emoji": "👍", "user_id": "..."}
{"type": "conversation.updated", "conversation": {...}}
{"type": "pong"}
```
---
## UI-Konzept
### MessageSidebar (ersetzt AISidebar)
```
┌──────────────────────────────────────────┐
│ Kommunikation [×] │
├──────────────────────────────────────────┤
│ 🔍 Suche... │
├──────────────────────────────────────────┤
│ 📌 Projekt Alpha │ ←angepinnt
│ 🤖 KI: 3 Leads zusammengefasst... │
│ ┌────────────────────────────────────┐ │
│ │ Max: @KI fasse die Leads zusammen │ │
│ │ 🤖 KI: 3 neue Leads, 2 aus... │ │
│ │ Lisa: Super, danke! │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ 📎 lead_report.pdf │ │ │
│ │ │ ──────────────────────────── │ │ │
│ │ │ ## 3 neue Leads │ │ │
│ │ │ - **Acme Corp** — €50k │ │ │
│ │ │ ──────────────────────────── │ │ │
│ │ │ [Öffnen] [Archivieren] │ │ │
│ │ └──────────────────────────────┘ │ │
│ └────────────────────────────────────┘ │
│ │
│ 📌 Assistent (1:1 mit KI) │
│ 🤖 47 Kontakte ohne Email... │
│ │
│ 👥 Sales Team │
│ Max: Hat jemand die Q3-Zahlen? │
│ │
│ 🔔 System │
│ 3 neue Leads importiert │
│ │
├──────────────────────────────────────────┤
│ [📎] [Eingabefeld...] [Senden] │
└──────────────────────────────────────────┘
```
### Konversations-Liste (links im Panel)
- Angespinnte Konversationen oben (📌)
- Ungelesene-Badge pro Konversation
- Letzte Nachricht mit Sender-Icon (🤖/👤/🔔)
- Klick → öffnet Konversation im Feed
### Feed (Mitte)
- Chronologische Nachrichten
- Sender-Icon + Name pro Nachricht
- Rich Content Blocks inline gerendert
- Action-Cards mit Buttons
- Datei-Anhänge mit Vorschau
- Reaktionen (Emoji-Bar beim Hover)
- Lesebestätigung (gelesen-Häkchen)
### Eingabefeld (unten)
- Text-Eingabe mit Markdown-Support
- Datei-Anhang Button (📎)
- Mini-App Picker (/command)
- @Mention Support (@KI, @Max)
- Senden-Button
- Kontextsensitiv: in System-Konversation → kein Eingabefeld
### Teilnehmer-Info
- In Konversations-Header: Avatare aller Teilnehmer
- Klick auf Avatar → Info-Popover
- KI-Teilnehmer: zeigt Modell/Agent
- System-Teilnehmer: zeigt Quelle
### Räume
- Konversationen können benannt werden (Titel editierbar)
- Anpinnen möglich (📌)
- Gruppierung durch Titel, nicht durch spezielle Raum-Logik
- Ein "Raum" ist einfach eine benannte Konversation
---
## EventBus Integration
### Events vom kommunikation Plugin
```
message.received → {conversation_id, message, sender_type}
message.sent → {conversation_id, message}
conversation.created → {conversation_id, participants, created_by}
participant.joined → {conversation_id, participant_type, participant_id}
participant.left → {conversation_id, participant_id}
```
### Events die andere Plugins hören
```
# ai_assistant hört auf:
message.received → prüft ob @KI erwähnt oder AI Teilnehmer → generiert Response
# system_notif hört auf (vom Core-System):
lead.created → erzeugt System-Nachricht
contact.created → erzeugt System-Nachricht
task.overdue → erzeugt System-Nachricht
# whatsapp_gateway hört auf:
message.received → wenn Konversation WhatsApp-Teilnehmer hat → sende extern
```
---
## Migration
### Phase 1: Backend — Plugin `kommunikation`
1. Neue Tabellen: `comm_conversations`, `comm_participants`, `comm_messages`, `comm_message_attachments`, `comm_message_blocks`, `comm_message_reactions`, `comm_message_reads`
2. Participant Registry Interface
3. REST-API + WebSocket
4. Rich Content Block System
5. Mini-App Registry Interface
### Phase 2: Backend — Plugin `ai_assistant` anpassen
1. `ParticipantHandler` implementieren
2. Bei `kommunikation` registrieren
3. Auf `message.received` hören → AI-Response generieren
4. Streaming-Responses über WebSocket pushen
5. Alte `AIChatSession`/`AIChatMessage` behalten für Abwärtskompatibilität
### Phase 3: Backend — Plugin `system_notif` (neu)
1. `ParticipantHandler` implementieren
2. System-Events → Nachrichten in System-Konversation
3. Bestehende Notifications migrieren
4. Action-URLs als `action_card` Blocks
### Phase 4: Frontend — MessageSidebar
1. AISidebar → MessageSidebar umbauen
2. Konversations-Liste mit Pinning
3. Unified Feed mit Rich Content Rendering
4. Eingabefeld mit Datei-Upload + @Mention
5. WebSocket-Verbindung
6. Mini-App Rendering Framework
### Phase 5: Frontend — Rich Content Renderer
1. Block-Renderer: Markdown, HTML, Image, Audio, Video, File
2. Action-Card Renderer mit Button-Handler
3. Mini-App Renderer (Plugin-basiert)
4. Contact-Card, Lead-Card, etc.
### Phase 6: Messenger-Gateway Plugins (später)
1. `whatsapp_gateway` Plugin
2. `telegram_gateway` Plugin
3. `email_gateway` Plugin
4. Jeweils: ParticipantHandler + Webhook-Routes + Gateway-Adapter
---
## Technische Entscheidungen
### WebSocket vs Polling
**WebSocket** — eine Verbindung pro User, pusht alle Konversationen.
Grund: Real-time ist essenziell für Chat, und eine Verbindung für alles ist effizienter als Multiple Polling.
### Rich Content: Blocks vs Inline
**Blocks** — separate Tabelle `comm_message_blocks` mit `block_type` + `block_data`.
Grund: Erweiterbar durch Plugins, strukturiert, frontend kann unbekannte Typen graceful ignorieren.
### Mini-Apps: Plugin-basiert
**Registry Pattern** — Plugins registrieren Mini-Apps bei `kommunikation`.
Grund: Plugins können eigene Mini-Apps mitbringen, Frontend rendert sie dynamisch.
### Räume: Keine separate Tabelle
**Titel + Pinning** — eine Konversation mit Titel ist ein Raum.
Grund: Minimalistisch, keine zusätzliche Komplexität, flexibel.
### @Mention Detection
**Im Backend** — `message.received` Event enthält geparste mentions.
Grund: Zentrale Logik, alle Teilnehmer-Plugins bekommen saubere Daten.
### Abwärtskompatibilität
**Alte Tabellen behalten** — `ai_chat_sessions`, `ai_chat_messages`, `ai_conversations`, `ai_messages` bleiben erhalten.
Grund: Bestehende Daten gehen nicht verloren, Migration schrittweise.
---
## Offene Fragen
1. **Soll `kommunikation` das bestehende AI Copilot System (AIConversation/AIMessage) ersetzen oder parallel laufen?**
- Vorschlag: Parallel, langfristig migrieren
2. **Datei-Speicherung:** DMS-Plugin nutzen oder eigener Speicher für Attachments?
- Vorschlag: DMS-Integration, `file_path` verweist auf DMS-Dokument
3. **Berechtigungen:** Wer darf Konversationen erstellen? Wer darf Teilnehmer hinzufügen?
- Vorschlag: `comm:write` für erstellen, `comm:manage` für Teilnehmer verwalten
4. **Gruppen-Chat-Limit:** Maximale Anzahl Teilnehmer?
- Vorschlag: Kein Limit, Performance-Test später
5. **Nachrichten-Historie:** Endlos oder Paginierung mit Lazy-Loading?
- Vorschlag: Paginierung (50 pro Seite), Lazy-Load beim Scrollen
6. **Suche:** Über alle Konversationen? Global mit unified_search Plugin?
- Vorschlag: Ja, `unified_search` Provider für `kommunikation`
7. **Push-Notifications:** Browser-Notifications bei neuen Nachrichten?
- Vorschlag: Ja, über Notification API + Service Worker
8. **Verschlüsselung:** E2E für bestimmte Konversationen?
- Vorschlag: Nein in Phase 1, später evaluieren
---
## Zusammenfassung
```
Ein Plugin (kommunikation) → Chat-Infrastruktur + Rich Content + WebSocket
Ein Interface (ParticipantHandler) → Plugins docken als Teilnehmer an
Ein Datenmodell (3+Tabellen) → Konversationen, Teilnehmer, Nachrichten + Blocks
Eine UI (MessageSidebar) → Ein Feed, eine Liste, ein Eingabefeld
Eine WebSocket → Real-time für alles
Ein EventBus → Plugins reagieren auf Nachrichten
KI = Teilnehmer → @KI in jedem Chat
System = Teilnehmer → Notifications als Nachrichten
WhatsApp = Teilnehmer → Externe Messenger andocken
Mini-Apps = Plugin-Blocks → Erweiterbar im Chat
Räume = Benannte Chats → Titel + Pinning
```