Abo-Stufen 1 bis 24 je bezahltem Monat, danach VIP. SEPA fuer Abos mit Neukunden-Frist, Verzug und Sperre nach Rueckbuchung. Stripe-Einrichtung erst im Testmodus per Skript, Livemodus nur nach Freigabe. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
40 KiB
Bienenpatenschaft: Urkunde, Abo, Medaillen und 3D-Ansicht im Konto
Datum: 2026-10-16 Status: Entwurf zur Freigabe, Implementierung ausstehend Gitea: #31
Dieses Dokument ersetzt den bisherigen Implementierungsauftrag zur Bienenpatenschaft vollständig. Grundlage sind die verbindlichen Vorgaben des Inhabers vom 2026-10-16 und seine Ergänzungen vom selben Tag (Abo, Kundenkonto, 3D-Ansicht, Medaillen, Treuestufen, Übertragung). Wo ältere Fassungen etwas anderes sagen, gilt dieses Dokument.
Problem und Ziel
Wabenhain verkauft symbolische Bienenpatenschaften als Geschenk oder für sich selbst, einmalig bezahlt oder als monatliches Abo. Das zentrale Produkt ist eine hochwertige, persönlich gestaltete Urkunde. Im Kundenkonto erleben Kunden ihre Urkunde und ihre Medaillen in einer interaktiven 3D-Ansicht und laden alles herunter.
Nach dem Kauf läuft alles automatisch: Zahlung, Urkunde, Medaillen, Abo-Abrechnung, Rechnungen, Lieferaufträge für den Abo-Honig. Die Handarbeit des Inhabers beschränkt sich auf Drucken, Verpacken und Versenden.
Erfolg heißt: Eine Testbestellung erzeugt ohne manuelle Nachbearbeitung eine korrekt personalisierte, hochwertige und druckfähige Urkunde, die sofort im Konto in 3D erscheint. Ein Test-Abo rechnet monatlich ab und erzeugt die Honiglieferung erst, wenn sie bezahlt ist.
Teilprojekte und Reihenfolge
Der Umfang ist zu groß für einen Plan. Jedes Teilprojekt bekommt einen eigenen Umsetzungsplan und wird einzeln geprüft und ausgerollt:
| Nr. | Teilprojekt | Hängt ab von | Schätzung |
|---|---|---|---|
| 1 | Urkunde, Einmal-Patenschaft, Kontopflicht, Kontobereich mit Downloads, Admin (Druck, Korrektur) | – | 4–5 Tage |
| 2 | 3D-Ansicht von Urkunde und Medaille, Patenschafts-Medaillen je Paket, „Alles herunterladen“ | 1 | 3–4 Tage |
| 3 | Übertragung an Beschenkte per befristetem Link | 1 | 1 Tag |
| 4 | Abo: Stripe-Abrechnung, Kündigungsbutton, Lieferzyklen, Honigkontingent, Rechnungen | 1 | 5–7 Tage |
| 5 | Treuestufen: Stammkunden-Stufen, Abo-Stufen, VIP | 2, 4 | 2 Tage |
Teilprojekt 1 ist allein verkaufsfähig. Jedes weitere macht das Angebot reicher, ohne das vorherige umzubauen.
Nicht im Umfang
Diese Leistungen entfallen. 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
- jede Pflicht zur laufenden Erstellung von Inhalten
- Veranstaltungs- oder Teilnehmerverwaltung
- Zusagen zu Naturschutzprojekten oder unbelegte Umweltversprechen
- ein Vorlagen-Auswahlschritt für Kunden (es gibt genau eine Gestaltung)
- Gastbestellungen von Patenschaften
Später möglich, jetzt nicht gebaut: Bilder oder andere Medien im Patenschaftsbereich des Kontos. Das Datenmodell lässt dafür Platz (siehe „Erweiterbarkeit“), es gibt aber keine Oberfläche und kein Versprechen.
Angebote
Alle Angebote sind im Admin pflegbar: Name, Beschreibung, Leistungsliste, Preis, aktiv/inaktiv, Reihenfolge, verknüpftes Honigprodukt, Gläser, Steueraufteilung, Medaillenstufe. Es kann beliebig viele Angebote beider Arten geben.
Einmal-Patenschaften
| Paket | Testpreis | Leistungen | Versand |
|---|---|---|---|
| Bienenfreund | 19 € | symbolische Namensgebung, PDF-Urkunde, Medaille, Konto mit 3D-Ansicht und Downloads | 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 |
- Laufzeit zwölf Monate ab Startdatum, endet automatisch.
- Nach Ablauf trägt die Urkunde weiter ihr Von-bis-Datum. Urkunde, Medaille und Downloads bleiben im Konto verfügbar.
- Alle Pakete bekommen dieselbe Urkunde in derselben Qualität. Sie unterscheiden sich in den physischen Leistungen und in der Medaillenstufe.
Abo-Patenschaften
Zwei Ausgangsangebote, Preise vom Inhaber festzulegen:
| Angebot | Zahlung | Honig | Lieferung |
|---|---|---|---|
| Patenschaft im Abo, vierteljährlich | monatlich | z. B. 2 × 500 g je Lieferung | nach jeweils 3 bezahlten Monaten |
| Patenschaft im Abo, nach der Ernte | monatlich | z. B. 3 × 500 g je Lieferung | in den Erntefenstern, frühestens nach 6 bezahlten Monaten seit der letzten Lieferung |
- Monatlich kündbar zum Ende des bezahlten Monats.
- Versand ist im Monatspreis enthalten. Die Verkaufsseite sagt das deutlich.
- Ein Abo gilt einer Biene mit einem Namen und hat eine Urkunde.
- Abo und Einmalkauf werden getrennt bezahlt (eigene Stripe-Sitzung je Abo).
- Ein Abo lässt sich in dieser Fassung nicht übertragen, weil die Zahlung am Konto des Käufers hängt.
Grußkarte
Vorgedruckt, nicht personalisiert, im Wabenhain-Design. Persönliche Worte stehen in der Widmung auf der Urkunde. So entsteht kein Handschreiben.
Kundenkonto ist Pflicht
- Patenschaften kauft nur, wer angemeldet ist. Das betrifft Einmal- und Abo-Angebote. Für andere Produkte bleibt die Gastbestellung wie heute.
- Die Personalisierung lässt sich ohne Anmeldung ausprobieren, samt Vorschau.
Beim Klick auf „In den Warenkorb“ oder „Abo abschließen“ führt die Seite zur
Anmeldung oder Registrierung. Die Eingaben bleiben dabei erhalten
(Entwurf im
sessionStorage, nach der Anmeldung zurückgeschrieben). - Der Checkout prüft serverseitig, dass ein Konto angemeldet ist, sobald eine Patenschaft im Warenkorb liegt.
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 | Einmal: frühestens Bestelltag, spätestens sechs Monate danach. Abo: Tag der ersten Zahlung |
Bei „für mich selbst“ blendet das Formular „Schenkende“ aus.
Eingabelimits
Die endgültigen Limits ergeben sich aus der Layout-Testmatrix. Startwerte:
- 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 klarer Meldung ab, statt ein Ersatzkästchen zu drucken.
- Umlaute, ß, Akzente, Bindestriche und Apostrophe funktionieren.
Urkundentext
Der Text entsteht aus hinterlegten 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 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 aus dem Namen abgeleiteten Anreden.
- Keine Formulierung, die eine individuelle Betreuung oder Verfolgung einer einzelnen Biene behauptet.
- Die Widmung wird wörtlich übernommen, nur sicher dargestellt (kein HTML, kein Markup) und sauber umbrochen.
Bausteine (Entwurf, vor Abnahme sprachlich final prüfen)
Überschrift: „Bienenpatenschaft“, darunter klein „Urkunde“.
Anlasszeile: „Zum Geburtstag“, „Zu Weihnachten“, „Als Dankeschön“.
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: eigener, typografisch abgesetzter Block.
Laufzeit:
- Einmal: „Patenschaft vom {Start} bis {Ende}“, Ende = Start plus zwölf Monate minus ein Tag.
- Abo, aktiv: „Patenschaft seit {Start}“.
- Abo, gekündigt: „Patenschaft vom {Start} bis {Ende}“, Ende = letzter bezahlter Tag. Diese Fassung entsteht automatisch als neue Revision, sobald die Kündigung wirksam wird (siehe „Abo“).
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.
Sprache: Die Urkunde erscheint in der beim Kauf gewählten Sprache (de/en). Beide Fassungen durchlaufen dieselbe Testmatrix.
Gestaltung der Urkunde
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 stehen unter der SIL Open Font License und dürfen in PDFs
eingebettet werden. Die TTF-Dateien kommen samt Lizenz nach
assets/fonts/. - Farben aus
src/app/globals.css: Forest#24352bfür Text, Honey Dark#8a6531für Akzente und Linien, Honey#b88a44nur klein, Sage#788774für Ornamente. Gold ist auf Papier eine flache Druckfarbe, nie Verlauf oder Folienimitat. Die Urkunde verspricht keine Goldfolie. - Logo: das hochgeladene Markenlogo (
getBrandAssets), für den Druck als SVG oder als PNG mit mindestens 300 dpi in Druckgröße. Fehlt es, nutzt die Urkunde das gezeichnete Waben-Zeichen auslib/brand-icon.ts. Das Logo wird nicht verzerrt, umgefärbt oder nachgezeichnet. - Weißes Papier, keine randlosen Farbflächen.
Drei Varianten, dann eine Entscheidung
Zuerst entstehen drei Varianten mit identischen Beispieldaten:
- Klassisch-editorial: zentrierte Achse, feiner Doppelrahmen in Honey Dark, kleine Biene als Strichzeichnung über der Überschrift.
- Wabe: asymmetrischer Aufbau, feines Hexagon-Linienraster als Eckmotiv, Namen linksbündig groß.
- 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 passendste Variante wird vollständig umgesetzt. Die anderen bleiben nicht im Produktcode. Illustrationen werden selbst als Vektor gezeichnet. Es gibt keine fremden Bildrechte und keine Rasterillustrationen.
Druck- und PDF-Anforderungen
- A4 hochkant, genau eine Seite
- Text als echter Text mit eingebetteten Schrift-Teilmengen, Illustrationen und Rahmen als Vektor
- Rasterbilder (nur das Logo, falls kein SVG) mit mindestens 300 dpi
- sicherer Rand: Inhalt mindestens 15 mm vom Blattrand, Rahmenlinien mindestens 12 mm
- keine abgeschnittenen Namen, keine Überlagerungen
- kleinste Schrift 8 pt (Kennung, Hinweis), Fließtext mindestens 11 pt
- PDF-Metadaten: Titel „Bienenpatenschaft {Bienenname}“, Autor „Imkerei Wabenhain“
Lange Inhalte löst das Layout über Regeln, nicht durch Verkleinern der ganzen Seite:
- Layoutvarianten: ohne Widmung, mit kurzer Widmung, mit langer Widmung. Die Variante folgt aus der gemessenen Höhe.
- Kontrollierte Umbrüche: Namen brechen nur an Leerzeichen oder Bindestrich, höchstens auf zwei Zeilen, nie mitten im Wort.
- Begrenzte Schriftstufen: jedes Feld hat eine feste Liste von Größen (zum Beispiel Bienenname 54, 46, 40 pt). Passt der Inhalt in der kleinsten Stufe nicht, ist das ein Validierungsfehler. Die Eingabelimits verhindern diesen Fall im Betrieb.
Medaillen und Treuestufen
Es gibt drei Arten von Medaillen. Alle werden deterministisch als Vektor erzeugt (SVG), im Konto in 3D gezeigt und als PNG (2048 px, transparent) und SVG heruntergeladen. Auf dem Bildschirm dürfen Medaillen metallisch glänzen. Das betrifft nur die digitale Darstellung, nicht den Druck.
1. Patenschafts-Medaille (Teilprojekt 2)
- Eine je Patenschaft, mit Bienenname, Jahr und Patenschaftsnummer.
- Die Stufe richtet sich nach dem Angebot: Bienenfreund, Honigfreund und Wabenfreund haben eigene Prägung und eigenes Metall (zum Beispiel Bronze, Silber, Gold). Abo-Angebote haben eine eigene Prägung. Die Zuordnung ist am Angebot im Admin einstellbar.
- Sie gehört zur Patenschaft und bleibt dauerhaft, auch nach Ablauf oder Kündigung. Bei einer Übertragung wandert sie mit.
2. Stammkunden-Stufen (Teilprojekt 5)
- Für alle Kunden mit Konto, über den ganzen Shop.
- Grundlage: Anzahl bezahlter, nicht erstatteter oder stornierter Bestellungen. Abo-Monatszahlungen zählen hier nicht, sie haben eigene Stufen.
- Stufen und Schwellen im Admin pflegbar. Vorschlag: „Blütenbesuch“ ab 2, „Wabenbau“ ab 5, „Honigschatz“ ab 10, „Goldwabe“ ab 25 Bestellungen.
- Die Stufe bleibt, sie sinkt nur, wenn Bestellungen erstattet oder storniert werden.
3. Abo-Stufen und VIP (Teilprojekt 5)
- Grundlage: ununterbrochen bezahlte Abo-Monate.
- Vorgabe: Stufe 1 bis 24, je bezahltem Monat eine Stufe, danach eine Stufe ohne Zahl, „VIP“, als Zeichen besonders hoher Wertschätzung. Die Schwellen sind im Admin pflegbar und lassen sich ohne Codeänderung anpassen.
- VIP bekommt eine eigene Medaille und eine VIP-Kennzeichnung im Konto. Weitere Vorteile (Rabatt, Versand) gehören nicht zum Umfang und lassen sich später über die bestehenden Rabattcodes ergänzen.
- Wird das Abo gekündigt, verschwindet die Abo-Stufe samt Medaille, sobald die Kündigung wirksam ist. Ein neues Abo beginnt wieder bei null.
- Ausfälle durch fehlgeschlagene Zahlung unterbrechen die Dauer nur, wenn das Abo deshalb endet.
Stufen werden aus den Daten berechnet, nicht als Zustand gespeichert. So gibt es keine Abweichung zwischen Stufe und tatsächlichen Bestellungen oder Zahlungen.
Kontobereich „Patenschaft“
Neuer Bereich /konto/patenschaft neben „Bestellungen“ und „Wunschliste“.
Übersicht
- alle Patenschaften des Kontos mit Bienenname, Art (einmalig/Abo), Laufzeit und Status (aktiv, abgelaufen, gekündigt)
- Medaillenleiste: Patenschafts-Medaillen, aktuelle Stammkunden-Stufe, aktuelle Abo-Stufe oder VIP
- bei Abos: nächste Abbuchung, nächste Lieferung, Fortschritt bis zur nächsten Lieferung („2 von 3 Monaten bezahlt“), Kündigungsbutton
Detail einer Patenschaft
- 3D-Ansicht der eigenen Urkunde und der Patenschafts-Medaille (Teilprojekt 2; in Teilprojekt 1 eine statische Ansicht)
- Downloads: Urkunde (PDF), Medaille (PNG, SVG), „Alles herunterladen“ (ZIP)
- Revisionen sind für Kunden nicht sichtbar. Sie sehen immer die aktuelle Fassung.
- Menüpunkt „Übertragen“ (nur Einmal-Patenschaften, Teilprojekt 3)
3D-Ansicht (Teilprojekt 2)
Ziel: Die Ansicht soll beeindrucken und sich hochwertig anfühlen, ohne die Urkunde zu verfälschen.
- Technik: three.js mit
@react-three/fiberund@react-three/drei, nur auf dieser Seite und erst im Browser geladen (dynamischer Import), damit der übrige Shop nicht schwerer wird. - Urkunde als Papierblatt mit leichter Wölbung, weichem Schatten und einem langsam wandernden Lichtreflex. Die Textur ist ein hochaufgelöstes Bild (2048 px breit) derselben Revision, aus demselben Layout wie die PDF und ohne Wasserzeichen. Sie wird nur angemeldeten Besitzern ausgeliefert.
- Rückseite der Urkunde: Wabenhain-Zeichen und Patenschaftsnummer.
- Medaille als Münze mit Rand und erhabener Prägung (SVG-Pfade extrudiert), Metall mit Umgebungsspiegelung. Die Umgebungstextur liegt lokal im Projekt, kein Abruf von fremden Servern.
- Bewegung: im Ruhezustand sanftes Schweben und Drehen. Der Mauszeiger neigt das Blatt leicht. Ziehen dreht mit Nachschwung. Doppelklick oder Doppeltippen wendet Urkunde oder Medaille. Zoom per Mausrad oder Zwei-Finger- Geste, begrenzt.
- Smartphone: Wischen dreht, Neigen des Geräts bewegt die Szene erst nach einem Tipp auf „Bewegung aktivieren“ (iOS verlangt die Erlaubnis).
prefers-reduced-motion: kein Schweben, keine automatische Drehung, Ziehen bleibt möglich.- Ohne WebGL oder bei Fehlern: statisches Bild der Urkunde und der Medaille, Downloads funktionieren unverändert.
- Leistung: Pixeldichte höchstens 2, Darstellung pausiert, wenn der Tab im Hintergrund oder die Szene außer Sicht ist. Ziel 60 fps auf einem Mittelklasse-Smartphone.
- Bedienbarkeit: Tastatur dreht (Pfeiltasten) und wendet (Leertaste), die Szene hat eine Textbeschreibung für Screenreader, alle Downloads sind normale Links.
Erweiterbarkeit
Sponsorship bekommt später eine Medienliste. Die Detailseite ist so
aufgebaut, dass ein weiterer Abschnitt („Bilder“) ohne Umbau hinzukommen
kann. In diesem Auftrag wird dafür nichts gebaut.
Übertragung an Beschenkte (Teilprojekt 3)
Nur Einmal-Patenschaften lassen sich übertragen.
- Der Besitzer wählt im Menü der Patenschaft „Übertragen“.
- Er wählt die Gültigkeit des Links: 24 Stunden, 1 Woche oder 30 Tage.
- Ein Bestätigungsdialog fragt: „Möchtest du den Übertragungslink wirklich erstellen? Jede Person, die diesen Link hat, kann die Patenschaft in ihr Konto übernehmen. Gib ihn nur an die beschenkte Person weiter. Die Weitergabe geschieht auf eigene Verantwortung.“ (Wortlaut rechtlich prüfen.)
- Erst nach Bestätigung entsteht der Link. Er ist einmal nutzbar, enthält ein zufälliges Token mit mindestens 128 Bit, gespeichert wird nur dessen Hash.
- Bis zur Einlösung sieht der Besitzer den offenen Link mit Ablaufzeit und kann ihn widerrufen.
- Die beschenkte Person öffnet den Link, meldet sich an oder registriert sich und bestätigt die Übernahme. Danach gehören Urkunde, Medaille und Downloads ihrem Konto. Beim bisherigen Besitzer verschwindet die Patenschaft aus dem Bereich „Patenschaft“. Bestellung und Rechnung bleiben bei ihm.
- Abgelaufene, widerrufene oder eingelöste Links zeigen eine neutrale Meldung ohne Daten der Patenschaft.
- Jede Übertragung steht im Audit-Log (erstellt, widerrufen, eingelöst, von welchem Konto an welches).
Eine Übertragung verändert die Urkunde nicht. Die Stammkunden-Stufe zählt den Kauf weiter beim Käufer.
Abo (Teilprojekt 4)
Abrechnung
- Stripe Billing: Jedes Abo-Angebot hat einen Stripe-Preis, der beim Speichern im Admin angelegt wird. Eine Preisänderung erzeugt einen neuen Stripe-Preis für neue Abos. Laufende Abos behalten ihren Preis.
Customerbekommt einestripeCustomerId.- Der Abschluss läuft über eine Stripe-Checkout-Sitzung im Modus
subscription. - Neue Webhook-Ereignisse:
customer.subscription.created,customer.subscription.updated,customer.subscription.deleted,invoice.paid,invoice.payment_failed. Jedes Ereignis wird über die Stripe-ID idempotent verarbeitet. - Jede bezahlte Monatsrechnung erzeugt eine Wabenhain-Rechnung im bestehenden Rechnungssystem (Nummernkreis, PDF, E-Rechnung) und eine Mail.
- Zahlungsart ändern: über das Stripe-Kundenportal, nur für die Zahlungsart.
Schutz vor Verlust: Lieferung erst nach Bezahlung
Der Kunde kann monatlich kündigen, bekommt aber nie mehr Honig, als er bezahlt hat:
- Vierteljährlich: Der Anspruch auf eine Lieferung entsteht nach jeweils drei bezahlten Monaten. Wer nach zwei Monaten kündigt, hatte zwei Monate Patenschaft, aber keinen Honig.
- Nach der Ernte: Der Inhaber legt im Admin die Erntefenster fest. Geliefert wird im nächsten Fenster, sobald seit der letzten Lieferung mindestens sechs Monate bezahlt sind.
- Bezahlt heißt: Stripe meldet die Rechnung als bezahlt, bei SEPA zusätzlich die Regeln unter „SEPA-Lastschrift und Rückbuchungen“.
- Fehlgeschlagene Zahlung: Stripe versucht es automatisch erneut. Solange das Abo im Verzug ist, entsteht keine Lieferung. Scheitern alle Versuche, endet das Abo wie bei einer Kündigung.
- Die Verkaufsseite und die Abo-Bedingungen sagen klar: „Der Honig wird nach jeweils drei bezahlten Monaten verschickt“ beziehungsweise die entsprechende Regel für die Ernte-Variante.
- Widerruf innerhalb von 14 Tagen: Bis dahin ist kein Honig verschickt, es entsteht kein Warenverlust.
SEPA-Lastschrift und Rückbuchungen
Abos lassen sich mit Karte, Apple Pay, Google Pay und SEPA-Lastschrift bezahlen.
Grenze, die keine Einstellung aufhebt: Bei einer SEPA-Lastschrift kann der Kunde acht Wochen lang ohne Angabe von Gründen bei seiner Bank die Erstattung verlangen, bei einer nicht autorisierten Lastschrift 13 Monate lang. Das ist Bankrecht. Stripe kann es nicht verhindern und solche Rückbuchungen nicht anfechten. Stripe berechnet dafür außerdem eine Gebühr. Der Schutz liegt deshalb in der Lieferlogik von Wabenhain:
- Lieferung nur gegen bezahlte Monate (siehe oben). Eine Rückbuchung kann höchstens Honig betreffen, der schon bezahlt erschien.
- Neukunden-Frist: Bei SEPA zählt die erste Abo-Zahlung eines Kontos erst nach einer Frist für den Lieferanspruch. Vorgabe 56 Tage, also die Acht-Wochen-Frist. Die erste Lieferung kommt dadurch bei SEPA etwas später, alle weiteren normal. Die Frist ist im Admin einstellbar (0 schaltet sie ab). Die Verkaufsseite nennt sie bei der Zahlart.
- Rückbuchung erkannt (
charge.dispute.created, im Webhook schon abonniert): Das Abo geht sofort aufIM_VERZUG, offene Lieferungen werden gestoppt und ihre Reservierung freigegeben, die Abo-Stufe ruht. Der Kunde bekommt eine Mail mit der Bitte, den Betrag zu begleichen. Der Fall erscheint in der Aufmerksamkeitsliste. - Wird der Betrag nicht binnen 14 Tagen bezahlt, endet das Abo wie bei einer Kündigung. Der Anspruch auf den Betrag bleibt bestehen. Ob er eingefordert wird, entscheidet der Inhaber.
- Ein Konto mit einer Rückbuchung kann neue Abos nur noch mit Karte oder Wallet abschließen. Der Admin kann diese Sperre aufheben.
Stripe-Einrichtung
Die Einrichtung erfolgt in Teilprojekt 4, zuerst im Testmodus, dann
identisch im Livemodus. Was per API geht, legt ein Einrichtungsskript im Repo
an (wiederholbar, ohne Geheimnisse im Code). Was nur im Dashboard geht,
steht als Checkliste in docs/EINRICHTUNG.md.
- Zahlarten für Abo-Checkout: Karte, Apple Pay, Google Pay, SEPA-Lastschrift (Mandat wird im Checkout erteilt).
- Billing: Smart Retries für fehlgeschlagene Zahlungen, nach dem letzten Versuch Abo kündigen. Stripe-eigene Kundenmails zu Rechnungen aus, weil Wabenhain eigene Rechnungen und Mails schickt.
- Kundenportal: nur Zahlungsart ändern. Kündigung und Tarifwechsel im Portal aus, weil die Kündigung über den eigenen Kündigungsbutton läuft.
- Webhook-Endpunkt: bestehende Ereignisse plus
customer.subscription.created,customer.subscription.updated,customer.subscription.deleted,invoice.paid,invoice.payment_failed,charge.dispute.closed. - Produkte und Preise der Abo-Angebote legt der Admin über Wabenhain an, nicht von Hand im Stripe-Dashboard.
- Tests mit Stripe Test Clocks (Abo über mehrere Monate) und SEPA-Testkonten, darunter eines, das eine Rückbuchung auslöst.
Lieferaufträge
Ein täglicher Lauf im CronJob wabenhain-certificates prüft fällige
Lieferungen. Ist der Anspruch erfüllt und Bestand reserviert, legt er einen
Lieferauftrag als normale Bestellung an (Status BEZAHLT, Betrag 0 €, mit
Verweis auf das Abo). Er erscheint in der bestehenden Pack- und DHL-Liste. Der
Inhaber packt und versendet wie bei jeder Bestellung.
Honigbestand und Kontingent
Kein Abo darf ohne Honig bleiben, weil der Shop zu viele Gläser einzeln verkauft hat:
- Kontingent: Jedes Abo-Angebot hat eine Höchstzahl aktiver Abos, im Admin pflegbar. Ist sie erreicht, zeigt die Verkaufsseite „Derzeit ausgebucht“ mit der bestehenden Benachrichtigung, sobald wieder Plätze frei sind.
- Reservierung, vierteljährlich: Für jedes aktive Abo sind die Gläser der nächsten fälligen Lieferung im Bestand des verknüpften Honigprodukts reserviert. Der Shop verkauft einzeln nur den freien Bestand: Bestand minus Abo-Reservierung minus offene Bestellungen.
- Reservierung, Ernte-Variante: Der Inhaber trägt je Erntefenster die geplanten Abo-Gläser ein. Sobald die Abfüllung im Bestand ist, wird dieser Anteil reserviert, bevor er in den Freiverkauf geht.
- Deckungsanzeige im Admin-Dashboard: „Bestand deckt den Abo-Bedarf der nächsten 2 Lieferungen.“ Unter einer Lieferung erscheint eine Warnung in der Aufmerksamkeitsliste.
- Reicht die Deckung für neue Abos nicht, stoppt der Shop neue Abschlüsse automatisch, bis der Inhaber nachlegt.
Kündigung
- Kündigungsbutton nach § 312k BGB: „Verträge hier kündigen“. Im Konto mit
einem Klick auf die Bestätigungsseite, zusätzlich öffentlich erreichbar
unter
/vertraege-kuendigenmit Name, E-Mail und Abo-Nummer, nach dem Muster der bestehenden Routevertrag-widerrufen. Rechtlich prüfen lassen. - Die Kündigung wirkt zum Ende des bezahlten Monats (
cancel_at_period_end). Eine Bestätigungsmail geht sofort hinaus. - Wird die Kündigung wirksam:
- Die Urkunde bekommt automatisch eine neue Revision mit „vom … bis …“. Ersteller „System“, Grund „Abo beendet“. Sie bleibt im Konto herunterladbar.
- Die Abo-Stufe und ihre Medaille verschwinden.
- Die Patenschafts-Medaille und alle Downloads bleiben.
- Offene Reservierungen werden freigegeben.
Architektur
Ein Layout, mehrere Ausgaben
Vorschau, 3D-Textur 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, Glyphen als Pfade, sharp → WebP,
│ Wasserzeichen, Bildschirmauflösung
└──► renderCertificateTexture() wie Vorschau, ohne Wasserzeichen,
2048 px, nur für Besitzer
Bild-Ausgaben setzen Glyphen als Pfade aus denselben Schriftdateien an dieselben Positionen. Sie hängen nicht von Browser-Schriften ab. Ein Test vergleicht die Zeilen aller 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, Laufzeitform |
layout.ts |
Messen, Umbrechen, Schriftstufen, Layoutvarianten |
templates/ |
Vorlagen, je Version eine Datei, alte Versionen bleiben erhalten |
render-pdf.ts |
pdfkit-Ausgabe |
render-image.ts |
SVG-Ausgabe, Vorschau und Textur |
storage.ts |
Ablage der PDFs |
issue.ts |
Erzeugung nach Zahlung, idempotent, mit Wiederholung |
Weitere Module: src/lib/medals/ (Medaillen-SVG, Stufenberechnung),
src/lib/sponsorship-subscription/ (Abo, Lieferanspruch, Reservierung),
src/lib/sponsorship-transfer.ts.
Vorlagenversion
Jede Vorlage hat eine feste Kennung, etwa wabe-classic@1. Eine
Designänderung erzeugt eine neue Version, die alte bleibt im Code. Neue
Patenschaften nutzen die aktuelle Version. Bestehende behalten ihre Version
und ihre gespeicherte PDF. Systemrevisionen (Abo-Ende) nutzen die Version der
vorherigen Revision. Medaillen sind ebenso versioniert.
Datenmodell (Prisma, beide Provider)
SponsorshipOffer: Art (EINMALIG,ABO), Name, Beschreibung, Leistungen, Preis (einmalig) oder Monatspreis, aktiv, Reihenfolge, physisch, verknüpftes Honigprodukt, Gläser je Lieferung, Lieferzyklus (VIERTELJAEHRLICH,ERNTE), Kontingent, Stripe-Preis-ID, Steueraufteilung, MedaillenstufeSponsorship: Besitzerkonto, Angebot, Bezug aufOrderItem(einmalig) oderSponsorshipSubscription(Abo), jeweils eindeutig als Idempotenzschlüssel, Patenschaftsnummer, Start, Ende (leer bei aktivem Abo), Status, aktuelle Revision, ZustellfelderpdfAttempts,nextAttemptAt,lastError,mailSentAt,printedAtSponsorshipRevision: unveränderlich: Personalisierung (JSON), aufgelöster Text, Vorlagenversion, PDF-Pfad, SHA-256, Ersteller (System, Admin), Grund, ZeitpunktSponsorshipCounter: fortlaufende Nummer je JahrSponsorshipSubscription: Konto, Angebot,stripeSubscriptionId(eindeutig), Status (AKTIV,IM_VERZUG,GEKUENDIGT,BEENDET), Beginn, Kündigung wirksam zum, EndeSubscriptionPayment: Abo,stripeInvoiceId(eindeutig), bezahlt am, Betrag, Zahlart, zählt für Lieferung ab (Datum, bei SEPA-Neukunden nach der Frist), zurückgebucht am, Wabenhain-RechnungSubscriptionDelivery: Abo, fällig am, Gläser, Status, erzeugte BestellungHarvestWindow: Zeitraum, geplante Abo-Gläser je AngebotSponsorshipTransfer: Patenschaft, Token-Hash, gültig bis, erstellt von, eingelöst von, eingelöst am, widerrufen amLoyaltyLevel: Art (STAMMKUNDE,ABO), Schwelle, Name, Medaillendesign; VIP als Stufe ohne ZahlCustomer.stripeCustomerId,Customer.sepaBlockedAt(gesetzt nach einer Rückbuchung)
Statuswerte der Patenschaft: AUSSTEHEND, FEHLER, BEREIT, GEDRUCKT.
Aktiv, abgelaufen und gekündigt werden aus Daten berechnet.
Warenkorb und Checkout (Einmal-Patenschaft)
- Patenschaft als Position im bestehenden Warenkorb, Menge immer 1 je Personalisierung.
- Die Personalisierung reist mit der Position. Der Checkout prüft sie erneut mit demselben Schema und denselben Layoutregeln und verlangt ein angemeldetes Konto.
- Vor dem Hinzufügen bestätigt der Kunde: „Ich habe die Vorschau und die Schreibweise geprüft.“
- Beim Anlegen der Bestellung wird die Personalisierung mit der
Vorlagenversion an der
OrderItemgespeichert. Genau dieser Stand wird nach der Zahlung zur ersten Revision. - Reine Digitalbestellungen haben keine Versandkosten. Ob dafür ein neuer
FulfillmentMethod-WertDIGITALnötig ist, entscheidet der Umsetzungsplan nach Lesen von Checkout, Rechnung und DHL-Logik. - Physische Pakete laufen über die bestehenden Versandstaffeln je Kategorie mit eigener Staffel für Patenschaftspakete.
- Der Honig eines Pakets bucht den Bestand des verknüpften Produkts über die vorhandene Bestandslogik (einschließlich ApiCore-Abgleich), unter Berücksichtigung der Abo-Reservierung.
Steuer
Pakete und Abos enthalten Leistungen mit unterschiedlichen Steuersätzen
(Urkunde und Leistung, Honig). Das Angebot speichert deshalb eine Aufteilung:
Honiganteil in Cent zum Honig-Satz, Rest zum Regelsatz. Die Rechnung zeigt
beide Steuerzeilen über die vorhandene Gruppierung in lib/vat.ts. Die
Methode muss die Steuerberatung bestätigen. Bei Kleinunternehmerregelung
entfällt die Aufteilung wie heute.
Ablauf nach der Zahlung (Einmal-Patenschaft)
- Der Stripe-Webhook markiert die Bestellung wie heute über den atomaren
Claim als bezahlt. Nur dieser Lauf legt die
Sponsorship-Zeilen an. Ein Duplikat scheitert am eindeutigenorderItemIdund bricht still ab. - Danach versucht der Webhook die Erzeugung direkt: Text, Layout, PDF, Ablage, Hash, erste Revision.
- Die Bestellbestätigung verlinkt auf
/konto/patenschaft/<id>. Der Mailversand wird überupdateMany … where mailSentAt = nullbeansprucht, damit doppelte Webhooks keine zweite Mail erzeugen. Erst danach ist der StatusBEREIT. - Scheitert die Erzeugung, antwortet der Webhook trotzdem 200 (die Zahlung
ist erfolgt). Die Patenschaft bleibt
AUSSTEHEND. Die Mail sagt: „Deine Urkunde wird gerade erstellt und erscheint in Kürze in deinem Konto.“ - Der CronJob
wabenhain-certificates(alle 10 Minuten,concurrencyPolicy: Forbid, wie die Jobs ink8s/07-backup-cronjob.yaml) holt offene Erzeugungen und Mails nach, mit wachsendem Abstand, höchstens 8 Versuche, danachFEHLERund Hinweis in der Aufmerksamkeitsliste.
Die finale Urkunde entsteht nie vor bestätigter Zahlung. SEPA-Zahlungen
erzeugen sie erst bei async_payment_succeeded. Beim Abo entsteht sie mit der
ersten bezahlten Rechnung.
Ablage und Zugriff
- PDFs liegen in
CERTIFICATE_DIR, nicht unterUPLOAD_DIR. Die Startprüfung auslib/invoice-storage.tswird übernommen. Das Verzeichnis kommt auf das gesicherte Volume und in den Sicherungs-CronJob. - Alle Downloads und die 3D-Textur liefern Routen aus, die Anmeldung und Besitz prüfen. Fremde IDs ergeben 404.
- Downloads liefern immer die gespeicherte PDF der aktuellen Revision.
- Kein QR-Code auf der Urkunde: Er brächte kaum Nutzen und würde die Gestaltung stören.
Vorschau
POST /api/patenschaft/vorschau: prüft die Personalisierung, gibt ein WebP mit Wasserzeichen „Unverbindliche Vorschau“ in Bildschirmauflösung zurück. Rate-Limit je Besucher. Keine Anmeldung nötig.- Der Client fordert sie etwa 400 ms nach der letzten Eingabe an und zeigt bis dahin die letzte gültige Vorschau.
Adminbereich
- Angebote: Einmal- und Abo-Angebote bearbeiten, Kontingent, Erntefenster, Medaillenstufe.
- Patenschaften: Liste mit Filtern (ausstehend, Fehler, bereit, zu drucken, gedruckt, Art, Angebot). Detail mit Vorschau, Revisionen, „Druck-PDF öffnen“, „Als gedruckt markieren“, „Erneut erzeugen“, „Mail erneut senden“, Übertragungshistorie.
- Abos: Liste mit Status, bezahlten Monaten, nächster Lieferung; Deckung des Honigbedarfs.
- Treuestufen: Schwellen und Namen pflegen.
- Korrektur: Felder im Kundenformular ändern, Vorschau mit derselben
Layoutlogik, Pflichtfeld Änderungsgrund, neue Revision mit neuer PDF, alte
bleibt abrufbar, Eintrag über
logAdminAction, optional Mail an den Kunden. Standardmäßig mit der Vorlagenversion der bisherigen Revision. - Druckablauf: Physische Bestellungen erscheinen nach Zahlung unter „zu drucken“. PDF öffnen, auf festem Papier drucken, als gedruckt markieren, wie gewohnt über DHL versenden.
Verkaufsseite
Route /patenschaft, zweisprachig, im Design der Website.
Im Mittelpunkt:
- einer Biene symbolisch einen eigenen Namen geben
- ein persönlich gestaltetes Geschenk
- die regionale Imkerei Wabenhain unterstützen
- je nach Angebot eigenen Wabenhain-Honig, einmalig oder regelmäßig
Aufbau:
- Kopfbereich mit großer, echter Urkundenvorschau
- Umschalter „Einmalig“ / „Im Abo“ mit den Angeboten, Preis, Leistungen, Versandkosten beziehungsweise „Versand inklusive“ und den Lieferregeln
- Personalisierung in Schritten: Angebot, für wen und Anlass, Namen, Widmung und Startdatum, Vorschau prüfen
- Ausschnitt aus dem Kontobereich (3D-Urkunde und Medaille als Video oder Bildfolge) mit dem Hinweis, dass der Kauf ein Kundenkonto braucht
- Hinweis zur symbolischen Namensgebung, gut sichtbar
- FAQ
Smartphone: Vorschau über dem jeweiligen Schritt, ein Tipp vergrößert sie. Eingabefelder mindestens 16 px Schrift, Bedienelemente mindestens 44 px.
FAQ-Themen: symbolische Namensgebung, Laufzeit (einmalig zwölf Monate, Abo monatlich kündbar), wann der Honig im Abo kommt, warum ein Konto nötig ist, Übertragung an Beschenkte, Versandkosten, Tippfehler (Kontakt, Korrektur durch Wabenhain), was nach Ablauf oder Kündigung bleibt. Keine FAQ verspricht Besuche, Berichte, Fotos oder Umweltwirkungen.
Prüfung
Layout-Testmatrix
Automatisierte Tests rendern echte PDFs und prüfen die Layoutdaten (keine Überlappung, alles in 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 und mit maximal langer Widmung samt allen Zeilenumbrüchen
- jeden Anlass, eigene und verschenkte Patenschaft, Deutsch und Englisch
- alle drei Laufzeitformen (einmalig, Abo aktiv, Abo beendet)
- Vorschau, Textur und PDF ergeben dieselben Zeilen
Die Matrix legt die endgültigen Eingabelimits fest.
Visuelle Kontrolle
PDFs werden mit 300 dpi gerastert und angesehen: ganze Seite und Ausschnitte
in hoher Vergrößerung. Probedruck auf einem Bürodrucker. Medaillen als PNG in
Originalgröße. 3D-Ansicht auf Desktop, 390 px mobil, mit
prefers-reduced-motion und ohne WebGL.
Ablauftests
- doppelter Webhook: eine Patenschaft, eine Mail
- PDF-Erzeugung scheitert: Webhook 200, CronJob holt nach
- Gastkauf einer Patenschaft wird serverseitig abgewiesen
- fremde Patenschaft, fremder Download, fremde Textur: 404
- Korrektur: neue Revision, alte unverändert, Audit-Eintrag
- neue Vorlagenversion: alte Urkunden unverändert
- Übertragung: Link läuft ab, wird widerrufen, wird genau einmal eingelöst
- Abo: Lieferung erst nach drei bezahlten Monaten; Kündigung nach zwei Monaten erzeugt keine Lieferung; Zahlungsausfall stoppt Lieferungen; Kündigung erzeugt Von-bis-Revision und entfernt die Abo-Stufe
- Bestand: Einzelverkauf kann reservierte Abo-Gläser nicht kaufen; Kontingent voll stoppt neue Abos
- doppelte Stripe-Abo-Ereignisse: eine Rechnung, eine Zahlung
- SEPA: erste Zahlung zählt erst nach der Neukunden-Frist; Rückbuchung stoppt Lieferungen, setzt das Abo in Verzug, sperrt SEPA für das Konto; ohne Ausgleich endet das Abo nach 14 Tagen
- Treuestufen: Erstattung senkt die Stammkunden-Stufe
- E2E (Playwright): Einmalkauf mit Stripe-Testkarte bis zur 3D-Ansicht im Konto; Abo-Abschluss mit Stripe-Testuhr (Test Clock) über drei Monate
Die Repo-Skripte lint, typecheck, test und build laufen grün.
Abnahme
Je Teilprojekt gilt: fertig erst nach den passenden Tests, der visuellen Kontrolle und einer Vorführung. Gesamtabnahme:
- Verkaufsseite und Personalisierung auf Desktop und 390 px mobil
- die drei Designvarianten und die gewählte Gestaltung
- mehrere echte PDF-Ausgaben mit unterschiedlichen Beispieldaten
- automatischer Ablauf vom Kauf bis zur 3D-Ansicht und zum Download
- Medaillen aller Arten und Stufen
- Übertragung von Konto zu Konto
- Abo über drei Monate mit Test Clock bis zur Lieferung, dann Kündigung
- Druck- und Korrekturablauf im Admin
- offene geschäftliche Konfiguration (Liste unten)
Geschäftliche Konfiguration vor Veröffentlichung
- Preise kaufmännisch prüfen: Einmalpakete und Abo-Monatspreise mit Honig, Papier, Verpackung, Grußkarte, Versand, Stripe-Gebühren, Arbeitszeit.
- Gläser je Abo-Lieferung, Erntefenster und Kontingente festlegen.
- Steueraufteilung mit der Steuerberatung abstimmen.
- AGB, Abo-Bedingungen und Widerrufsbelehrung: personalisierte Ware (§ 312g Abs. 2 Nr. 1 BGB), digitale Inhalte (§ 356 Abs. 5 BGB), Abo-Laufzeit und Kündigung, Kündigungsbutton (§ 312k BGB), Lieferregel „nach bezahlten Monaten“, Übertragung auf eigene Verantwortung. Rechtlich prüfen lassen.
- Datenschutzerklärung: Namen Dritter, Speicherdauer, Stripe Billing.
- Stripe-Livemodus freigeben: Die Einrichtung (siehe „Stripe-Einrichtung“) läuft erst im Testmodus. Den Livemodus stellt das Skript erst nach ausdrücklicher Freigabe des Inhabers um. Neukunden-Frist für SEPA bestätigen (Vorgabe 56 Tage).
- Versandstaffel für Patenschaftspakete anlegen.
- Logo als SVG oder PNG mit mindestens 300 dpi hochladen.
- Material bevorraten: Urkundenpapier (200–250 g/m², matt, naturweiß), Geschenkverpackung, Grußkarten. Probedruck freigeben.
- Bestellschluss für Weihnachten festlegen.
- Textbausteine und Medaillennamen sprachlich freigeben (de und en).