Files
motia/bitbylaw/steps/advoware_cal_sync
root 9d40f47e19 Refaktorierung Calendar Sync: Event-driven Design, Fixes für mehrtägige Termine, Logging und Locking
- Refaktorierung zu event-driven Ansatz ohne PostgreSQL Hub
- Fixes für mehrtägige Termine: korrekte Verwendung von datumBis, Entfernung 24h-Limit
- Per-Employee Locking mit Redis
- Logging via context.logger für Motia Workbench
- Neue Schritte: calendar_sync_all_step.py, calendar_sync_cron_step.py
- Aktualisiertes README.md mit aktueller Architektur
- Workbench-Gruppierung: advoware-calendar-sync
2025-10-24 19:13:41 +00:00
..

Advoware Calendar Sync - Event-Driven Design

Dieser Abschnitt implementiert die bidirektionale Synchronisation zwischen Advoware-Terminen und Google Calendar. Das System wurde zu einem einfachen, event-driven Ansatz refaktoriert, der auf direkten API-Calls basiert, mit Redis für Locking und Deduplikation. Es stellt sicher, dass Termine konsistent gehalten werden, mit Fokus auf Robustheit, Fehlerbehandlung und korrekte Handhabung von mehrtägigen Terminen.

Übersicht

Das System synchronisiert Termine zwischen:

  • Advoware: Zentrale Terminverwaltung mit detaillierten Informationen.
  • Google Calendar: Benutzerfreundliche Kalenderansicht für jeden Mitarbeiter.

Architektur

Event-Driven Design

  • Direkte API-Synchronisation: Kein zentraler Hub; Sync läuft direkt zwischen APIs.
  • Redis Locking: Per-Employee Locking verhindert Race-Conditions.
  • Event Emission: Cron → All-Step → Employee-Step für skalierbare Verarbeitung.
  • Fehlerresistenz: Einzelne Fehler stoppen nicht den gesamten Sync.
  • Logging: Alle Logs erscheinen im Motia Workbench via context.logger.

Sync-Phasen

  1. Cron-Step: Tägliche Auslösung des Syncs.
  2. All-Step: Fetcht alle Mitarbeiter und emittiert Events pro Employee.
  3. Employee-Step: Synchronisiert Termine für einen einzelnen Mitarbeiter.

Datenmapping und Standardisierung

Beide Systeme werden auf gemeinsames Format normalisiert (Berlin TZ):

{
    'start': datetime,  # Berlin TZ
    'end': datetime,
    'text': str,
    'notiz': str,
    'ort': str,
    'dauertermin': int,  # 0/1
    'turnus': int,       # 0/1
    'turnusArt': int,
    'recurrence': str    # RRULE oder None
}

Advoware → Standard

  • Start: datum + uhrzeitVon (Fallback 09:00), oder datum als datetime.
  • End: datumBis + uhrzeitBis (Fallback 10:00), oder datum + 1h.
  • All-Day: dauertermin=1 oder Dauer >1 Tag.
  • Recurring: turnus/turnusArt (vereinfacht, keine RRULE).

Google → Standard

  • Start/End: dateTime oder date (All-Day).
  • All-Day: dauertermin=1 wenn All-Day oder Dauer >1 Tag.
  • Recurring: RRULE aus recurrence.

Standard → Advoware

  • POST/PUT: datum/uhrzeitBis/datumBis aus start/end.
  • Defaults: vorbereitungsDauer='00:00:00', sb/anwalt=employee_kuerzel.

Standard → Google

  • All-Day: date statt dateTime, end +1 Tag.
  • Recurring: RRULE aus recurrence.

Funktionalität

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.

Sync-Details

Cron-Step (calendar_sync_cron_step.py)

  • Läuft täglich und emittiert "calendar_sync_all".

All-Step (calendar_sync_all_step.py)

  • Fetcht alle Mitarbeiter aus Advoware.
  • Filtert Debug-Liste (falls konfiguriert).
  • Setzt Redis-Lock pro Employee.
  • Emittiert "calendar_sync_employee" pro Employee.

Employee-Step (calendar_sync_event_step.py)

  • Fetcht Advoware-Termine für den Employee.
  • Fetcht Google-Events für den Employee.
  • Synchronisiert: Neue erstellen, Updates anwenden, Deletes handhaben.
  • Verwendet Locking, um parallele Syncs zu verhindern.

API-Step (calendar_sync_api_step.py)

  • Manueller Trigger für einzelnen Employee oder "ALL".
  • Bei "ALL": Emittiert "calendar_sync_all".
  • Bei Employee: Setzt Lock und emittiert "calendar_sync_employee".

API-Schwächen und Fixes

Advoware API

  • Mehrtägige Termine: datumBis wird korrekt für Enddatum verwendet; '00:00:00' als '23:59:59' interpretiert.
  • Zeitformate: Robuste Parsing mit Fallbacks.
  • Keine 24h-Limit: Termine können länger als 24h sein; Google Calendar unterstützt das.

Google Calendar API

  • Zeitbereiche: Akzeptiert Events >24h ohne Probleme.
  • Rate Limits: Backoff-Retry implementiert.

Step-Konfiguration

calendar_sync_cron_step.py

  • Type: cron
  • Flows: advoware-calendar-sync

calendar_sync_all_step.py

  • Type: event
  • Subscribes: calendar_sync_all
  • Flows: advoware-calendar-sync

calendar_sync_event_step.py

  • Type: event
  • Subscribes: calendar_sync_employee
  • Flows: advoware-calendar-sync

calendar_sync_api_step.py

  • Type: api
  • Flows: advoware-calendar-sync

Setup

Umgebungsvariablen

# 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
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB_CALENDAR_SYNC=1
REDIS_TIMEOUT_SECONDS=5

# Debug
CALENDAR_SYNC_DEBUG_EMPLOYEES=PB,AI  # Optional, filter employees

Verwendung

Manueller Sync

curl -X POST "http://localhost:3000/advoware/calendar/sync" \
  -H "Content-Type: application/json" \
  -d '{"kuerzel": "PB"}'

Automatischer Sync

Cron-Step läuft täglich.

Fehlerbehandlung und Logging

  • Locking: Redis NX/EX verhindert parallele Syncs.
  • Logging: context.logger für Workbench-Sichtbarkeit.
  • API-Fehler: Retry mit Backoff.
  • Parsing-Fehler: Robuste Fallbacks.

Sicherheit

  • Service Account für Google.
  • HMAC für Advoware.
  • Redis für Locking.

Bekannte Probleme

  • Recurring-Events: Begrenzte Unterstützung.
  • Performance: Bei vielen Terminen Paginierung prüfen.

Letzte Änderungen

  • Refaktorierung zu event-driven Design ohne PostgreSQL Hub.
  • Fixes für mehrtägige Termine: Korrekte Verwendung von datumBis.
  • Entfernung 24h-Limit; Google Calendar unterstützt lange Events.
  • Per-Employee Locking mit Redis.
  • Logging via context.logger für Workbench.
  • Neue Schritte: calendar_sync_all_step.py, calendar_sync_cron_step.py.
  • Workbench-Gruppierung: "advoware-calendar-sync".