Files
Wabenhain/scripts/render-medal-samples.ts
T
Nick SzaunigandClaude Opus 5.5 f227aeb8f9 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]>
2026-10-16 14:07:30 +02:00

44 lines
2.6 KiB
TypeScript

/**
* 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);
});