# 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
```
