cc3ac9a43d
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
625 lines
25 KiB
Markdown
625 lines
25 KiB
Markdown
# 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
|
||
```
|