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
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:
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).
|
||||
Reference in new issue
Block a user