Files
Atlas/AUTOMATION-SYSTEM.md
Julia Wehden a2c95c70e7 feat: Equipment-System, Buchungsbearbeitung, Kundenadresse, LexOffice-Fix
- Vintage Modell hinzugefuegt
- Equipment Multi-Select (Neue Buchung + Bearbeitung)
- Kundenadresse in Formularen
- Bearbeiten-Seite fuer Buchungen
- Abbau-Zeiten in Formularen und Uebersicht
- Vertrag PDF nur bei Privatkunden
- LexOffice Kontakt-Erstellung Fix (BUSINESS)
- Zurueck-Pfeil auf Touren-Seite
2026-03-19 16:21:55 +01:00

9.3 KiB

SaveTheMoment Automatisierungs-System

Übersicht

Das vollständig automatisierte Buchungs- und Verwaltungssystem für SaveTheMoment verarbeitet Anfragen von der E-Mail-Eingang bis zur Admin-Bestätigung.

Workflow-Phasen

Phase 1: ANFRAGE (Automatisch bei neuer Buchung)

Trigger: Neue Buchung via E-Mail-Sync oder API

Automatische Aktionen (lib/booking-automation.ts::runPostBookingActions()):

  1. LexOffice Contact & Quotation erstellen

    • Contact aus Kundendaten erstellen
    • Angebot mit allen Positionen generieren (Fotobox, KM-Pauschale, Extras)
    • Angebots-PDF von LexOffice herunterladen
    • Speichert lexofficeContactId und lexofficeOfferId
  2. Mietvertrag-PDF generieren

    • PDF aus Template (mietvertrag-vorlage.pdf) erstellen
    • Kundendaten, Event-Details, Preis einfügen
    • Setzt contractGenerated: true und contractGeneratedAt
  3. E-Mail mit Angebot + Vertrag versenden

    • Beide PDFs als Anhänge
    • Online-Signatur-Link enthalten
    • Übersichtliche Buchungsdetails und Gesamtpreis
    • Setzt contractSentAt
  4. Nextcloud Kalender-Sync

    • Event im Buchungskalender erstellen/aktualisieren
    • Setzt calendarSynced: true und calendarSyncedAt
  5. Admin-Benachrichtigung

    • Notification mit Typ NEW_BOOKING

Dateien:

  • lib/booking-automation.ts - Hauptlogik
  • lib/lexoffice.ts - LexOffice API (Contact, Quotation, PDF-Download)
  • lib/pdf-template-service.ts - Contract PDF-Generierung
  • lib/email-service.ts - sendInitialBookingEmail()
  • lib/nextcloud-calendar.ts - CalDAV-Synchronisation

Phase 2: ONLINE-UNTERSCHRIFT (Kunde)

Endpoint: POST /api/bookings/[id]/sign

Ablauf:

  1. Kunde öffnet Link: /contract/sign/{token}
  2. Canvas-Signatur zeichnen
  3. POST an /api/bookings/[id]/sign mit Base64-Signatur
  4. PDF mit Signatur neu generieren
  5. Datenbank-Update:
    • contractSigned: true
    • contractSignedAt: DateTime
    • contractSignedOnline: true
    • contractSignatureData: String (Base64)
    • contractSignedBy: String (Kundenname)
    • contractSignedIp: String
  6. Notification CONTRACT_SIGNED für Admin

Dateien:

  • app/api/bookings/[id]/sign/route.ts

Phase 3: ADMIN-BESTÄTIGUNG

Endpoint: POST /api/bookings/[id]/confirm

Voraussetzungen:

  • contractSigned === true
  • status !== 'CONFIRMED'

Ablauf:

  1. Admin klickt auf "Buchung bestätigen" im Dashboard
  2. LexOffice Auftragsbestätigung erstellen
    • lexofficeService.createConfirmationFromBooking()
    • Speichert lexofficeConfirmationId
  3. Status-Update: RESERVED → CONFIRMED
  4. Setzt confirmationSentAt
  5. Nextcloud Kalender aktualisieren (Status: CONFIRMED)
  6. Notification BOOKING_CONFIRMED

Dateien:

  • app/api/bookings/[id]/confirm/route.ts

