# 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) ```bash 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 ```json POST /api/sb/render Authorization: Bearer { "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 |