AVV-Pipeline — Technische Dokumentation
Ueberblick
Prilog generiert bei jeder Neubestellung automatisch einen personalisierten Auftragsverarbeitungsvertrag (AVV nach Art. 28 DSGVO). Der Vertrag wird mit den Kundendaten aus dem Onboarding befuellt, als PDF gerendert, in S3 archiviert, in der Datenbank protokolliert und dem Kunden per Mail zugestellt.
Kein manuelles Ausfuellen, kein Papier, kein Postversand. Der gesamte Prozess dauert unter 3 Sekunden.
Architektur
Onboarding-Frontend (Step 6: Rechtliches)
│
│ Kunde sieht AVV-Checkbox + PDF-Download-Link
│ Checkbox: "Ich schliesse den AVV elektronisch ab"
│ Klick: "Verbindlich bestellen"
│
▼
Backend: POST /api/public/orders
│
├─ [1] Order in DB anlegen (Prisma Transaction)
│
├─ [2] avv-service.processAvvConsent() (async, nicht-blockierend)
│ │
│ ├─ avv-renderer.renderAvvMarkdown()
│ │ Template laden → Platzhalter ersetzen
│ │
│ ├─ avv-renderer.generateAvvPdf()
│ │ Markdown → HTML → PDF (md-to-pdf, A4)
│ │
│ ├─ s3.uploadToS3()
│ │ avv/{orderId}/AVV_{subdomain}_{date}.pdf
│ │
│ ├─ prisma.avvConsentLog.create()
│ │ Version, Hash, Zeitstempel, IP, User-Agent
│ │
│ └─ avv-mailer.sendAvvEmail()
│ PDF als Anhang an Kunden-E-Mail
│
└─ [3] Response an Frontend (201 Created)
│
▼
Success-Page: "AVV herunterladen" ButtonDateien
| Datei | Verantwortlichkeit |
|---|---|
src/services/avv/avv-template.md | AVV-Vorlage mit Platzhaltern (691 Zeilen) |
src/services/avv/avv-renderer.ts | Template-Rendering + PDF-Generierung |
src/services/avv/avv-service.ts | Orchestrierung: rendern → speichern → protokollieren → mailen |
src/services/avv/avv-mailer.ts | MailPace-Integration fuer AVV-Versand mit PDF-Anhang |
src/services/s3.service.ts | Generischer S3-Upload/Download |
src/routes/public.ts | Trigger bei Order-Erstellung (Zeile ~390) |
src/routes/admin/monitoring.router.ts | Admin-Endpoints fuer Consent-Log + PDF-Download |
Template-System
Platzhalter
Das AVV-Template (avv-template.md) enthaelt benannte Platzhalter die zur Laufzeit ersetzt werden:
| Platzhalter | Quelle | Beispiel |
|---|---|---|
| billingCompany | Waldorfschule Weser e.V. |
| Strasse + PLZ + Ort + Land | Musterstr. 1, 28195 Bremen, DE |
| Vorname + Nachname | Max Mustermann |
| contactTechEmail | max@waldorf-weser.de |
| hostingType === 'shared' | ☑ oder ☐ |
| hostingType === 'dedicated' | ☑ oder ☐ |
| (noch nicht verfuegbar) | ☐ |
| Zeitpunkt der Zustimmung | 22.04.2026 |
| Stadt aus Rechnungsadresse | Bremen |
Versionierung
Das Template enthaelt eine Versionszeile:
*Version 1.0 | Stand 22. April 2026*Bei Aenderungen am AVV:
- Neue Version im Template (
Version 1.1) - Bestehende Kunden behalten ihre unterzeichnete Version (PDF in S3 unveraendert)
- Neue Kunden bekommen die aktuelle Version
avv_consent_log.versionermoeglicht spaetere Zuordnung
PDF-Generierung
Bibliothek
md-to-pdf — konvertiert Markdown ueber einen internen Chromium-Prozess in PDF. Leichtgewichtiger als Puppeteer standalone, da der Chromium nur fuer die Konversion gestartet wird.
Layout
- Format: A4
- Raender: 25mm oben/unten, 20mm links/rechts
- Schrift: Segoe UI / -apple-system / sans-serif, 11pt
- Ueberschriften: Gruen unterstrichen (
#22c55e) — Corporate Design - Tabellen: Vollstaendige Rahmen, graue Header
- Seitenumbruch: Vor jeder
<h1>(ausser der ersten)
CSS
Das Styling ist direkt im avv-renderer.ts definiert (Variable AVV_CSS), nicht als externe Datei. Das vereinfacht das Deployment — keine zusaetzlichen Assets noetig.
Consent-Protokollierung
Datenbank-Tabelle: avv_consent_log
| Feld | Typ | Zweck |
|---|---|---|
id | cuid | Primary Key |
order_id | VARCHAR(50) | Zuordnung zur Bestellung |
tenant_id | VARCHAR(64) | Tenant-Referenz (falls schon vorhanden) |
version | VARCHAR(20) | AVV-Versionsnummer ("1.0") |
content_hash | VARCHAR(64) | SHA-256 des gerenderten Markdown |
signed_at | TIMESTAMP | Zeitpunkt der Zustimmung |
signed_by | VARCHAR(255) | Name der zustimmenden Person |
signed_by_email | VARCHAR(255) | E-Mail der zustimmenden Person |
ip_address | VARCHAR(50) | IP-Adresse zum Zeitpunkt der Zustimmung |
user_agent | TEXT | Browser-Informationen |
pdf_storage_key | VARCHAR(500) | S3-Pfad zur archivierten PDF |
plan | VARCHAR(20) | Gewaehltes Leistungsmodell (light/pro) |
company_name | VARCHAR(255) | Name der Einrichtung |
subdomain | VARCHAR(100) | Gewaehlte Subdomain |
created_at | TIMESTAMP | Erstellungszeitpunkt des Log-Eintrags |
Content-Hash
Der SHA-256 Hash wird ueber das gerenderte Markdown berechnet (nach Platzhalter-Ersetzung, vor PDF-Konversion). Das beweist:
- Welche Version des Templates verwendet wurde
- Welche Kundendaten eingesetzt wurden
- Dass das Dokument nach der Unterschrift nicht veraendert wurde
import * as crypto from 'crypto';
const hash = crypto.createHash('sha256').update(markdown, 'utf-8').digest('hex');S3-Speicherung
Pfad-Schema
s3://prilog-files/avv/{orderId}/AVV_{subdomain}_{YYYY-MM-DD}.pdfBeispiel: avv/ORD-20260422-abc123/AVV_waldorf-weser_2026-04-22.pdf
Fail-Open
Wenn S3 nicht erreichbar ist (Netzwerk-Problem, Credentials falsch), wird der Prozess nicht abgebrochen. Das PDF wird trotzdem generiert und per Mail versendet. Der S3-Upload-Fehler wird geloggt. Beim naechsten Admin-Download wird das PDF on-demand neu generiert.
E-Mail-Versand
MailPace-Integration
Die AVV-Mail wird ueber MailPace (transactional email service) versendet:
- Von:
noreply@prilog.chat - An: Ansprechpartner aus dem Onboarding
- Betreff:
Auftragsverarbeitungsvertrag (AVV) — {Firmenname} - Anhang:
AVV_{subdomain}.pdf(Base64-kodiert im API-Call) - Fallback: Wenn MailPace fehlschlaegt, wird der Fehler geloggt aber der Onboarding-Prozess nicht blockiert
E-Mail-Inhalt
HTML-formatierte Mail mit:
- Begruessung mit Namen
- Hinweis auf die Prilog-Instanz (Subdomain)
- Verweis auf das Portal fuer erneuten Download
- Corporate Footer
API-Endpoints
Oeffentlich (Onboarding)
| Endpoint | Methode | Zweck |
|---|---|---|
POST /api/public/orders | POST | Order anlegen → AVV automatisch generiert |
Der AVV-Prozess wird async nach der Order-Erstellung angestossen. Die Response wartet nicht auf die PDF-Generierung — der Kunde sieht sofort die Success-Page.
Admin (admin.prilog.chat)
| Endpoint | Methode | Zweck |
|---|---|---|
GET /api/admin/avv-consents | GET | Alle AVV-Consent-Logs (letzte 50) |
GET /api/admin/orders/{orderId}/avv | GET | AVV-PDF fuer eine Order herunterladen |
Der PDF-Download versucht zuerst aus S3 zu laden. Wenn das fehlschlaegt (S3 down, Datei geloescht), wird das PDF on-demand aus den gespeicherten Consent-Daten + Order-Daten neu generiert.
Sicherheit und Compliance
DSGVO Art. 28 Abs. 9
"Der Vertrag wird schriftlich abgefasst, was auch in einem elektronischen Format erfolgen kann."
Die Umsetzung erfuellt alle Anforderungen:
| Anforderung | Umsetzung |
|---|---|
| Vollstaendiger Text vor Abschluss einsehbar | PDF-Download-Link im Legal-Step |
| Herunterladen moeglich | Download-Button vor und nach Abschluss |
| Aktive Bestaetigung | Checkbox + "Verbindlich bestellen" Button |
| Vertretungsberechtigung | Checkbox-Text bestaetigt Vertretung |
| Nachweis gespeichert | avv_consent_log mit Hash, IP, Zeitstempel |
| Kopie jederzeit verfuegbar | Admin-Download + Portal-Download + E-Mail |
Audit-Trail
Fuer jede AVV-Zustimmung ist nachweisbar:
- Wer hat zugestimmt (Name, E-Mail)
- Wann (sekundengenauer Zeitstempel)
- Was wurde akzeptiert (Version + Content-Hash)
- Wie (IP-Adresse, Browser User-Agent)
- Wo ist das Dokument archiviert (S3-Pfad)
Erweiterungen (geplant)
| Feature | Beschreibung | Prioritaet |
|---|---|---|
| Portal-Download | AVV unter "Rechtliches" im Kunden-Portal downloadbar | Mittel |
| AVV-Aktualisierung | Bestehende Kunden per Mail bei AVV-Aenderung informieren | Niedrig |
| Digitale Signatur | Qualifizierte elektronische Signatur (eIDAS) | Niedrig |
| PDF/A | Langzeitarchivierungs-Format fuer rechtliche Dokumente | Niedrig |