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:
1 parent
dcb578f062
commit
f227aeb8f9
269 files changed
+28054
-141
No files matched your search
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Rendert Beispiel-Medaillen aller Arten und Stufen als PNG (und SVG) zur
|
||||
* Sichtpruefung. Aufruf: pnpm tsx scripts/render-medal-samples.ts <Zielordner> [Groesse]
|
||||
*/
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { medalReliefSvg, renderMedalPng, renderMedalSvg, type MedalInput } from "../src/lib/medals";
|
||||
|
||||
const SAMPLES: Array<[string, MedalInput]> = [
|
||||
["patenschaft-bronze", { kind: "PATENSCHAFT", tier: "BRONZE", beeName: "Summsi", year: 2026, number: "WH-P-2026-00042" }],
|
||||
["patenschaft-silber", { kind: "PATENSCHAFT", tier: "SILBER", beeName: "Zoë", year: 2026, number: "WH-P-2026-00043" }],
|
||||
["patenschaft-gold", { kind: "PATENSCHAFT", tier: "GOLD", beeName: "Ñúñez", year: 2026, number: "WH-P-2026-00044" }],
|
||||
["patenschaft-abo", { kind: "PATENSCHAFT", tier: "ABO", beeName: "Hildegard", year: 2026, number: "WH-P-2026-00045" }],
|
||||
["patenschaft-lang-24", { kind: "PATENSCHAFT", tier: "BRONZE", beeName: "Wilhelmine Augusta Maxi", year: 2026, number: "WH-P-2026-00046" }],
|
||||
["patenschaft-lang-ohne-umbruch", { kind: "PATENSCHAFT", tier: "GOLD", beeName: "Bienenköniginwunderbarer", year: 2026, number: "WH-P-2026-00047" }],
|
||||
["patenschaft-abo-lang", { kind: "PATENSCHAFT", tier: "ABO", beeName: "Wilhelmine-Augusta Maxi", year: 2026, number: "WH-P-2026-00048" }],
|
||||
["stammkunde-1", { kind: "STAMMKUNDE", level: 1, name: "Blütenbesuch" }],
|
||||
["stammkunde-2", { kind: "STAMMKUNDE", level: 2, name: "Wabenbau" }],
|
||||
["stammkunde-3", { kind: "STAMMKUNDE", level: 3, name: "Honigschatz" }],
|
||||
["stammkunde-4", { kind: "STAMMKUNDE", level: 4, name: "Goldwabe" }],
|
||||
["abo-1", { kind: "ABO", months: 1 }],
|
||||
["abo-12", { kind: "ABO", months: 12 }],
|
||||
["abo-24", { kind: "ABO", months: 24 }],
|
||||
["vip", { kind: "VIP" }],
|
||||
];
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const target = process.argv[2];
|
||||
if (!target) throw new Error("Zielordner fehlt: pnpm tsx scripts/render-medal-samples.ts <Zielordner> [Groesse]");
|
||||
const size = Number(process.argv[3] ?? 1024);
|
||||
await mkdir(target, { recursive: true });
|
||||
for (const [name, input] of SAMPLES) {
|
||||
await writeFile(path.join(target, `${name}.png`), await renderMedalPng(input, size));
|
||||
await writeFile(path.join(target, `${name}.svg`), renderMedalSvg(input));
|
||||
if (name === "patenschaft-gold") await writeFile(path.join(target, `${name}-relief.svg`), medalReliefSvg(input));
|
||||
}
|
||||
process.stdout.write(`${SAMPLES.length} Medaillen in ${target}\n`);
|
||||
}
|
||||
|
||||
main().catch((error: unknown) => {
|
||||
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in new issue
Block a user