Files
2026-05-20 09:24:11 +02:00
..
2026-05-20 09:24:11 +02:00
2026-05-20 09:24:11 +02:00
2026-05-20 09:24:11 +02:00
2026-05-20 09:24:11 +02:00
2026-05-20 09:24:11 +02:00
2026-05-20 09:24:11 +02:00
2026-05-20 09:24:11 +02:00

Serienbrief-Backend

Node.js/Express-Backend für das Serienbrief-System auf Basis von Directus (Adressdatenbank) und Gotenberg/Carbone (PDF-Rendering).

Voraussetzungen

  • Docker Engine 27.x, Docker Compose V2
  • Laufende Directus-Instanz mit:
    • Collection sb_templates (siehe Konzept-Dokument)
    • Service-Account-Token mit Lesezugriff auf Kontakt-Collections und sb_templates
  • Gotenberg v8 (oder Carbone, via RENDERER=carbone)
  • PostgreSQL-Instanz für Audit-Log

Schnellstart (Entwicklung)

cp .env.example .env
# .env anpassen (DIRECTUS_TOKEN, AUDIT_DB_* etc.)

npm install
npm run dev

Umgebungsvariablen

Alle Optionen: siehe .env.example

API-Endpunkte

Methode Pfad Auth Beschreibung
GET /health nein Healthcheck
GET /api/sb/templates Bearer Aktive Templates
GET /api/sb/recipients Bearer Empfängerliste
POST /api/sb/render Bearer PDF generieren
GET /api/sb/audit Bearer (Admin) Audit-Log
POST /admin/reload-templates intern Template-Cache leeren

Render-Request

POST /api/sb/render
Authorization: Bearer <directus-user-token>

{
  "templateId": "uuid-aus-sb_templates",
  "collection": "kontakte",
  "recipientIds": [42, 87, 133],
  "extraFields": { "betreff": "Wichtige Information" }
}

Response: application/pdf (Datei-Download)

Template-Syntax (Carbone)

Templates sind ODT- oder DOCX-Dateien mit Carbone-Platzhaltern:

{d.empfaenger[i].vorname} {d.empfaenger[i].nachname}
{d.empfaenger[i].adresse}
{d.empfaenger[i].plz} {d.empfaenger[i].ort}

Datum: {d.meta.datum}
Betreff: {d.meta.betreff}

Sicherheit

  • Service-Account-Token wird als Docker Secret geliefert (/run/secrets/directus_token)
  • User-Bearer-Token wird gegen Directus /users/me validiert
  • Generierte PDFs werden nur im RAM gehalten und direkt gestreamt (keine Persistenz)
  • Audit-Log: INSERT-only (DB-User hat kein UPDATE/DELETE)
  • Container läuft als non-root (UID 1001), read_only: true, cap_drop: ALL

Renderer-Auswahl

Variable Wert Beschreibung
RENDERER gotenberg (default) Carbone merged Template + Daten → Gotenberg konvertiert nach PDF
RENDERER carbone Carbone merged + konvertiert direkt (LibreOffice im Container nötig)

Direktus-Collection sb_templates

Feld Typ Beschreibung
id UUID Primärschlüssel
name String Anzeigename
description String Beschreibung
version String z.B. 2.1
file_id FK → directus_files Template-Datei
active Boolean Nur aktive werden angezeigt
allowed_fields String Kommagetrennte Felder-Allowlist