diff --git a/docs/superpowers/specs/2026-10-16-bienenpatenschaft-design.md b/docs/superpowers/specs/2026-10-16-bienenpatenschaft-design.md index 33d7235..7c380cd 100644 --- a/docs/superpowers/specs/2026-10-16-bienenpatenschaft-design.md +++ b/docs/superpowers/specs/2026-10-16-bienenpatenschaft-design.md @@ -1,77 +1,118 @@ -# Bienenpatenschaft mit automatisch erzeugter Urkunde +# 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. Wo ältere Fassungen etwas anderes sagen, gilt dieses -Dokument. +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 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. +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, optisch hochwertige und druckfähige Urkunde, und der -Käufer bekommt den Download automatisch. +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 vollständig. Sie werden weder auf der -Verkaufsseite noch in E-Mails, Urkunden, FAQs oder Rechtstexten versprochen: +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, Newsletter zur Patenschaft +- Videos, individuelle Bienenfotos, Saisonberichte - 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) +- Gastbestellungen von Patenschaften -Die Patenschaftsseite zeigt nur die persönlichen Patenschaftsdaten und den -Download der Urkunde. Sie braucht keine redaktionelle Pflege. +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. -## Produkt +## Angebote -### Pakete +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. -Drei Ausgangspakete, im Adminbereich bearbeitbar (Name, Preis, Beschreibung, -Leistungsliste, aktiv/inaktiv, Reihenfolge): +### Einmal-Patenschaften | Paket | Testpreis | Leistungen | Versand | |---|---:|---|---| -| Bienenfreund | 19 € | symbolische Namensgebung, individuell gestaltete PDF-Urkunde, sicherer Download | keiner | +| 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 | -- Die Preise sind Testpreise. Vor Veröffentlichung werden sie kaufmännisch - geprüft (siehe „Geschäftliche Konfiguration vor Veröffentlichung“). +- 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 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. + unterscheiden sich in den physischen Leistungen und in der Medaillenstufe. -### Honig im Paket +### Abo-Patenschaften -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. +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 -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. +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 @@ -81,17 +122,16 @@ So entsteht kein Handschreiben pro Bestellung. |---|---|---| | 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“) | +| 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 | +| Startdatum | ja | Einmal: frühestens Bestelltag, spätestens sechs Monate danach. Abo: Tag der ersten Zahlung | -Bei „für mich selbst“ blendet das Formular das Feld „Schenkende“ aus. +Bei „für mich selbst“ blendet das Formular „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: +Die endgültigen Limits ergeben sich aus der Layout-Testmatrix. Startwerte: - Bienenname: 2–24 Zeichen - Name auf der Urkunde: 2–60 Zeichen @@ -108,40 +148,35 @@ und Client prüfen mit demselben zod-Schema. - 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. + klarer Meldung ab, statt ein Ersatzkästchen zu drucken. +- Umlaute, ß, Akzente, Bindestriche und Apostrophe 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. +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, passende - Anlasszeile. „Für mich selbst“ und „allgemeines Geschenk“ haben keine. +- 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 Anreden wie „Liebe/Lieber“, - die aus dem Namen abgeleitet wären. +- 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. Erlaubt sind nur sichere Darstellung - (kein HTML, kein Markup) und sauberer Umbruch. +- 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 über dem Haupttext: - -- Geburtstag: „Zum Geburtstag“ -- Weihnachten: „Zu Weihnachten“ -- Dankeschön: „Als Dankeschön“ -- allgemeines Geschenk und für mich selbst: keine Anlasszeile +Anlasszeile: „Zum Geburtstag“, „Zu Weihnachten“, „Als Dankeschön“. Haupttext, eigene Patenschaft: @@ -159,10 +194,16 @@ Haupttext, verschenkte Patenschaft: Schenkende, nur wenn ausgefüllt: „Geschenkt von {Schenkende}“. -Widmung, nur wenn ausgefüllt: als eigener, typografisch abgesetzter Block. +Widmung, nur wenn ausgefüllt: eigener, typografisch abgesetzter Block. -Laufzeit: „Patenschaft vom {Startdatum} bis {Enddatum}“, Enddatum = Startdatum -plus zwölf Monate minus ein Tag, deutsches Langformat. +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`). @@ -172,11 +213,10 @@ 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. +Sprache: Die Urkunde erscheint in der beim Kauf gewählten Sprache (de/en). +Beide Fassungen durchlaufen dieselbe Testmatrix. -## Gestaltung +## Gestaltung der Urkunde ### Anspruch @@ -195,19 +235,17 @@ Die Urkunde soll wie ein rahmenwürdiges Geschenk wirken: ### 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. + 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 `#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. + `#8a6531` für Akzente und Linien, Honey `#b88a44` nur klein, Sage `#788774` + fü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 aus `lib/brand-icon.ts`. Das Logo + wird nicht verzerrt, umgefärbt oder nachgezeichnet. +- Weißes Papier, keine randlosen Farbflächen. ### Drei Varianten, dann eine Entscheidung @@ -220,48 +258,265 @@ Zuerst entstehen drei Varianten mit identischen Beispieldaten: 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. +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 -- Format A4 hochkant, genau eine Seite +- 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. +- 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 und Hinweis), Fließtext mindestens 11 pt +- kleinste Schrift 8 pt (Kennung, Hinweis), Fließtext mindestens 11 pt - PDF-Metadaten: Titel „Bienenpatenschaft {Bienenname}“, Autor „Imkerei Wabenhain“ -### Lange Inhalte +Lange Inhalte löst das Layout über Regeln, nicht durch Verkleinern der ganzen +Seite: -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. +1. Layoutvarianten: ohne Widmung, 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. + höchstens auf zwei Zeilen, nie mitten im Wort. 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. + 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-Dauer. +- Vorgabe des Inhabers: Stufen bis 24, danach eine Stufe ohne Zahl, „VIP“, + als Zeichen besonders hoher Wertschätzung. Ob die 24 Jahre oder Monate + meint, ist offen (siehe „Offene Fragen“). Die Schwellen sind im Admin + pflegbar, damit sich das ohne Codeänderung anpassen lässt. +- 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/fiber` und `@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. + +1. Der Besitzer wählt im Menü der Patenschaft „Übertragen“. +2. Er wählt die Gültigkeit des Links: 24 Stunden, 1 Woche oder 30 Tage. +3. 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.) +4. 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. +5. Bis zur Einlösung sieht der Besitzer den offenen Link mit Ablaufzeit und + kann ihn widerrufen. +6. 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. +7. Abgelaufene, widerrufene oder eingelöste Links zeigen eine neutrale Meldung + ohne Daten der Patenschaft. +8. 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. +- `Customer` bekommt eine `stripeCustomerId`. +- 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-Lastschrift + ist eine Rückbuchung bis acht Wochen möglich. Empfehlung: Abos zuerst nur mit + Karte und Wallets (Apple Pay, Google Pay) anbieten. SEPA ist eine + Entscheidung des Inhabers. +- 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. + +### 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-kuendigen` mit Name, E-Mail und Abo-Nummer, nach dem + Muster der bestehenden Route `vertrag-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: + 1. Die Urkunde bekommt automatisch eine neue Revision mit „vom … bis …“. + Ersteller „System“, Grund „Abo beendet“. Sie bleibt im Konto + herunterladbar. + 2. Die Abo-Stufe und ihre Medaille verschwinden. + 3. Die Patenschafts-Medaille und alle Downloads bleiben. + 4. Offene Reservierungen werden freigegeben. ## Architektur -### Ein Layout, zwei Ausgaben +### Ein Layout, mehrere Ausgaben -Vorschau und finale PDF müssen identisch umbrechen. Deshalb gibt es genau eine -Layout-Berechnung auf dem Server: +Vorschau, 3D-Textur und finale PDF müssen identisch umbrechen. Deshalb gibt es +genau eine Layout-Berechnung auf dem Server: ``` Personalisierung + Textbausteine + Vorlagenversion @@ -275,289 +530,283 @@ layoutCertificate() → positionierte Elemente: Zeilen mit x/y, 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 + ├──► renderCertificatePreview() SVG, Glyphen als Pfade, sharp → WebP, + │ Wasserzeichen, Bildschirmauflösung + └──► renderCertificateTexture() wie Vorschau, ohne Wasserzeichen, + 2048 px, nur für Besitzer ``` -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. +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 | +| `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-preview.ts` | SVG-Ausgabe und Rasterung mit Wasserzeichen | -| `storage.ts` | Ablage der PDFs (eigenes Verzeichnis, siehe unten) | +| `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 -Bestellungen nutzen die aktuelle Version. Bereits ausgestellte Urkunden -behalten ihre Version und ihre gespeicherte PDF. +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) -- `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`, +- `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, Medaillenstufe +- `Sponsorship`: Besitzerkonto, Angebot, Bezug auf `OrderItem` (einmalig) + oder `SponsorshipSubscription` (Abo), jeweils eindeutig als + Idempotenzschlüssel, Patenschaftsnummer, Start, Ende (leer bei aktivem Abo), + Status, aktuelle Revision, Zustellfelder `pdfAttempts`, `nextAttemptAt`, `lastError`, `mailSentAt`, `printedAt` +- `SponsorshipRevision`: unveränderlich: Personalisierung (JSON), aufgelöster + Text, Vorlagenversion, PDF-Pfad, SHA-256, Ersteller (System, Admin), + Grund, Zeitpunkt +- `SponsorshipCounter`: fortlaufende Nummer je Jahr +- `SponsorshipSubscription`: Konto, Angebot, `stripeSubscriptionId` + (eindeutig), Status (`AKTIV`, `IM_VERZUG`, `GEKUENDIGT`, `BEENDET`), + Beginn, Kündigung wirksam zum, Ende +- `SubscriptionPayment`: Abo, `stripeInvoiceId` (eindeutig), bezahlt am, + Betrag, Wabenhain-Rechnung, zählt für Lieferung (ja/nein) +- `SubscriptionDelivery`: Abo, fällig am, Gläser, Status, erzeugte Bestellung +- `HarvestWindow`: Zeitraum, geplante Abo-Gläser je Angebot +- `SponsorshipTransfer`: Patenschaft, Token-Hash, gültig bis, erstellt von, + eingelöst von, eingelöst am, widerrufen am +- `LoyaltyLevel`: Art (`STAMMKUNDE`, `ABO`), Schwelle, Name, Medaillendesign; + VIP als Stufe ohne Zahl +- `Customer.stripeCustomerId` -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. +Statuswerte der Patenschaft: `AUSSTEHEND`, `FEHLER`, `BEREIT`, `GEDRUCKT`. +Aktiv, abgelaufen und gekündigt werden aus Daten berechnet. -### Warenkorb und Checkout +### Warenkorb und Checkout (Einmal-Patenschaft) -- 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. +- 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 `OrderItem` gespeichert. Genau dieser Stand wird nach + der Zahlung zur ersten Revision. +- Reine Digitalbestellungen haben keine Versandkosten. Ob dafür ein neuer + `FulfillmentMethod`-Wert `DIGITAL` nö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 -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. +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 +### Ablauf nach der Zahlung (Einmal-Patenschaft) 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`. + Claim als bezahlt. Nur dieser Lauf legt die `Sponsorship`-Zeilen an. + Ein Duplikat scheitert am eindeutigen `orderItemId` und bricht still ab. +2. Danach versucht der Webhook die Erzeugung direkt: Text, Layout, PDF, + Ablage, Hash, erste Revision. +3. Die Bestellbestätigung verlinkt auf `/konto/patenschaft/`. Der + Mailversand wird über `updateMany … where mailSentAt = null` beansprucht, + damit doppelte Webhooks keine zweite Mail erzeugen. Erst danach ist 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). + ist erfolgt). Die Patenschaft bleibt `AUSSTEHEND`. Die Mail sagt: „Deine + Urkunde wird gerade erstellt und erscheint in Kürze in deinem Konto.“ +5. Der CronJob `wabenhain-certificates` (alle 10 Minuten, + `concurrencyPolicy: Forbid`, wie die Jobs in `k8s/07-backup-cronjob.yaml`) + holt offene Erzeugungen und Mails nach, mit wachsendem Abstand, höchstens + 8 Versuche, danach `FEHLER` und Hinweis in der Aufmerksamkeitsliste. -Die finale Urkunde entsteht nie vor bestätigter Zahlung. Async-Zahlarten -(SEPA) erzeugen sie erst bei `async_payment_succeeded`. +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 +### Ablage und Zugriff -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/` 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. +- PDFs liegen in `CERTIFICATE_DIR`, nicht unter `UPLOAD_DIR`. Die + Startprüfung aus `lib/invoice-storage.ts` wird ü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 -- 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. +- `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 -### 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. +- 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 bestehenden Design der Website. +Route `/patenschaft`, zweisprachig, im Design der Website. -Im Mittelpunkt stehen: +Im Mittelpunkt: - 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 +- je nach Angebot eigenen Wabenhain-Honig, einmalig oder regelmäßig 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 +1. Kopfbereich mit großer, echter Urkundenvorschau +2. Umschalter „Einmalig“ / „Im Abo“ mit den Angeboten, Preis, Leistungen, + Versandkosten beziehungsweise „Versand inklusive“ und den Lieferregeln +3. Personalisierung in Schritten: Angebot, 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 +4. Ausschnitt aus dem Kontobereich (3D-Urkunde und Medaille als Video oder + Bildfolge) mit dem Hinweis, dass der Kauf ein Kundenkonto braucht +5. Hinweis zur symbolischen Namensgebung, gut sichtbar +6. 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. +Smartphone: Vorschau über dem jeweiligen Schritt, ein Tipp vergrößert sie. +Eingabefelder mindestens 16 px Schrift, 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. +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 von Elementboxen, alles innerhalb der Sicherheitszone, Schrift nie -unter Mindestgröße, genau eine Seite) für: +Ü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 -- maximal lange Widmung, auch mit allen erlaubten Zeilenumbrüchen +- ohne Widmung und mit maximal langer Widmung samt allen Zeilenumbrüchen - jeden Anlass, eigene und verschenkte Patenschaft, Deutsch und Englisch -- Vorschau und PDF ergeben dieselben Zeilen +- alle drei Laufzeitformen (einmalig, Abo aktiv, Abo beendet) +- Vorschau, Textur und PDF ergeben dieselben Zeilen -Die Matrix legt die endgültigen Eingabelimits fest. Sie stehen danach im -Schema und im Formular. +Die Matrix legt die endgültigen Eingabelimits fest. ### 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. +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 -- 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 +- 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 +- 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 -Fertig ist die Funktion, wenn eine Testbestellung ohne manuelle Nacharbeit -eine korrekt personalisierte, hochwertige und druckfähige Urkunde erzeugt. +Je Teilprojekt gilt: fertig erst nach den passenden Tests, der visuellen +Kontrolle und einer Vorführung. Gesamtabnahme: -Zum Abschluss werden gezeigt: - -1. Verkaufsseite und Personalisierung auf Desktop und bei 390 px mobil +1. Verkaufsseite und Personalisierung auf Desktop und 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) +4. automatischer Ablauf vom Kauf bis zur 3D-Ansicht und zum Download +5. Medaillen aller Arten und Stufen +6. Übertragung von Konto zu Konto +7. Abo über drei Monate mit Test Clock bis zur Lieferung, dann Kündigung +8. Druck- und Korrekturablauf im Admin +9. offene geschäftliche Konfiguration (Liste unten) + +## Offene Fragen an den Inhaber + +1. Abo-Stufen „bis 24“: Jahre oder Monate? Die Schwellen sind pflegbar, die + Antwort bestimmt nur die Vorgabe. +2. SEPA-Lastschrift für Abos anbieten (Rückbuchungsrisiko bis acht Wochen) + oder zuerst nur Karte und Wallets? ## 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). +1. Preise kaufmännisch prüfen: Einmalpakete und Abo-Monatspreise mit Honig, + Papier, Verpackung, Grußkarte, Versand, Stripe-Gebühren, Arbeitszeit. +2. Gläser je Abo-Lieferung, Erntefenster und Kontingente festlegen. +3. Steueraufteilung mit der Steuerberatung abstimmen. +4. 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. +5. Datenschutzerklärung: Namen Dritter, Speicherdauer, Stripe Billing. +6. Stripe: Billing aktivieren, Kundenportal nur für Zahlungsart einrichten, + Webhook-Ereignisse ergänzen. +7. Versandstaffel für Patenschaftspakete anlegen. +8. Logo als SVG oder PNG mit mindestens 300 dpi hochladen. +9. Material bevorraten: Urkundenpapier (200–250 g/m², matt, naturweiß), + Geschenkverpackung, Grußkarten. Probedruck freigeben. +10. Bestellschluss für Weihnachten festlegen. +11. Textbausteine und Medaillennamen sprachlich freigeben (de und en).