Update README.md with comprehensive documentation of Advoware Calendar Sync implementation, including API quirks, token security, and known issues

This commit is contained in:
root
2025-10-22 23:36:21 +00:00
parent c897f4c39d
commit 0a4317c44a

View File

@@ -13,35 +13,69 @@ Das System synchronisiert Termine zwischen:
### Automatische Kalender-Erstellung ### Automatische Kalender-Erstellung
- Für jeden Advoware-Mitarbeiter wird ein Google Calendar mit dem Namen `AW-{Kuerzel}` erstellt - Für jeden Advoware-Mitarbeiter wird ein Google Calendar mit dem Namen `AW-{Kuerzel}` erstellt
- Beispiel: Mitarbeiter mit Kürzel "SB" → Calendar "AW-SB" - 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 #### 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 - Neue Termine werden in den entsprechenden Google Calendar eingetragen
- Die Advoware-Termin-ID (`frNr`) wird als Metadaten gespeichert - Die Advoware-Termin-ID (`frNr`) wird als Metadaten gespeichert
- Bestehende Termine werden aktualisiert, wenn Änderungen erkannt werden
#### Google Calendar → Advoware #### Google Calendar → Advoware
- Termine aus Google Calendar ohne `frNr` werden als neue Termine in Advoware erstellt - Termine aus Google Calendar ohne `frNr` werden als neue Termine in Advoware erstellt
- Die generierte `frNr` wird zurück in den Google Calendar geschrieben - 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 ### Token-Sicherheit
- **Vollständige Termindetails**: Titel, Beschreibung, Ort werden synchronisiert - MD5-Hash mit Salt (aus Umgebungsvariable `CALENDAR_SYNC_SALT`) für Änderungsvalidierung
- **Nur "Blocked"**: Termine werden nur als "beschäftigt" markiert (keine Details) - 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 ## API-Endpunkte
### Advoware ### Advoware API
- `GET /api/v1/advonet/Mitarbeiter` - Liste aller Mitarbeiter - `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 - `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 ### Google Calendar API
- Kalender-Management (erstellen, auflisten) - Kalender-Management (erstellen, auflisten, ACL setzen)
- Event-Management (erstellen, aktualisieren, löschen) - Event-Management (erstellen, aktualisieren, löschen)
- Service Account Authentifizierung mit Backoff bei Rate Limits
## Step-Konfiguration ## 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 - **Type:** api
- **Path:** `/advoware/calendar/sync` - **Path:** `/advoware/calendar/sync`
- **Method:** POST - **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 ## Setup
### Google API Credentials ### Google API Credentials
1. Google Cloud Console Projekt erstellen 1. Google Cloud Console Projekt erstellen
2. Google Calendar API aktivieren 2. Google Calendar API aktivieren
3. OAuth 2.0 Credentials erstellen 3. Service Account erstellen (kein OAuth)
4. `token.pickle` Datei im Projektverzeichnis bereitstellen 4. `service-account.json` Datei im Projektverzeichnis bereitstellen
### Advoware API Credentials
OAuth-ähnliche Authentifizierung mit HMAC-Signature.
### Umgebungsvariablen ### Umgebungsvariablen
```env ```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 ## Verwendung
@@ -76,28 +141,35 @@ curl -X POST "http://localhost:3000/advoware/calendar/sync" \
-d '{"full_content": true}' -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 ### 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 ## Datenmapping
### Advoware → Google Calendar ### Advoware → Google Calendar
```javascript ```javascript
{ {
"summary": appointment.text || "Advoware Termin", "summary": "Advoware blocked", // Immer "blocked" für Privacy
"description": `Advoware Termin\nNotiz: ${appointment.notiz}\nOrt: ${appointment.ort}`, "description": `Advoware Termin ID: ${appointment.frNr}`,
"location": appointment.ort, "location": "",
"start": { "start": {
"dateTime": `${appointment.datum}T${appointment.uhrzeitBis || '00:00:00'}`, "dateTime": start_datetime, // Berechnet aus datum/uhrzeitVon
"timeZone": "Europe/Berlin" "timeZone": "Europe/Berlin"
}, },
"end": { "end": {
"dateTime": `${appointment.datumBis || appointment.datum}T${appointment.uhrzeitBis || '23:59:59'}`, "dateTime": end_datetime, // Berechnet aus datumBis/uhrzeitBis
"timeZone": "Europe/Berlin" "timeZone": "Europe/Berlin"
}, },
"extendedProperties": { "extendedProperties": {
"private": { "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 ### Google Calendar → Advoware
```javascript ```javascript
{ {
"frNr": int(frnr),
"text": event.summary, "text": event.summary,
"notiz": event.description, "notiz": updated_description, // Mit sync-info
"ort": event.location, "ort": event.location,
"datum": event.start.dateTime.substring(0, 10), "datum": start.split('+')[0] if '+' in start else start,
"uhrzeitBis": event.start.dateTime.substring(11, 19), "uhrzeitBis": end.split('T')[1].split('+')[0] if 'T' in end else '09:00:00',
"datumBis": event.end.dateTime.substring(0, 10), "datumBis": end.split('+')[0] if '+' in end else end,
"sb": employee_kuerzel, "sb": employee_kuerzel,
"anwalt": employee_kuerzel "anwalt": employee_kuerzel,
"vorbereitungsDauer": "00:00:00"
} }
``` ```
## Fehlerbehandlung ## Fehlerbehandlung
- **Google API Fehler:** Automatische Token-Refresh, Fallback bei Authentifizierungsfehlern - **Google API Fehler:** Exponentieller Backoff bei 403/429, automatische Wiederholung
- **Advoware API Fehler:** Retry-Logic, detaillierte Logging - **Advoware API Fehler:** Token-Refresh bei 401, detaillierte Logging
- **Netzwerkfehler:** Timeout-Handling, Wiederholungsversuche - **JSON Parse Fehler:** Response-Text logging für Debugging
- **Dateninkonsistenzen:** Validierung vor Sync, Konfliktlösung - **Netzwerkfehler:** Timeout-Handling, konfigurierbare Timeouts
- **Dateninkonsistenzen:** Token-Validierung, Änderungsvergleich vor Update
## Monitoring ## Monitoring
### Logs ### Logs
- Erfolgreiche Synchronisationen - Erfolgreiche Synchronisationen mit Anzahl
- Fehlerhafte Termine - Fehlerhafte API-Calls mit Details
- Kalender-Erstellungen - Kalender-Erstellungen und ACL-Setups
- Performance-Metriken - Performance-Metriken (Sync-Dauer)
- Debug-Logs für Änderungsvergleiche
### Metriken ### Metriken
- Anzahl synchronisierter Termine - Anzahl synchronisierter Termine
- Verarbeitete Mitarbeiter - Verarbeitete Mitarbeiter
- Fehlerquoten - Fehlerquoten pro API
- Sync-Dauer - Gelöschte Termine
- Token-Validierungsfehler
## Sicherheit ## Sicherheit
- OAuth 2.0 für Google API Zugriff - Service Account für Google API (kein User-Consent)
- Token-Speicherung in verschlüsselten Dateien - HMAC-SHA512 für Advoware Token-Generierung
- Scoped API Permissions (nur Calendar-Zugriff) - 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 - 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 ## Erweiterungen
### Geplante Features ### Geplante Features
- Inkrementelle Syncs (nur geänderte Termine) - Inkrementelle Syncs (nur geänderte Termine seit letztem Sync)
- Konfliktlösungsstrategien (Advoware gewinnt, Google gewinnt, Manuell) - Konfliktlösungsstrategien (Advoware gewinnt, Google gewinnt, Manuell)
- Batch-Verarbeitung für Performance - Batch-Verarbeitung für bessere Performance
- Webhook-Integration für Echtzeit-Syncs - Webhook-Integration für Echtzeit-Syncs
- Mehrere Google-Accounts unterstützen - Mehrere Google-Accounts unterstützen
- Outlook/Apple Calendar Integration
### Integration mit anderen Systemen ### Code-Verbesserungen
- Outlook Calendar - Unit-Tests für API-Calls
- Apple Calendar - Mock-Server für Testing
- Mobile Apps - Config-Validation beim Startup
- Notification-Systeme - Health-Checks für beide APIs
- Metrics-Export (Prometheus)