# Architektur ## Systemübersicht Das bitbylaw-System ist eine event-driven Integration Platform mit Motia als zentraler Middleware. Motia orchestriert die bidirektionale Kommunikation zwischen allen angebundenen Systemen: Advoware (Kanzlei-Software), EspoCRM/VMH (CRM), Google Calendar, Vermieterhelden (WordPress), 3CX (Telefonie) und Y (assistierende KI). ### Kernkomponenten ``` ┌──────────────────────┐ │ KONG API Gateway │ │ api.bitbylaw.com │ │ (Auth, Rate Limit) │ └──────────┬───────────┘ │ │ ┌────────────────────┼────────────────────┐ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ │ │ ┌─────────┼─────────▶│ Motia │◀──────────┼──────────┐ │ │ │ (Middleware) │ │ │ │ │ │ Event-Driven │ │ │ │ │ │ │ │ │ │ │ └──────────────────┘ │ │ │ │ ▲ │ │ │ │ │ │ │ │ │ ┌─────────┴─────────┐ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ Y │ │VMH/CRM│ │Google │ │Advo- │ │ 3CX │ │Vermie-│ │ KI │ │EspoCRM│ │Calen- │ │ware │ │Tele- │ │terHel-│ │Assist.│ │ │ │ dar │ │ │ │fonie │ │den.de │ └───────┘ └───────┘ └───────┘ └───────┘ └───────┘ └───────┘ AI CRM Calendar Kanzlei Calls Leads Context Management Sync Software Handling Input ``` **Architektur-Prinzipien**: - **Motia als Hub**: Alle Systeme kommunizieren ausschließlich mit Motia - **Keine direkte Kommunikation**: Externe Systeme kommunizieren nicht untereinander - **Bidirektional**: Jedes System kann Daten senden und empfangen - **Event-Driven**: Ereignisse triggern Workflows zwischen Systemen - **KONG als Gateway**: Authentifizierung und Rate Limiting für alle API-Zugriffe ## Komponenten-Details ### 0. KONG API Gateway **Zweck**: Zentraler API-Gateway für alle öffentlichen APIs mit Authentifizierung und Rate Limiting. **Domain**: `api.bitbylaw.com` **Funktionen**: - **Authentication**: API-Key-basiert, JWT, OAuth2 - **Rate Limiting**: Pro Consumer/API-Key - **Request Routing**: Zu Backend-Services (Motia, etc.) - **SSL/TLS Termination**: HTTPS-Handling - **Logging & Monitoring**: Request-Logs, Metrics - **CORS Handling**: Cross-Origin Requests **Upstream Services**: - Motia Framework (Advoware Proxy, Calendar Sync, VMH Webhooks) - Zukünftig: Weitere Microservices **Konfiguration**: ```yaml # KONG Service Configuration services: - name: motia-backend url: http://localhost:3000 routes: - name: advoware-proxy paths: [/advoware/*] - name: calendar-sync paths: [/calendar/*] - name: vmh-webhooks paths: [/vmh/*] plugins: - name: key-auth - name: rate-limiting config: minute: 600 ``` **Flow**: ``` Client → KONG (api.bitbylaw.com) → Auth Check → Rate Limit → Motia Backend ``` ### 1. Advoware Proxy Layer **Zweck**: Transparente REST-API-Proxy für Advoware mit Authentifizierung und Caching. **Module**: `steps/advoware_proxy/` - `advoware_api_proxy_get_step.py` - GET-Requests - `advoware_api_proxy_post_step.py` - POST-Requests (Create) - `advoware_api_proxy_put_step.py` - PUT-Requests (Update) - `advoware_api_proxy_delete_step.py` - DELETE-Requests **Services**: `services/advoware.py` - Token-Management (HMAC-512 Authentifizierung) - Redis-basiertes Token-Caching (55min Lifetime) - Automatischer Token-Refresh bei 401-Errors - Async API-Client mit aiohttp **Datenfluss**: ``` Client → API-Step → AdvowareAPI Service → Redis (Token Cache) → Advoware API ``` ### 2. Calendar Sync System **Zweck**: Bidirektionale Synchronisation zwischen Advoware-Terminen und Google Calendar. **Architecture Pattern**: Event-Driven Cascade **Integration**: EspoCRM sendet Webhooks an KONG → Motia **Datenfluss**: ``` EspoCRM (Vermieterhelden CRM) → KONG → Motia VMH Webhooks → Redis Dedup → Events ``` ``` Cron (täglich) → calendar_sync_cron_step → Emit: "calendar_sync_all" → calendar_sync_all_step → Fetch Employees → For each Employee: → Set Redis Lock → Emit: "calendar_sync_employee" → calendar_sync_event_step → Fetch Advoware Events → Fetch Google Events → Sync (Create/Update/Delete) → Clear Redis Lock ``` **Module**: `steps/advoware_cal_sync/` - `calendar_sync_cron_step.py` - Täglicher Trigger - `calendar_sync_all_step.py` - Employee-List-Handler - `calendar_sync_event_step.py` - Per-Employee Sync-Logic - `calendar_sync_api_step.py` - Manueller Trigger-Endpoint - `calendar_sync_utils.py` - Shared Utilities - `audit_calendar_sync.py` - Audit & Diagnostics **Key Features**: - **Redis Locking**: Verhindert parallele Syncs für denselben Employee - **Rate Limiting**: Token-Bucket-Algorithm (7 tokens, Redis-based) - **Normalisierung**: Common format (Berlin TZ) für beide APIs - **Error Isolation**: Employee-Fehler stoppen nicht Gesamt-Sync **Datenmapping**: ``` Advoware Format → Standard Format → Google Calendar Format ↓ ↓ ↓ datum/uhrzeitVon start (datetime) dateTime datumBis end (datetime) dateTime dauertermin all_day (bool) date turnus/turnusArt recurrence RRULE ``` ### 3. VMH Webhook System **Zweck**: Empfang und Verarbeitung von EspoCRM Webhooks für Beteiligte-Entitäten. **Architecture Pattern**: Webhook → Deduplication → Event Emission **Module**: `steps/vmh/` - `webhook/beteiligte_create_api_step.py` - Create Webhook - `webhook/beteiligte_update_api_step.py` - Update Webhook - `webhook/beteiligte_delete_api_step.py` - Delete Webhook - `beteiligte_sync_event_step.py` - Sync Event Handler (Placeholder) **Webhook-Flow**: ``` EspoCRM → POST /vmh/webhook/beteiligte/create ↓ Webhook Step ↓ Extract Entity IDs ↓ Redis Deduplication (SET: vmh:beteiligte:create_pending) ↓ Emit Event: "vmh.beteiligte.create" ↓ Sync Event Step (subscribes) ↓ [TODO: Implementierung] ### 4. Vermieterhelden Integration **Zweck**: Lead-Eingang von Vermieterhelden.de WordPress-Frontend. **URL**: `https://vermieterhelden.de` **Technologie**: WordPress-basiertes Frontend **Funktionen**: - **Lead-Formulare**: Mieter, Vermieter, Anfragen - **Lead-Routing**: Zu EspoCRM (VMH) → Motia - **Webhook-basiert**: POST zu KONG/Motia bei neuem Lead **Datenfluss**: ``` Vermieterhelden.de → Lead erstellt → Webhook → KONG → Motia → EspoCRM/Advoware ``` **Lead-Typen**: - Mieter-Anfragen - Vermieter-Anfragen - Kontaktformulare - Newsletter-Anmeldungen **Integration mit Motia**: - Eigener Webhook-Endpoint: `/api/leads/vermieterhelden` - Lead-Validierung und -Enrichment - Weiterleitung an CRM-Systeme ### 5. 3CX Telefonie-Integration **Zweck**: Telefonie-System-Integration für Call-Handling und Lead-Qualifizierung. **URL**: `https://ralup.my3cx.de` **Technologie**: 3CX Cloud PBX **Funktionen**: - **Outbound Calls**: Lead-Anrufe (automatisch oder manuell) - **Inbound Calls**: Stammdatenabfrage (CTI - Computer Telephony Integration) - **Call Logging**: Anrufprotokolle zu CRM - **Call Recording**: Aufzeichnungen speichern und abrufen - **Screen Pops**: Kundeninfo bei eingehendem Anruf **API-Integrationen**: **A) Outbound: Motia → 3CX** ``` Motia → KONG → 3CX API - Initiate Call to Lead - Get Call Status ``` **B) Inbound: 3CX → Motia** ``` 3CX Webhook → KONG → Motia - Call Started → Fetch Customer Data - Call Ended → Log Call Record ``` **Datenfluss**: **Call Initiation**: ``` Lead in CRM → Trigger Call → Motia → 3CX API → Dial Number ``` **Inbound Call**: ``` 3CX detects call → Webhook to Motia → Lookup in Advoware/EspoCRM → Return data → 3CX Screen Pop ``` **Call Recording**: ``` Call ends → 3CX Webhook → Motia → Store metadata → Link to CRM entity ``` **Use Cases**: - Lead-Qualifizierung nach Eingang - Stammdatenabfrage bei Anruf - Anrufprotokoll in EspoCRM/Advoware - Automatische Follow-up-Tasks ``` **Deduplikation-Mechanismus**: - Redis SET für pending IDs pro Action-Type (create/update/delete) - Neue IDs werden zu SET hinzugefügt - Events nur für neue (nicht-duplizierte) IDs emittiert - SET-TTL verhindert Memory-Leaks ## Event-Driven Design ### Event-Topics | Topic | Emitter | Subscriber | Payload | |-------|---------|------------|---------| | `calendar_sync_all` | cron_step | all_step | `{}` | | `calendar_sync_employee` | all_step, api_step | event_step | `{kuerzel, full_content}` | | `vmh.beteiligte.create` | create webhook | sync_event_step | `{entity_id, action, source, timestamp}` | | `vmh.beteiligte.update` | update webhook | sync_event_step | `{entity_id, action, source, timestamp}` | | `vmh.beteiligte.delete` | delete webhook | sync_event_step | `{entity_id, action, source, timestamp}` | ### Event-Flow Patterns **1. Cascade Pattern** (Calendar Sync): ``` Trigger → Fetch List → Emit per Item → Process Item ``` **2. Webhook Pattern** (VMH): ``` External Event → Dedup → Internal Event → Processing ``` ## Redis Architecture ### Database Layout **DB 0**: Default (Motia internal) **DB 1**: Advoware Cache & Locks - `advoware_access_token` - Bearer Token (TTL: 53min) - `advoware_token_timestamp` - Token Creation Time - `calendar_sync:lock:{kuerzel}` - Per-Employee Lock (TTL: 5min) - `vmh:beteiligte:create_pending` - Create Dedup SET - `vmh:beteiligte:update_pending` - Update Dedup SET - `vmh:beteiligte:delete_pending` - Delete Dedup SET **DB 2**: Calendar Sync Rate Limiting - `google_calendar_api_tokens` - Token Bucket for Rate Limiting --- ## External APIs ### Advoware REST API **Base URL**: `https://advoware-api.example.com/api/v1/` **Auth**: HMAC-512 (siehe `services/advoware.py`) **Rate Limits**: Unknown (keine Limits bekannt) **Documentation**: [Advoware API Swagger](../docs/advoware/advoware_api_swagger.json) **Wichtige Endpoints**: - `POST /auth/login` - Token generieren - `GET /employees` - Employee-Liste - `GET /events` - Termine abrufen - `POST /events` - Termin erstellen - `PUT /events/{id}` - Termin aktualisieren ### Redis Usage Patterns **Token Caching**: ```python # Set with expiration redis.set('advoware_access_token', token, ex=3180) # 53min # Get with fallback token = redis.get('advoware_access_token') if not token: token = fetch_new_token() ``` ### EspoCRM (VMH) **Integration**: Webhook Sender (Outbound), API Consumer **Endpoints**: Configured in EspoCRM, routed via KONG **Format**: JSON POST with entity data **Note**: Dient als CRM für Vermieterhelden-Leads ### 3CX Telefonie API **Base URL**: `https://ralup.my3cx.de/api/v1/` **Auth**: API Key oder Basic Auth **Rate Limits**: Unknown (typisch 60 req/min) **Key Endpoints**: - `POST /calls/initiate` - Anruf starten - `GET /calls/{id}/status` - Call-Status - `GET /calls/{id}/recording` - Aufzeichnung abrufen - `POST /webhook` - Webhook-Konfiguration (eingehend) **Webhooks** (Inbound von 3CX): - `call.started` - Anruf beginnt - `call.ended` - Anruf beendet - `call.transferred` - Anruf weitergeleitet ### Vermieterhelden **Integration**: Webhook Sender (Lead-Eingang) **Base**: WordPress mit Custom Plugins **Format**: JSON POST zu Motia **Webhook-Events**: - `lead.created` - Neuer Lead - `contact.submitted` - Kontaktformular lock_key = f'calendar_sync:lock:{kuerzel}' if not redis.set(lock_key, '1', nx=True, ex=300): raise LockError("Already locked") # Always release redis.delete(lock_key) ``` **Deduplication**: ```python # Check & Add atomically existing = redis.smembers('vmh:beteiligte:create_pending') new_ids = input_ids - existing if new_ids: redis.sadd('vmh:beteiligte:create_pending', *new_ids) ``` ## Service Layer ### AdvowareAPI Service **Location**: `services/advoware.py` **Responsibilities**: - HMAC-512 Authentication - Token Management - HTTP Client (aiohttp) - Error Handling & Retries **Key Methods**: ```python get_access_token(force_refresh=False) -> str api_call(endpoint, method, params, json_data) -> Any ``` **Authentication Flow**: ``` 1. Generate HMAC-512 signature - Message: "{product_id}:{app_id}:{nonce}:{timestamp}" - Key: Base64-decoded API Key - Hash: SHA512 2. POST to security.advo-net.net/api/v1/Token - Body: {AppID, User, Password, HMAC512Signature, ...} 3. Extract access_token from response 4. Cache in Redis (53min TTL) 5. Use as Bearer Token: "Authorization: Bearer {token}" ``` ## External API Integration ### Advoware API **Base URL**: `https://www2.advo-net.net:90/` **Auth**: HMAC-512 + Bearer Token **Rate Limits**: Unknown (robust error handling) **Key Endpoints**: - `/employees` - Mitarbeiter-Liste - `/appointments` - Termine ### Google Calendar API **Auth**: Service Account (JSON Key) **Rate Limits**: 600 requests/minute (enforced via Redis) **Scopes**: `https://www.googleapis.com/auth/calendar` **Key Operations**: - `calendars().get()` - Calendar abrufen - `calendars().insert()` - Calendar erstellen - `events().list()` - Events abrufen - `events().insert()` - Event erstellen - KONG Gateway**: API-Key oder JWT-based Auth für externe Clients **Advoware**: User-based Auth (ADVOWARE_USER + PASSWORD) **Google**: Service Account (domain-wide delegation) **3CX**: API Key oder Basic Auth **Redis**: Localhost only (no password) **Vermieterhelden**: Webhook-Secret für Validation ### EspoCRM **Integration**: Webhook Sender (Outbound) **Endpoints**: Configured in EspoCRM **Format**: JSON POST with entity data ## Security ### Secrets Management **Environment Variables**: ```bash ADVOWARE_API_KEY # Base64-encoded HMAC Key ADVOWARE_PASSWORD # User Password GOOGLE_CALENDAR_SERVICE_ACCOUNT_PATH # Path to JSON Key ESPOCRM_MARVIN_API_KEY # Webhook Validation (optional) ``` **Storage**: - Environment variables in systemd service - Service Account JSON: `/opt/motia-app/service-account.json` (chmod 600) - No secrets in code or Git ### Access Control **Advoware**: User-based Auth (ADVOWARE_USER + PASSWORD) **Google**: Service Account (domain-wide delegation) **Redis**: Localhost only (no password) ## Performance Characteristics ### Throughput **Calendar Sync**: - ~10 employees: 2-3 minutes - Rate-limited by Google API (600 req/min) - Per-employee parallelization: Nein (sequential via events) **Webhooks**: - Instant processing (<100ms) - Batch support (multiple entities per request) - Redis dedup overhead: <10ms ### Memory Usage **Current**: 169MB (Peak: 276MB) **Breakdown**: - Node.js process: ~150MB - Python dependencies: Lazy-loaded per step - Redis memory: <10MB ### Scalability **Horizontal**: Nicht ohne weiteres möglich (Redis Locks, Shared State) **Vertical**: CPU-bound bei vielen parallel Employees **Bottleneck**: Google Calendar API Rate Limits ## Monitoring & Observability ### Logging **Framework**: Motia Workbench (structured logging) **Levels**: DEBUG, INFO, ERROR **Output**: journalctl (systemd) + Motia Workbench UI **Key Log Points**: - API-Requests (Method, URL, Status) - Event Emission (Topic, Payload) - Redis Operations (Keys, Success/Failure) - Errors (Stack traces, Context) ### Metrics **Available** (via Logs): - Webhook receive count - Calendar sync duration per employee - API call count & latency - Redis hit/miss ratio (implicit) **Missing** (Future): - Prometheus metrics - Grafana dashboards - Alerting ## Deployment ### systemd Service **Unit**: `motia.service` **User**: `www-data` **WorkingDirectory**: `/opt/motia-app/bitbylaw` **Restart**: `always` (10s delay) **Environment**: ```bash NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 --inspect HOST=0.0.0.0 MOTIA_LOG_LEVEL=debug ``` ### Dependencies **Runtime**: - Node.js 18+ - Python 3.13+ - Redis Server - systemd **Build**: - npm (Node packages) - pip (Python packages) - Motia CLI ## Disaster Recovery ### Backup Strategy **Redis**: - RDB snapshots (automatisch) - AOF persistence (optional) **Configuration**: - Git-versioniert - Environment Variables in systemd **Service Account**: - Manual backup: `/opt/motia-app/service-account.json` ### Recovery Procedures **Service Restart**: ```bash systemctl restart motia.service ``` **Clear Redis Cache**: ```bash redis-cli -n 1 FLUSHDB # Advoware Cache redis-cli -n 2 FLUSHDB # Calendar Sync ``` **Clear Employee Lock**: ```bash python /opt/motia-app/bitbylaw/delete_employee_locks.py ``` ## Future Enhancements ### P3CX Full Integration**: Complete call handling, CTI features 3. **Vermieterhelden Lead Processing**: Automated lead routing and enrichment 4. **Horizontal Scaling**: Distributed locking (Redis Cluster) 5. **Metrics & Monitoring**: Prometheus exporters 6. **Health Checks**: `/health` endpoint via KONG ### Considered 1. **PostgreSQL Hub**: Persistent sync state (currently Redis-only) 2. **Webhook Signatures**: Validation von Vermieterhelden/3CX requests 3. **Multi-Tenant**: Support für mehrere Kanzleien 4. **KONG Plugins**: Custom plugins für business logic 1. **PostgreSQL Hub**: Persistent sync state (currently Redis-only) 2. **Webhook Signatures**: Validation von EspoCRM requests 3. **Multi-Tenant**: Support für mehrere Kanzleien ## Related Documentation - [Development Guide](DEVELOPMENT.md) - [API Reference](API.md) - [Configuration](CONFIGURATION.md) - [Troubleshooting](TROUBLESHOOTING.md) - [Deployment Guide](DEPLOYMENT.md)