feat: Bienenpatenschaft mit Urkunde, Abo, Medaillen und 3D-Konto

Setzt Teilprojekte 1-5 der Spec 2026-10-16 um:
- Urkunden-Engine (lib/certificate): ein Layout fuer PDF, Vorschau und
  3D-Textur, Vorlage classic@1, eingebettete OFL-Schriften, Testmatrix
- Einmal-Patenschaft ueber Traegerprodukte (Kategorie PATENSCHAFT),
  Paket wird im Checkout in Patenschaft (Regelsatz) und Honig aufgeteilt,
  Kontopflicht, rein digitale Bestellungen (FulfillmentMethod DIGITAL)
- Ausstellung nach Zahlung idempotent, Wiederholung im App-Prozess
  (instrumentation + background-jobs), Ablage in CERTIFICATE_DIR
- Verkaufsseite /patenschaft mit Konfigurator und Live-Vorschau,
  Warenkorb mit Schluessel je Position
- Kundenkonto: 3D-Ansicht von Urkunde und Medaille, Downloads, ZIP,
  Uebertragung per befristetem Einmal-Link, Treuestufen bis VIP
- Admin: Angebote, Patenschaften, Druck, Korrektur mit Revisionen,
  Abos, Erntefenster, Deckung, SEPA-Frist, Treuestufen
- Abo ueber Stripe Billing: Lieferung erst nach bezahlten Monaten,
  SEPA-Neukunden-Frist und Rueckbuchungsschutz, Honigreservierung,
  Kuendigungsbutton, Monatsrechnungen, Stripe-Einrichtungsskript

Startangebote werden inaktiv angelegt; Livebetrieb erst nach Freigabe.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-16 14:07:30 +02:00
1 parent dcb578f062
commit f227aeb8f9
269 files changed
+28054 -141

No files matched your search

@@ -0,0 +1,18 @@
import { BackLink } from "@/components/back-link";
import { getLocale } from "@/i18n/locale";
import { getSponsorshipAdminStrings } from "@/i18n/sponsorship/admin";
import { createSponsorshipOfferAction } from "@/app/admin/actions";
import { EMPTY_OFFER, OfferForm } from "../../_components/offer-form";
import { getHoneyProductOptions } from "../../_lib/offer-overview";
export default async function AdminSponsorshipOfferNewPage() {
const t = getSponsorshipAdminStrings(await getLocale());
const honeyOptions = await getHoneyProductOptions(null);
return (
<div className="max-w-3xl">
<BackLink href="/admin/patenschaften/angebote" label={t.offerForm.backToOffers} />
<h1 className="mb-8 text-2xl text-heading">{t.offerForm.newTitle}</h1>
<OfferForm defaults={EMPTY_OFFER} isNew honeyOptions={honeyOptions} action={createSponsorshipOfferAction} t={t} />
</div>
);
}