feat: Add Advoware Filesystem Change Webhook for exploratory logging

This commit is contained in:
bsiggel
2026-03-20 12:28:52 +00:00
parent 71f583481a
commit 3c4c1dc852
2 changed files with 146 additions and 0 deletions

View File

@@ -0,0 +1 @@
# Advoware Document Sync Steps

View File

@@ -0,0 +1,145 @@
"""
Advoware Filesystem Change Webhook
Empfängt Events vom Windows-Watcher (explorative Phase).
Aktuell nur Logging, keine Business-Logik.
"""
from typing import Dict, Any
from motia import http, FlowContext, ApiRequest, ApiResponse
import os
from datetime import datetime
config = {
"name": "Advoware Filesystem Change Webhook (Exploratory)",
"description": "Empfängt Filesystem-Events vom Windows-Watcher. Aktuell nur Logging für explorative Analyse.",
"flows": ["advoware-document-sync-exploratory"],
"triggers": [http("POST", "/advoware/filesystem/akte-changed")],
"enqueues": [] # Noch keine Events, nur Logging
}
async def handler(request: ApiRequest, ctx: FlowContext) -> ApiResponse:
"""
Handler für Filesystem-Events (explorative Phase)
Payload:
{
"aktennummer": "201900145",
"timestamp": "2026-03-20T10:15:30Z"
}
Aktuelles Verhalten:
- Validiere Auth-Token
- Logge alle Details
- Return 200 OK
"""
try:
ctx.logger.info("=" * 80)
ctx.logger.info("📥 ADVOWARE FILESYSTEM EVENT EMPFANGEN")
ctx.logger.info("=" * 80)
# ========================================================
# 1. AUTH-TOKEN VALIDIERUNG
# ========================================================
auth_header = request.headers.get('Authorization', '')
expected_token = os.getenv('ADVOWARE_WATCHER_AUTH_TOKEN', 'CHANGE_ME')
ctx.logger.info(f"🔐 Auth-Header: {auth_header[:20]}..." if auth_header else "❌ Kein Auth-Header")
if not auth_header.startswith('Bearer ') or auth_header[7:] != expected_token:
ctx.logger.error("❌ Invalid auth token")
ctx.logger.error(f" Expected: Bearer {expected_token[:10]}...")
ctx.logger.error(f" Received: {auth_header[:30]}...")
return ApiResponse(status_code=401, body={"error": "Unauthorized"})
ctx.logger.info("✅ Auth-Token valid")
# ========================================================
# 2. PAYLOAD LOGGING
# ========================================================
payload = request.body
ctx.logger.info(f"📦 Payload Type: {type(payload)}")
ctx.logger.info(f"📦 Payload Keys: {list(payload.keys()) if isinstance(payload, dict) else 'N/A'}")
ctx.logger.info(f"📦 Payload Content:")
# Detailliertes Logging aller Felder
if isinstance(payload, dict):
for key, value in payload.items():
ctx.logger.info(f" {key}: {value} (type: {type(value).__name__})")
else:
ctx.logger.info(f" {payload}")
# Aktennummer extrahieren
aktennummer = payload.get('aktennummer') if isinstance(payload, dict) else None
timestamp = payload.get('timestamp') if isinstance(payload, dict) else None
if not aktennummer:
ctx.logger.error("❌ Missing 'aktennummer' in payload")
return ApiResponse(status_code=400, body={"error": "Missing aktennummer"})
ctx.logger.info(f"📂 Aktennummer: {aktennummer}")
ctx.logger.info(f"⏰ Timestamp: {timestamp}")
# ========================================================
# 3. REQUEST HEADERS LOGGING
# ========================================================
ctx.logger.info("📋 Request Headers:")
for header_name, header_value in request.headers.items():
# Kürze Authorization-Token für Logs
if header_name.lower() == 'authorization':
header_value = header_value[:20] + "..." if len(header_value) > 20 else header_value
ctx.logger.info(f" {header_name}: {header_value}")
# ========================================================
# 4. REQUEST METADATA LOGGING
# ========================================================
ctx.logger.info("🔍 Request Metadata:")
ctx.logger.info(f" Method: {request.method}")
ctx.logger.info(f" Path: {request.path}")
ctx.logger.info(f" Query Params: {request.query_params}")
# ========================================================
# 5. TODO: Business-Logik (später)
# ========================================================
ctx.logger.info("💡 TODO: Hier später Business-Logik implementieren:")
ctx.logger.info(" 1. Redis SADD pending_aktennummern")
ctx.logger.info(" 2. Optional: Emit Queue-Event")
ctx.logger.info(" 3. Optional: Sofort-Trigger für Batch-Sync")
# ========================================================
# 6. ERFOLG
# ========================================================
ctx.logger.info("=" * 80)
ctx.logger.info(f"✅ Event verarbeitet: Akte {aktennummer}")
ctx.logger.info("=" * 80)
return ApiResponse(
status_code=200,
body={
"success": True,
"aktennummer": aktennummer,
"received_at": datetime.now().isoformat(),
"message": "Event logged successfully (exploratory mode)"
}
)
except Exception as e:
ctx.logger.error("=" * 80)
ctx.logger.error(f"❌ ERROR in Filesystem Webhook: {e}")
ctx.logger.error("=" * 80)
ctx.logger.error(f"Exception Type: {type(e).__name__}")
ctx.logger.error(f"Exception Message: {str(e)}")
# Traceback
import traceback
ctx.logger.error("Traceback:")
ctx.logger.error(traceback.format_exc())
return ApiResponse(
status_code=500,
body={
"success": False,
"error": str(e),
"error_type": type(e).__name__
}
)