docs: Spezifikation Bienenpatenschaft mit automatischer Urkunde
Docker Image bauen und veroeffentlichen / lint (push) Canceled after 0s
Docker Image bauen und veroeffentlichen / typecheck (push) Canceled after 0s
Docker Image bauen und veroeffentlichen / test (push) Canceled after 0s
Docker Image bauen und veroeffentlichen / build-and-push (push) Canceled after 0s

Ersetzt den bisherigen Implementierungsauftrag nach den verbindlichen
Vorgaben vom 2026-10-16: drei Pakete, keine Besuche oder laufenden
Inhalte, Urkunde als deterministisch erzeugte PDF mit Vorschau aus
derselben Layoutberechnung, idempotente Erzeugung nach Zahlung,
Revisionen und Druckablauf im Admin.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-16 07:45:54 +02:00
1 parent 35e7c84767
commit 24df111495
1 file changed
+563
@@ -0,0 +1,563 @@
# Bienenpatenschaft mit automatisch erzeugter Urkunde
Datum: 2026-10-16
Status: Entwurf zur Freigabe, Implementierung ausstehend
Dieses Dokument ersetzt den bisherigen Implementierungsauftrag zur
Bienenpatenschaft vollständig. Grundlage sind die verbindlichen Vorgaben des
Inhabers vom 2026-10-16. Wo ältere Fassungen etwas anderes sagen, gilt dieses
Dokument.
## Problem und Ziel
Wabenhain soll eine symbolische Bienenpatenschaft als Geschenkprodukt
verkaufen. Das zentrale Produkt ist eine hochwertige, persönlich gestaltete
Urkunde. Nach der Bestellung läuft alles automatisch: Zahlung, Erzeugung der
Urkunde, Zustellung des Downloads. Die Handarbeit des Inhabers beschränkt sich
bei physischen Paketen auf Drucken, Verpacken und Versenden.
Erfolg heißt: Eine Testbestellung erzeugt ohne manuelle Nachbearbeitung eine
korrekt personalisierte, optisch hochwertige und druckfähige Urkunde, und der
Käufer bekommt den Download automatisch.
## Nicht im Umfang
Diese Leistungen entfallen vollständig. Sie werden weder auf der
Verkaufsseite noch in E-Mails, Urkunden, FAQs oder Rechtstexten versprochen:
- Besuche beim Imker oder am Bienenstand
- Patentage, Veranstaltungen, Terminbuchungen
- Videos, individuelle Bienenfotos, Saisonberichte, Newsletter zur Patenschaft
- jede Pflicht zur laufenden Erstellung von Inhalten
- Veranstaltungs- oder Teilnehmerverwaltung
- automatische Verlängerung, Abo oder Erinnerungsmails zum Ablauf
- Zusagen zu Naturschutzprojekten oder unbelegte Umweltversprechen
- ein Vorlagen-Auswahlschritt für Kunden (es gibt genau eine Gestaltung)
Die Patenschaftsseite zeigt nur die persönlichen Patenschaftsdaten und den
Download der Urkunde. Sie braucht keine redaktionelle Pflege.
## Produkt
### Pakete
Drei Ausgangspakete, im Adminbereich bearbeitbar (Name, Preis, Beschreibung,
Leistungsliste, aktiv/inaktiv, Reihenfolge):
| Paket | Testpreis | Leistungen | Versand |
|---|---:|---|---|
| Bienenfreund | 19 € | symbolische Namensgebung, individuell gestaltete PDF-Urkunde, sicherer Download | keiner |
| Honigfreund | 39 € | digitale Leistungen, gedruckte Urkunde, 1 × 500 g Honig, Grußkarte, Geschenkverpackung | ja |
| Wabenfreund | 59 € | digitale Leistungen, gedruckte Urkunde, 3 × 500 g Honig, Grußkarte, Geschenkverpackung | ja |
- Die Preise sind Testpreise. Vor Veröffentlichung werden sie kaufmännisch
geprüft (siehe „Geschäftliche Konfiguration vor Veröffentlichung“).
- Alle Pakete bekommen dieselbe Urkunde in derselben Qualität. Sie
unterscheiden sich nur in den physischen Leistungen.
- Die Patenschaft läuft zwölf Monate ab dem gewählten Startdatum und endet
automatisch. Danach zeigt die Patenschaftsseite den Status „abgelaufen“, der
Download bleibt erhalten. Es folgen keine weiteren Leistungen oder Mails.
### Honig im Paket
Jedes physische Paket verweist im Admin auf ein Honigprodukt aus dem
bestehenden Sortiment und auf eine Anzahl Gläser. Die Bestellung reserviert
und bucht den Bestand dieses Produkts über die vorhandene Bestandslogik
(einschließlich ApiCore-Abgleich). Ist das verknüpfte Produkt ausverkauft, ist
das Paket nicht bestellbar und die Verkaufsseite sagt das. Der Inhaber wechselt
die Sorte, indem er im Admin ein anderes Produkt verknüpft.
### Grußkarte
Die Grußkarte ist eine vorgedruckte, nicht personalisierte Karte im
Wabenhain-Design. Persönliche Worte stehen in der Widmung auf der Urkunde.
So entsteht kein Handschreiben pro Bestellung.
## Personalisierung
### Felder
| Feld | Pflicht | Hinweis |
|---|---|---|
| Name der Patenbiene | ja | symbolischer Name |
| Name der Person auf der Urkunde | ja | für wen die Urkunde ausgestellt ist |
| Schenkende | nein | eine oder mehrere Personen, als Freitext („Anna und Ben“) |
| Widmung | nein | wird unverändert übernommen |
| Anlass | ja | für mich selbst, Geburtstag, Weihnachten, Dankeschön, allgemeines Geschenk |
| Startdatum | ja | frühestens am Bestelltag, spätestens sechs Monate danach |
Bei „für mich selbst“ blendet das Formular das Feld „Schenkende“ aus.
### Eingabelimits
Die endgültigen Limits ergeben sich aus der Layout-Testmatrix (siehe
„Prüfung“). Startwerte, die die Testmatrix bestätigen oder verschärfen muss:
- Bienenname: 2–24 Zeichen
- Name auf der Urkunde: 2–60 Zeichen
- Schenkende: bis 80 Zeichen
- Widmung: bis 280 Zeichen und höchstens 5 Zeilenumbrüche
Das Formular zeigt jedes Limit vor der Bestellung als Zeichenzähler an. Server
und Client prüfen mit demselben zod-Schema.
### Zeichen
- Eingaben werden nach Unicode NFC normalisiert, Steuerzeichen entfernt,
Mehrfach-Leerzeichen zusammengefasst.
- Zulässig ist jedes Zeichen, für das die eingebetteten Schriften eine Glyphe
haben. Die Prüfung läuft serverseitig über die Font-Metriken (fontkit).
Fehlt eine Glyphe (zum Beispiel Emoji), lehnt das Formular die Eingabe mit
einer klaren Meldung ab, statt ein Ersatzkästchen zu drucken.
- Umlaute, ß, Akzente, Bindestriche und Apostrophe müssen funktionieren.
## Urkundentext
Der Text entsteht aus hinterlegten, sorgfältig formulierten Bausteinen. Es
gibt keine KI-Anfrage pro Bestellung. Der Kunde sieht den endgültigen Wortlaut
vor dem Kauf in der Vorschau.
### Regeln
- Eigene und verschenkte Patenschaft haben unterschiedliche Formulierungen.
- Geburtstag, Weihnachten und Dankeschön haben je eine kurze, passende
Anlasszeile. „Für mich selbst“ und „allgemeines Geschenk“ haben keine.
- Leere Felder erzeugen keine Platzhalter, keine leeren Zeilen und keine
verwaisten Bezeichnungen wie „Von:“ ohne Namen.
- Keine erfundenen Eigenschaften, Beziehungen oder Ereignisse.
- Keine Geschlechtszuordnung: keine Pronomen, keine Anreden wie „Liebe/Lieber“,
die aus dem Namen abgeleitet wären.
- Keine Formulierung, die eine individuelle Betreuung oder Verfolgung einer
einzelnen Biene behauptet.
- Die Widmung wird wörtlich übernommen. Erlaubt sind nur sichere Darstellung
(kein HTML, kein Markup) und sauberer Umbruch.
### Bausteine (Entwurf, vor Abnahme sprachlich final prüfen)
Überschrift: „Bienenpatenschaft“, darunter klein „Urkunde“.
Anlasszeile über dem Haupttext:
- Geburtstag: „Zum Geburtstag“
- Weihnachten: „Zu Weihnachten“
- Dankeschön: „Als Dankeschön“
- allgemeines Geschenk und für mich selbst: keine Anlasszeile
Haupttext, eigene Patenschaft:
> {Name auf der Urkunde} hat einer Biene der Imkerei Wabenhain symbolisch den
> Namen
> **{Bienenname}**
> gegeben und unterstützt damit die Imkerei und ihre Bienenvölker.
Haupttext, verschenkte Patenschaft:
> Für {Name auf der Urkunde}
> Einer Biene der Imkerei Wabenhain wurde symbolisch der Name
> **{Bienenname}**
> gegeben. Die Patenschaft unterstützt die Imkerei und ihre Bienenvölker.
Schenkende, nur wenn ausgefüllt: „Geschenkt von {Schenkende}“.
Widmung, nur wenn ausgefüllt: als eigener, typografisch abgesetzter Block.
Laufzeit: „Patenschaft vom {Startdatum} bis {Enddatum}“, Enddatum = Startdatum
plus zwölf Monate minus ein Tag, deutsches Langformat.
Kennung: „Nr. {Patenschaftsnummer}“, Format `WH-P-JJJJ-NNNNN`, fortlaufend über
einen eigenen Zähler (wie `InvoiceCounter`).
Hinweis, immer vorhanden und gut lesbar:
> Die Namensgebung ist symbolisch. Sie gilt keiner einzeln begleiteten Biene,
> sondern unterstützt die Imkerei Wabenhain und ihre Bienenvölker.
Englische Texte: Die Seite ist zweisprachig (de/en). Die Urkunde erscheint in
der beim Checkout gewählten Sprache (`Order.locale`). Beide Sprachfassungen
durchlaufen dieselbe Testmatrix.
## Gestaltung
### Anspruch
Die Urkunde soll wie ein rahmenwürdiges Geschenk wirken:
- elegante Typografie mit klarer Hierarchie
- großzügiger Weißraum, ausgewogene Proportionen
- Bienenname und Name auf der Urkunde als gestalterischer Mittelpunkt
- dezente Bienen-, Blüten- oder Wabenillustration als feine Strichgrafik
- zurückhaltende Markenfarben, feine Rahmen oder Ornamente
- harmonisch eingebundene Widmung
- diskrete Patenschaftsnummer und Datumsangaben
- keine Cliparts, keine Office-Vorlagenoptik, keine erfundenen Gütesiegel,
keine Unterschrift
### Markengrundlage
- Schriften: Cormorant Garamond für Überschrift, Namen und Widmung, Inter für
Kleintext (beide schon auf der Website, beide unter SIL Open Font License,
Einbettung in PDF erlaubt). Die TTF-Dateien kommen nach `assets/fonts/` samt
Lizenzdatei.
- Farben aus `src/app/globals.css`: Forest `#24352b` für Text, Honey Dark
`#8a6531` für Akzente und Linien, Honey `#b88a44` nur flächig klein, Sage
`#788774` für Ornamente. Gold erscheint als flache Druckfarbe, nie als
Verlauf oder Folienimitat. Die Urkunde verspricht keine Goldfolie.
- Logo: das hochgeladene Markenlogo (`getBrandAssets`). Für den Druck braucht
es eine SVG-Fassung oder ein PNG mit mindestens 300 dpi in Druckgröße. Liegt
keins vor, nutzt die Urkunde das gezeichnete Waben-Zeichen aus
`lib/brand-icon.ts` als Vektor. Das Logo wird nicht verzerrt, nicht
umgefärbt und nicht nachgezeichnet.
- Papier ist weiß. Die Urkunde hat keine randlosen Farbflächen.
### Drei Varianten, dann eine Entscheidung
Zuerst entstehen drei Varianten mit identischen Beispieldaten:
1. Klassisch-editorial: zentrierte Achse, feiner Doppelrahmen in Honey Dark,
kleine Biene als Strichzeichnung über der Überschrift.
2. Wabe: asymmetrischer Aufbau, feines Hexagon-Linienraster als Eckmotiv,
Namen linksbündig groß.
3. Botanisch: Lindenblüten- oder Kleezweig als Strichillustration, die den
Textblock an zwei Ecken einfasst.
Alle drei werden als echte PDFs gerendert und nebeneinander beurteilt. Die zur
Marke passendste Variante wird vollständig umgesetzt. Die anderen beiden
bleiben nicht im Produktcode.
Illustrationen werden selbst als Vektor gezeichnet (SVG-Pfade, im Code als
Pfaddaten). Es gibt keine fremden Bildrechte und keine Rasterillustrationen.
## Druck- und PDF-Anforderungen
- Format A4 hochkant, genau eine Seite
- Text als echter Text mit eingebetteten Schrift-Teilmengen, Illustrationen
und Rahmen als Vektor
- Rasterbilder (nur das Logo, falls es kein SVG gibt) mit mindestens 300 dpi
in Druckgröße
- sicherer Rand: aller Inhalt mindestens 15 mm vom Blattrand, Rahmenlinien
mindestens 12 mm. Übliche Büro- und Tintenstrahldrucker lassen 3–5 mm frei.
- keine abgeschnittenen Namen, keine Überlagerungen
- kleinste Schrift 8 pt (Kennung und Hinweis), Fließtext mindestens 11 pt
- PDF-Metadaten: Titel „Bienenpatenschaft {Bienenname}“, Autor „Imkerei
Wabenhain“
### Lange Inhalte
Lange Inhalte löst das Layout über definierte Regeln, nicht durch
Verkleinern der ganzen Seite:
1. Layoutvarianten: ohne Widmung (mehr Luft, größere Namen), mit kurzer
Widmung, mit langer Widmung. Die Variante folgt aus der gemessenen Höhe.
2. Kontrollierte Umbrüche: Namen brechen nur an Leerzeichen oder Bindestrich,
höchstens auf zwei Zeilen, nie mitten im Wort. Doppelnamen bleiben möglichst
in einer Zeile.
3. Begrenzte Schriftstufen: jedes Feld hat eine feste Liste von Größen (zum
Beispiel Bienenname 54, 46, 40 pt). Passt der Inhalt auch in der kleinsten
Stufe nicht, ist das ein Validierungsfehler. Die Eingabelimits sind so
gewählt, dass dieser Fall im Betrieb nicht auftritt.
## Architektur
### Ein Layout, zwei Ausgaben
Vorschau und finale PDF müssen identisch umbrechen. Deshalb gibt es genau eine
Layout-Berechnung auf dem Server:
```
Personalisierung + Textbausteine + Vorlagenversion
│
▼
composeCertificateText() → aufgelöste Textblöcke (reine Funktion)
│
▼
layoutCertificate() → positionierte Elemente: Zeilen mit x/y,
Schriftgröße, Schrift, Pfade (reine Funktion,
misst mit fontkit an denselben TTF-Dateien)
│
├──► renderCertificatePdf() pdfkit, Text als Text
└──► renderCertificatePreview() SVG mit Glyphen als Pfade,
per sharp zu WebP gerastert,
mit Wasserzeichen
```
Die Vorschau setzt Glyphen als Pfade aus denselben Schriftdateien an dieselben
Positionen. Sie hängt damit nicht von Browser-Schriften ab, und ein
Umbruchunterschied zwischen Vorschau und PDF ist ausgeschlossen. Ein Test
vergleicht die Zeilen beider Ausgaben.
Module unter `src/lib/certificate/`:
| Modul | Aufgabe |
|---|---|
| `schema.ts` | zod-Schema der Personalisierung, gemeinsam für Client und Server |
| `text.ts` | Bausteine je Sprache, Anlass, eigene/verschenkte Patenschaft |
| `layout.ts` | Messen, Umbrechen, Schriftstufen, Layoutvarianten |
| `templates/` | Vorlagen, je Version eine Datei, alte Versionen bleiben erhalten |
| `render-pdf.ts` | pdfkit-Ausgabe |
| `render-preview.ts` | SVG-Ausgabe und Rasterung mit Wasserzeichen |
| `storage.ts` | Ablage der PDFs (eigenes Verzeichnis, siehe unten) |
| `issue.ts` | Erzeugung nach Zahlung, idempotent, mit Wiederholung |
### Vorlagenversion
Jede Vorlage hat eine feste Kennung, etwa `wabe-classic@1`. Eine
Designänderung erzeugt eine neue Version, die alte bleibt im Code. Neue
Bestellungen nutzen die aktuelle Version. Bereits ausgestellte Urkunden
behalten ihre Version und ihre gespeicherte PDF.
### Datenmodell (Prisma, beide Provider)
- `SponsorshipPackage`: Name, Beschreibung, Leistungsliste, Preis, aktiv,
Reihenfolge, physisch ja/nein, verknüpftes Honigprodukt, Anzahl Gläser,
Steueraufteilung (siehe unten)
- `Sponsorship`: eine je gekaufter Patenschaft. Bezug auf `OrderItem`
(eindeutig, das ist der Idempotenzschlüssel), Patenschaftsnummer, Start- und
Enddatum, Status, Zugriffs-Token als Hash, aktuelle Revision
- `SponsorshipRevision`: unveränderlicher Stand: Personalisierung (JSON),
aufgelöster Text, Vorlagenversion, PDF-Pfad, SHA-256 der PDF, erstellt von
(System oder Admin), Änderungsgrund, Zeitpunkt
- `SponsorshipCounter`: fortlaufende Nummer je Jahr
- Zustellfelder an `Sponsorship`: `pdfAttempts`, `nextAttemptAt`,
`lastError`, `mailSentAt`, `printedAt`
Statuswerte der Patenschaft: `AUSSTEHEND` (bezahlt, PDF noch nicht da),
`FEHLER` (Versuche aufgebraucht, braucht Admin), `BEREIT` (PDF da, Mail
versendet), `GEDRUCKT` (nur physisch). Der Laufzeitstatus aktiv/abgelaufen
wird aus den Daten berechnet, nicht gespeichert.
### Warenkorb und Checkout
- Die Patenschaft kommt als Position in den bestehenden Warenkorb, Menge
immer 1 je Personalisierung. Mehrere Patenschaften sind mehrere Positionen.
- Die Personalisierung reist mit der Warenkorbposition. Der Checkout prüft sie
serverseitig erneut mit demselben Schema und denselben Layoutregeln.
- Bevor die Position in den Warenkorb darf, bestätigt der Kunde: „Ich habe die
Vorschau und die Schreibweise geprüft.“
- Beim Anlegen der Bestellung wird die Personalisierung zusammen mit der
Vorlagenversion als Entwurf an der `OrderItem` gespeichert. Genau dieser
Stand wird nach der Zahlung zur ersten Revision.
- Reine Digitalbestellungen haben keine Versandkosten. Die Rechnungsanschrift
bleibt Pflicht wie heute. Ob dafür ein neuer `FulfillmentMethod`-Wert
`DIGITAL` nötig ist oder `VERSAND` mit 0 € genügt, entscheidet der
Implementierungsplan nach Lesen von Checkout, Rechnung und DHL-Logik.
- Physische Pakete laufen über die bestehenden Versandstaffeln je Kategorie.
Für Patenschaftspakete wird eine eigene Staffel gepflegt.
### Steuer
Ein physisches Paket enthält Leistungen mit unterschiedlichen Steuersätzen
(Urkunde und Leistung, Honig). Das Paket speichert deshalb eine Aufteilung des
Bruttopreises: Honiganteil in Cent zum Honig-Satz, Rest zum Regelsatz. Die
Rechnung zeigt das Paket mit beiden Steuerzeilen. Die vorhandene
Gruppierung nach Steuersätzen in `lib/vat.ts` wird dafür genutzt. Die Methode
der Aufteilung muss die Steuerberatung bestätigen. Ist
Kleinunternehmerregelung aktiv, entfällt die Aufteilung wie heute.
### Ablauf nach der Zahlung
1. Der Stripe-Webhook markiert die Bestellung wie heute über den atomaren
Claim als bezahlt. Nur dieser Lauf legt die `Sponsorship`-Zeilen an
(`create` mit eindeutigem `orderItemId`; ein Duplikat bricht still ab).
2. Danach versucht der Webhook die Erzeugung direkt: Text auflösen, Layout,
PDF rendern, ablegen, Hash und erste Revision speichern.
3. Die Bestellbestätigung enthält den Downloadlink. Der Versand der Mail wird
über `updateMany … where mailSentAt = null` beansprucht, damit doppelte
Webhooks keine zweite Mail erzeugen. Erst nach erfolgreichem Versand wird
der Status `BEREIT`.
4. Scheitert die Erzeugung, antwortet der Webhook trotzdem 200 (die Zahlung
ist erfolgt, wie bei der Rechnung heute). Die Patenschaft bleibt
`AUSSTEHEND` mit `nextAttemptAt`. Die Bestätigungsmail sagt dann: „Ihre
Urkunde wird gerade erstellt, der Link folgt in einer eigenen Mail.“
5. Ein neuer CronJob `wabenhain-certificates` (alle 10 Minuten,
`concurrencyPolicy: Forbid`, wie die bestehenden Jobs in
`k8s/07-backup-cronjob.yaml`) holt offene Erzeugungen und offene Mails
nach. Wiederholung mit wachsendem Abstand, höchstens 8 Versuche, danach
`FEHLER` und Hinweis im Admin-Dashboard (bestehende Aufmerksamkeitsliste).
Die finale Urkunde entsteht nie vor bestätigter Zahlung. Async-Zahlarten
(SEPA) erzeugen sie erst bei `async_payment_succeeded`.
### Ablage
PDFs liegen in einem eigenen Verzeichnis `CERTIFICATE_DIR`, nicht unter
`UPLOAD_DIR`, weil die Upload-Route alles ohne Anmeldung ausliefert. Die
Startprüfung aus `lib/invoice-storage.ts` (Verzeichnis darf nicht im
Upload-Verzeichnis liegen) wird übernommen. Das Verzeichnis kommt auf das
gesicherte Volume und in den Sicherungs-CronJob.
### Download und Patenschaftsseite
- Der Link enthält ein zufälliges Token mit mindestens 128 Bit. Gespeichert
wird nur der SHA-256-Hash. Die URL enthält keine Namen und keine
Bestellnummer.
- `/patenschaft/<token>` zeigt Bienenname, Name auf der Urkunde, Laufzeit,
Status aktiv/abgelaufen und den Download. Keine Anschrift, keine
Bestelldaten. `noindex`, Rate-Limit über `lib/rate-limit.ts`.
- Angemeldete Kunden sehen ihre Patenschaften zusätzlich unter „Konto“.
- Der Download liefert immer die gespeicherte PDF der aktuellen Revision. Es
wird nicht neu gerendert.
- Der Link darf an Beschenkte weitergegeben werden. Er zeigt nur, was ohnehin
auf der Urkunde steht.
### QR-Code
Die Urkunde bekommt keinen QR-Code. Er brächte kaum Nutzen, stört die
Gestaltung, und ein QR-Code zur Patenschaftsseite würde den Downloadlink
jedem öffnen, der ein Foto der gerahmten Urkunde sieht.
### Vorschau
- Endpunkt `POST /api/patenschaft/vorschau`: nimmt die Personalisierung,
prüft sie, gibt ein WebP zurück. Rate-Limit je Besucher.
- Die Vorschau trägt sichtbar „Unverbindliche Vorschau“ als Wasserzeichen und
hat nur Bildschirmauflösung. Sie ersetzt so nicht die gekaufte PDF.
- Der Client fordert sie mit Verzögerung nach der letzten Eingabe an (etwa
400 ms) und zeigt bis dahin die letzte gültige Vorschau.
## Adminbereich
### Pakete
Pakete bearbeiten wie Produkte: Name, Preis, Beschreibung, Leistungen, aktiv,
Honigprodukt, Gläser, Steueraufteilung.
### Patenschaften
Liste mit Filtern nach Status (ausstehend, Fehler, bereit, zu drucken,
gedruckt) und Paket. Detailansicht:
- Vorschau der aktuellen Revision, Liste aller Revisionen
- „Druck-PDF öffnen“: dieselbe gespeicherte PDF, die der Kunde bekommt
- „Als gedruckt markieren“ (nur physisch)
- „Erneut erzeugen“ bei Status `FEHLER` (gleiche Vorlagenversion)
- „Mail erneut senden“
### Korrektur
1. Admin öffnet „Korrigieren“, ändert Felder im selben Formular wie der Kunde.
2. Die Vorschau zeigt das Ergebnis mit derselben Layoutlogik.
3. Speichern verlangt einen Änderungsgrund.
4. Es entsteht eine neue `SponsorshipRevision` mit neuer PDF. Die alte bleibt
erhalten und ist abrufbar.
5. `logAdminAction` schreibt den Vorgang ins Audit-Log (wer, wann, welche
Felder, Grund).
6. Optional per Häkchen: Mail an den Käufer „Ihre korrigierte Urkunde“.
Eine Korrektur nutzt standardmäßig die Vorlagenversion der bisherigen
Revision. Ein Wechsel auf die aktuelle Version ist eine bewusste Auswahl im
Formular.
### Druckablauf
Physische Bestellungen erscheinen nach der Zahlung in der Liste „zu drucken“.
Der Inhaber öffnet die PDF, druckt sie auf festem Papier, markiert sie als
gedruckt und versendet die Bestellung wie heute über DHL. Mehr Schritte gibt
es nicht.
## Verkaufsseite
Route `/patenschaft`, zweisprachig, im bestehenden Design der Website.
Im Mittelpunkt stehen:
- einer Biene symbolisch einen eigenen Namen geben
- ein persönlich gestaltetes Geschenk
- die regionale Imkerei Wabenhain unterstützen
- je nach Paket eigenen Wabenhain-Honig verschenken
Aufbau:
1. Kopfbereich mit großer, echter Urkundenvorschau als zentrales Element
2. Paketwahl mit klarer Leistungsliste, Preis und Versandkosten
3. Personalisierung in Schritten: Paket, für wen und Anlass, Namen, Widmung
und Startdatum, Vorschau prüfen
4. Hinweis zur symbolischen Namensgebung, gut sichtbar und nicht im Kleingedruckten
5. FAQ
Auf dem Smartphone steht die Vorschau über dem jeweiligen Schritt. Ein Tipp
vergrößert sie auf volle Breite. Eingabefelder haben mindestens 16 px
Schriftgröße (kein Zoom unter iOS), Bedienelemente mindestens 44 px.
FAQ-Themen: Was bedeutet symbolische Namensgebung? Wie lange läuft die
Patenschaft? (zwölf Monate, endet automatisch, kein Abo) Wann kommt die
Urkunde? (digital direkt nach Zahlung, gedruckt mit dem Paket) Was ist im
Paket? Was kostet der Versand? Was, wenn ich mich vertippt habe? (Kontakt,
Korrektur durch Wabenhain) Keine FAQ verspricht Besuche, Berichte, Fotos oder
Umweltwirkungen.
## Prüfung
### Layout-Testmatrix
Automatisierte Tests rendern echte PDFs und prüfen die Layoutdaten (keine
Überlappung von Elementboxen, alles innerhalb der Sicherheitszone, Schrift nie
unter Mindestgröße, genau eine Seite) für:
- sehr kurze Namen („Li“, „Bo“)
- maximal lange Namen in beiden Feldern
- Doppelnamen („Marie-Luise Schmidt-Habermann“)
- Umlaute und Sonderzeichen („Jürgen Weiß“, „Zoë“, „Ñúñez“, „O’Brien“)
- mehrere Schenkende („Anna, Ben, Carla und Familie Özdemir“)
- ohne Widmung
- maximal lange Widmung, auch mit allen erlaubten Zeilenumbrüchen
- jeden Anlass, eigene und verschenkte Patenschaft, Deutsch und Englisch
- Vorschau und PDF ergeben dieselben Zeilen
Die Matrix legt die endgültigen Eingabelimits fest. Sie stehen danach im
Schema und im Formular.
### Visuelle Kontrolle
Die erzeugten PDFs werden gerastert (300 dpi) und angesehen: die ganze Seite
und Ausschnitte bei hoher Vergrößerung (Namen, Widmung, Ornament, Kleintext).
Layoutfehler werden vor Abschluss behoben. Ein Probedruck auf einem
Bürodrucker gehört dazu.
### Ablauftests
- Webhook doppelt zugestellt: eine Patenschaft, eine Mail
- PDF-Erzeugung schlägt fehl: Webhook 200, CronJob holt nach, Status wird `BEREIT`
- Mailversand schlägt fehl: CronJob holt nach, keine Doppelmail
- Fremdes oder falsches Token: 404 ohne Hinweis auf Existenz
- Korrektur: neue Revision, alte unverändert, Audit-Eintrag vorhanden
- Vorlagenversion erhöht: alte Urkunden liefern unverändert ihre PDF
- E2E (Playwright): Paket wählen, personalisieren, Vorschau, Checkout mit
Stripe-Testkarte, Downloadseite, PDF abrufbar
Die Repo-Skripte `lint`, `typecheck`, `test` und `build` laufen grün.
## Abnahme
Fertig ist die Funktion, wenn eine Testbestellung ohne manuelle Nacharbeit
eine korrekt personalisierte, hochwertige und druckfähige Urkunde erzeugt.
Zum Abschluss werden gezeigt:
1. Verkaufsseite und Personalisierung auf Desktop und bei 390 px mobil
2. die drei Designvarianten und die gewählte Gestaltung
3. mehrere echte PDF-Ausgaben mit unterschiedlichen Beispieldaten
4. der automatische Ablauf vom Kauf bis zum Download
5. Druck- und Korrekturablauf im Adminbereich
6. die offene geschäftliche Konfiguration (Liste unten)
## Geschäftliche Konfiguration vor Veröffentlichung
Diese Punkte entscheidet der Inhaber. Die Software ist ohne sie fertig,
veröffentlicht wird erst danach.
1. Preise kaufmännisch prüfen: Honig, Papier, Verpackung, Grußkarte,
Stripe-Gebühren, Arbeitszeit je Paket.
2. Steueraufteilung der physischen Pakete mit der Steuerberatung abstimmen.
3. AGB und Widerrufsbelehrung anpassen: Ausschluss des Widerrufs für nach
Kundenangaben angefertigte Waren (§ 312g Abs. 2 Nr. 1 BGB), Zustimmung zum
sofortigen Beginn bei digitalen Inhalten (§ 356 Abs. 5 BGB), Behandlung
des Honiganteils. Rechtlich prüfen lassen.
4. Datenschutzerklärung ergänzen: Namen Dritter (Beschenkte, Schenkende),
Speicherdauer der Personalisierung und der PDFs.
5. Versandstaffel für Patenschaftspakete im Admin anlegen.
6. Logo als SVG oder PNG mit mindestens 300 dpi hochladen.
7. Material bevorraten: Urkundenpapier (Empfehlung 200–250 g/m², matt,
naturweiß), Geschenkverpackung, vorgedruckte Grußkarten. Probedruck auf dem
eigenen Drucker freigeben.
8. Bestellschluss für Weihnachten festlegen und auf der Verkaufsseite nennen.
9. Bausteintexte sprachlich final freigeben (de und en).