diff --git a/bitbylaw/steps/advoware_cal_sync/README.md b/bitbylaw/steps/advoware_cal_sync/README.md index 61d02748..4418ae47 100644 --- a/bitbylaw/steps/advoware_cal_sync/README.md +++ b/bitbylaw/steps/advoware_cal_sync/README.md @@ -13,35 +13,69 @@ Das System synchronisiert Termine zwischen: ### Automatische Kalender-Erstellung - Für jeden Advoware-Mitarbeiter wird ein Google Calendar mit dem Namen `AW-{Kuerzel}` erstellt - Beispiel: Mitarbeiter mit Kürzel "SB" → Calendar "AW-SB" +- Kalender wird mit dem Haupt-Google-Account (`lehmannundpartner@gmail.com`) als Owner geteilt -### Bidirektionale Synchronisation +### Bidirektionale Synchronisation mit Token-Validierung #### Advoware → Google Calendar -- Alle Termine eines Mitarbeiters werden aus Advoware abgerufen +- Alle Termine eines Mitarbeiters werden aus Advoware abgerufen (Zeitraum: aktuelles Jahr + 2 Jahre) - Neue Termine werden in den entsprechenden Google Calendar eingetragen - Die Advoware-Termin-ID (`frNr`) wird als Metadaten gespeichert +- Bestehende Termine werden aktualisiert, wenn Änderungen erkannt werden #### Google Calendar → Advoware - Termine aus Google Calendar ohne `frNr` werden als neue Termine in Advoware erstellt - Die generierte `frNr` wird zurück in den Google Calendar geschrieben +- Token-basierte Validierung verhindert unbefugte Änderungen +- Sync-Info wird in der Description/Notiz gespeichert -### Konfigurationsoptionen -- **Vollständige Termindetails**: Titel, Beschreibung, Ort werden synchronisiert -- **Nur "Blocked"**: Termine werden nur als "beschäftigt" markiert (keine Details) +### Token-Sicherheit +- MD5-Hash mit Salt (aus Umgebungsvariable `CALENDAR_SYNC_SALT`) für Änderungsvalidierung +- Sync-Info Format: `## no change below this line ##\nfrNr: {frNr}\nsync-token: {token}` +- Token wird bei jeder Änderung neu berechnet und validiert + +### Löschungen +- Google-initiale Termine, die in Google gelöscht werden, werden auch in Advoware gelöscht +- Tracking von gelöschten `frNr` um Re-Sync zu verhindern ## API-Endpunkte -### Advoware -- `GET /api/v1/advonet/Mitarbeiter` - Liste aller Mitarbeiter +### Advoware API +- `GET /api/v1/advonet/Mitarbeiter?aktiv=true` - Liste aktiver Mitarbeiter +- `GET /api/v1/advonet/Termine?frnr={frnr}` - Einzelner Termin - `GET /api/v1/advonet/Termine?kuerzel={kuerzel}&from={date}&to={date}` - Termine eines Mitarbeiters +- `POST /api/v1/advonet/Termine` - Neuen Termin erstellen +- `PUT /api/v1/advonet/Termine` - Termin aktualisieren +- `DELETE /api/v1/advonet/Termine?frnr={frnr}` - Termin löschen + +**API-Schwächen und Seltsamkeiten:** +- Parameter müssen als Strings übergeben werden (z.B. `aktiv='true'`, nicht `True`) +- Response kann manchmal HTML statt JSON zurückgeben, auch bei 200 Status +- Content-Type Header ist nicht immer korrekt gesetzt +- Token-Authentifizierung mit HMAC-Signature erforderlich +- Keine Paginierung für große Resultate +- Zeitformate: `datum` als `YYYY-MM-DDTHH:MM:SS`, aber manchmal ohne T ### Google Calendar API -- Kalender-Management (erstellen, auflisten) +- Kalender-Management (erstellen, auflisten, ACL setzen) - Event-Management (erstellen, aktualisieren, löschen) +- Service Account Authentifizierung mit Backoff bei Rate Limits ## Step-Konfiguration -### advoware_calendar_sync_step.py +### calendar_sync_event_step.py +- **Type:** event +- **Subscribes:** calendar.sync.triggered +- **Flows:** advoware + +**Event Data:** +```json +{ + "full_content": true // oder false für nur "blocked" +} +``` + +### calendar_sync_api_step.py - **Type:** api - **Path:** `/advoware/calendar/sync` - **Method:** POST @@ -54,17 +88,48 @@ Das System synchronisiert Termine zwischen: } ``` +### calendar_sync_cron_step.py +- **Type:** cron +- **Schedule:** Täglich um 2:00 Uhr +- **Flows:** advoware + ## Setup ### Google API Credentials 1. Google Cloud Console Projekt erstellen 2. Google Calendar API aktivieren -3. OAuth 2.0 Credentials erstellen -4. `token.pickle` Datei im Projektverzeichnis bereitstellen +3. Service Account erstellen (kein OAuth) +4. `service-account.json` Datei im Projektverzeichnis bereitstellen + +### Advoware API Credentials +OAuth-ähnliche Authentifizierung mit HMAC-Signature. ### Umgebungsvariablen ```env -GOOGLE_CALENDAR_CREDENTIALS_PATH=token.pickle +# Google Calendar +GOOGLE_CALENDAR_SERVICE_ACCOUNT_PATH=service-account.json + +# Advoware API +ADVOWARE_API_BASE_URL=https://www2.advo-net.net:90/ +ADVOWARE_PRODUCT_ID=64 +ADVOWARE_APP_ID=your_app_id +ADVOWARE_API_KEY=your_api_key +ADVOWARE_KANZLEI=your_kanzlei +ADVOWARE_DATABASE=your_database +ADVOWARE_USER=your_user +ADVOWARE_ROLE=2 +ADVOWARE_PASSWORD=your_password +ADVOWARE_TOKEN_LIFETIME_MINUTES=55 +ADVOWARE_API_TIMEOUT_SECONDS=30 + +# Redis für Token Caching +REDIS_HOST=localhost +REDIS_PORT=6379 +REDIS_DB_ADVOWARE_CACHE=1 +REDIS_TIMEOUT_SECONDS=5 + +# Calendar Sync +CALENDAR_SYNC_SALT=your_secret_salt ``` ## Verwendung @@ -76,28 +141,35 @@ curl -X POST "http://localhost:3000/advoware/calendar/sync" \ -d '{"full_content": true}' ``` +### Event-basierter Sync +```bash +curl -X POST "http://localhost:3000/events" \ + -H "Content-Type: application/json" \ + -d '{"type": "calendar.sync.triggered", "data": {"full_content": true}}' +``` + ### Automatischer Sync -Der Step kann über Cron-Jobs oder Events regelmäßig ausgeführt werden. +Der Cron-Step führt täglich um 2:00 Uhr einen vollständigen Sync aus. ## Datenmapping ### Advoware → Google Calendar ```javascript { - "summary": appointment.text || "Advoware Termin", - "description": `Advoware Termin\nNotiz: ${appointment.notiz}\nOrt: ${appointment.ort}`, - "location": appointment.ort, + "summary": "Advoware blocked", // Immer "blocked" für Privacy + "description": `Advoware Termin ID: ${appointment.frNr}`, + "location": "", "start": { - "dateTime": `${appointment.datum}T${appointment.uhrzeitBis || '00:00:00'}`, + "dateTime": start_datetime, // Berechnet aus datum/uhrzeitVon "timeZone": "Europe/Berlin" }, "end": { - "dateTime": `${appointment.datumBis || appointment.datum}T${appointment.uhrzeitBis || '23:59:59'}`, + "dateTime": end_datetime, // Berechnet aus datumBis/uhrzeitBis "timeZone": "Europe/Berlin" }, "extendedProperties": { "private": { - "advoware_frnr": appointment.frNr + "advoware_frnr": appointment.frNr.toString() } } } @@ -106,56 +178,84 @@ Der Step kann über Cron-Jobs oder Events regelmäßig ausgeführt werden. ### Google Calendar → Advoware ```javascript { + "frNr": int(frnr), "text": event.summary, - "notiz": event.description, + "notiz": updated_description, // Mit sync-info "ort": event.location, - "datum": event.start.dateTime.substring(0, 10), - "uhrzeitBis": event.start.dateTime.substring(11, 19), - "datumBis": event.end.dateTime.substring(0, 10), + "datum": start.split('+')[0] if '+' in start else start, + "uhrzeitBis": end.split('T')[1].split('+')[0] if 'T' in end else '09:00:00', + "datumBis": end.split('+')[0] if '+' in end else end, "sb": employee_kuerzel, - "anwalt": employee_kuerzel + "anwalt": employee_kuerzel, + "vorbereitungsDauer": "00:00:00" } ``` ## Fehlerbehandlung -- **Google API Fehler:** Automatische Token-Refresh, Fallback bei Authentifizierungsfehlern -- **Advoware API Fehler:** Retry-Logic, detaillierte Logging -- **Netzwerkfehler:** Timeout-Handling, Wiederholungsversuche -- **Dateninkonsistenzen:** Validierung vor Sync, Konfliktlösung +- **Google API Fehler:** Exponentieller Backoff bei 403/429, automatische Wiederholung +- **Advoware API Fehler:** Token-Refresh bei 401, detaillierte Logging +- **JSON Parse Fehler:** Response-Text logging für Debugging +- **Netzwerkfehler:** Timeout-Handling, konfigurierbare Timeouts +- **Dateninkonsistenzen:** Token-Validierung, Änderungsvergleich vor Update ## Monitoring ### Logs -- Erfolgreiche Synchronisationen -- Fehlerhafte Termine -- Kalender-Erstellungen -- Performance-Metriken +- Erfolgreiche Synchronisationen mit Anzahl +- Fehlerhafte API-Calls mit Details +- Kalender-Erstellungen und ACL-Setups +- Performance-Metriken (Sync-Dauer) +- Debug-Logs für Änderungsvergleiche ### Metriken - Anzahl synchronisierter Termine - Verarbeitete Mitarbeiter -- Fehlerquoten -- Sync-Dauer +- Fehlerquoten pro API +- Gelöschte Termine +- Token-Validierungsfehler ## Sicherheit -- OAuth 2.0 für Google API Zugriff -- Token-Speicherung in verschlüsselten Dateien -- Scoped API Permissions (nur Calendar-Zugriff) +- Service Account für Google API (kein User-Consent) +- HMAC-SHA512 für Advoware Token-Generierung +- Token-Caching in Redis mit TTL +- MD5-Token für Sync-Validierung mit Salt +- Scoped Permissions (nur Calendar-Zugriff) - Audit-Logs für alle Änderungen +## Bekannte Probleme und Workarounds + +### Advoware API +- **Parameter-Typen:** Alle Query-Parameter müssen Strings sein (z.B. `'true'` statt `True`) +- **Response-Formate:** Manchmal HTML statt JSON, auch bei 200 Status +- **Content-Type:** Nicht immer korrekt gesetzt, führt zu Parse-Fehlern +- **Zeitformate:** Inkonsistente Formate, manuelle Parsing erforderlich +- **Rate Limits:** Keine dokumentierten Limits, aber praktische Limits vorhanden + +### Google Calendar API +- **Rate Limits:** 403/429 mit Backoff-Handling +- **ACL-Sharing:** Owner-Rolle für Hauptaccount erforderlich +- **Event-Updates:** Vollständige Event-Daten bei Updates senden + +### Sync-Logik +- **Token-Mismatch:** Verhindert unbefugte Änderungen +- **Deleted Tracking:** Verhindert Re-Sync gelöschter Termine +- **Änderungsvergleich:** Nur tatsächliche Änderungen syncen + ## Erweiterungen ### Geplante Features -- Inkrementelle Syncs (nur geänderte Termine) +- Inkrementelle Syncs (nur geänderte Termine seit letztem Sync) - Konfliktlösungsstrategien (Advoware gewinnt, Google gewinnt, Manuell) -- Batch-Verarbeitung für Performance +- Batch-Verarbeitung für bessere Performance - Webhook-Integration für Echtzeit-Syncs - Mehrere Google-Accounts unterstützen +- Outlook/Apple Calendar Integration -### Integration mit anderen Systemen -- Outlook Calendar -- Apple Calendar -- Mobile Apps -- Notification-Systeme \ No newline at end of file +### Code-Verbesserungen +- Unit-Tests für API-Calls +- Mock-Server für Testing +- Config-Validation beim Startup +- Health-Checks für beide APIs +- Metrics-Export (Prometheus) \ No newline at end of file