Phase 4: RECHNUNG (Zeitgesteuert - TODO)

Trigger: Cron-Job

Regeln:

  • Privatkunde: 2 Wochen vor Event-Datum
  • Geschäftskunde: Nach Event-Datum

Ablauf:

  1. LexOffice Rechnung erstellen
  2. Rechnung finalisieren (freigeben)
  3. E-Mail an Kunde mit Rechnungs-PDF
  4. Setzt lexofficeInvoiceId

API-Endpunkte

Admin-Endpoints

POST/GET /api/admin/test-automation

Testet die automatischen Aktionen für die neueste Buchung.

Response:

{
  "success": true,
  "emailSent": true,
  "calendarSynced": true,
  "lexofficeCreated": true,
  "contractGenerated": true,
  "errors": []
}

POST /api/bookings/[id]/confirm

Bestätigt eine Buchung (RESERVED → CONFIRMED) und erstellt LexOffice Auftragsbestätigung.

Auth: Admin required


Public-Endpoints

POST /api/bookings/[id]/sign

Speichert die Online-Signatur des Kunden.

Body:

{
  "signatureData": "data:image/png;base64,..."
}

GET /api/bookings/[id]/sign

Ruft Buchungsdetails für Signatur-Seite ab.


E-Mail-Templates

1. Initiale Buchungsanfrage (sendInitialBookingEmail)

An: Kunde
Anhänge:

  • Angebot_{bookingNumber}.pdf
  • Mietvertrag_{bookingNumber}.pdf

Inhalt:

  • Buchungsdetails (Nummer, Datum, Location, Fotobox)
  • Gesamtpreis (Highlight)
  • Online-Signatur-Button
  • Nächste Schritte

2. Buchungsbestätigung (sendBookingConfirmationEmail)

An: Kunde
Anhänge: Keine (aktuell - TODO: Auftragsbestätigung anhängen)

Inhalt:

  • Bestätigung der verbindlichen Buchung
  • Buchungsdetails

3. Vertragsversand (sendContractEmail)

An: Kunde
Anhänge:

  • Mietvertrag_{bookingNumber}.pdf

Inhalt:

  • Vertrag als PDF
  • Online-Signatur-Link
  • Hinweis auf Signatur-Möglichkeiten

Datenbank-Felder (Booking)

LexOffice-Integration

  • lexofficeContactId - LexOffice Kontakt-ID
  • lexofficeOfferId - LexOffice Angebots-ID
  • lexofficeConfirmationId - LexOffice Auftragsbestätigungs-ID
  • lexofficeInvoiceId - LexOffice Rechnungs-ID (TODO)
  • confirmationSentAt - Zeitpunkt Admin-Bestätigung

Contract Management

  • contractGenerated - PDF wurde generiert
  • contractGeneratedAt - Zeitpunkt Generierung
  • contractSentAt - Zeitpunkt Versand
  • contractSigned - Vertrag unterschrieben
  • contractSignedAt - Zeitpunkt Unterschrift
  • contractSignedOnline - Online vs. Upload
  • contractSignatureData - Base64 Signatur-Bild
  • contractSignedBy - Name des Unterzeichners
  • contractSignedIp - IP-Adresse bei Online-Signatur
  • contractPdfUrl - URL zum finalen PDF (optional)

Kalender-Sync

  • calendarEventId - Nextcloud Event-UID
  • calendarSynced - Sync erfolgreich
  • calendarSyncedAt - Zeitpunkt letzter Sync

Konfiguration

Umgebungsvariablen

# LexOffice
LEXOFFICE_API_KEY=your_api_key

# Nextcloud
NEXTCLOUD_URL=https://your-nextcloud.com
NEXTCLOUD_USERNAME=username
NEXTCLOUD_PASSWORD=app_password

# E-Mail Test-Modus
TEST_MODE=true
TEST_EMAIL_RECIPIENT=test@example.com
EMAIL_ENABLED=true

# Base URL
NEXTAUTH_URL=https://your-domain.com

LexOffice-Artikel-IDs

Artikel-IDs sind in PriceConfig hinterlegt:

  • lexofficeArticleId - Fotobox ohne Druckflatrate
  • lexofficeArticleIdWithFlat - Fotobox mit Druckflatrate
  • lexofficeKmFlatArticleId - Kilometerpauschale (optional)
  • lexofficeKmExtraArticleId - Zusatzkilometer (optional)

Setup: scripts/setup-lexoffice-mapping.ts


Testing

Manuelle Tests

  1. Test Automation:

    curl -X GET http://localhost:3000/api/admin/test-automation \
      -H "Cookie: next-auth.session-token=YOUR_TOKEN"
    
  2. Test Signatur:

    curl -X POST http://localhost:3000/api/bookings/{id}/sign \
      -H "Content-Type: application/json" \
      -d '{"signatureData": "data:image/png;base64,..."}'
    
  3. Test Bestätigung:

    curl -X POST http://localhost:3000/api/bookings/{id}/confirm \
      -H "Cookie: next-auth.session-token=YOUR_TOKEN"
    

E-Mail-Sync Test

npm run sync-emails
# oder
node scripts/manual-email-sync.ts

Fehlerbehandlung

Automatisierung (Non-Blocking)

Alle Aktionen in runPostBookingActions() sind try-catch geschützt:

  • LexOffice-Fehler → logged, aber kein Abbruch
  • PDF-Fehler → logged, aber kein Abbruch
  • E-Mail-Fehler → logged, nur wenn beide PDFs verfügbar
  • Kalender-Fehler → logged, aber kein Abbruch

Return-Objekt:

{
  emailSent: boolean;
  calendarSynced: boolean;
  lexofficeCreated: boolean;
  contractGenerated: boolean;
  errors: string[];
}

Error-Logs

Alle Fehler werden in Console geloggt mit Emoji-Präfix:

  • Erfolg
  • Fehler
  • ⚠️ Warnung
  • 🤖 Automation Start
  • 💼 LexOffice
  • 📄 PDF
  • 📧 E-Mail
  • 📅 Kalender

Nächste Schritte

Kurzfristig

  1. Frontend für Online-Signatur erstellen (/contract/sign/{token})
  2. Dashboard-Button für Admin-Bestätigung
  3. Testing mit echter Buchung

Mittelfristig

  1. Rechnung-Scheduler implementieren (Cron-Job)
  2. E-Mail-Template für Rechnung
  3. Zahlungsstatus-Tracking

Langfristig

  1. Webhook-Integration für LexOffice (statt Polling)
  2. SMS-Benachrichtigungen
  3. Customer-Portal für Buchungsübersicht

Architektur-Entscheidungen

Warum Custom LineItems statt nur LexOffice-Artikel?

Problem: Kilometerpreise sind standortabhängig (Lübeck: 60€/15km, Hamburg: 100€/60km)

Lösung: Hybrid-Ansatz

  • Fotobox: LexOffice-Artikel (wenn ID vorhanden)
  • KM-Pauschale: Custom LineItem mit dynamischem Preis
  • Extras: LexOffice-Artikel oder Custom

Warum Promise-basiertes Singleton für Nextcloud?

Problem: Race-Conditions bei parallelen Initialisierungen

Lösung: initPromise-Pattern

  • Erste Initialisierung erstellt Promise
  • Alle weiteren Aufrufe warten auf gleiche Promise
  • Bei Fehler: Reset für erneuten Versuch

Warum Non-Blocking Automation?

Problem: Ein Fehler (z.B. LexOffice down) sollte nicht den gesamten Prozess stoppen

Lösung: Granulare Error-Handling

  • Jede Aktion in eigenem try-catch
  • Fehler werden gesammelt, aber nicht propagiert
  • Partial Success möglich (z.B. E-Mail ja, Kalender nein)

Support

Bei Fragen oder Problemen:

  1. Logs prüfen (Console-Output mit Emojis)
  2. .env Konfiguration validieren
  3. Nextcloud-Credentials testen: node test-nextcloud-connection.js
  4. LexOffice-Artikel-IDs prüfen: node scripts/setup-lexoffice-mapping.ts

Version: 1.0
Letzte Aktualisierung: 2025-11-12
Entwickler: Dennis Forte mit KI-Unterstützung