Architektur

Ein Worker, eine D1-Datenbank, ein R2-Bucket. Keine Server, keine Warteschlangen, kein Admin-Login.

Überblick

Projektseite ──GET/POST /buy/:sku──▶ Worker ──Checkout-API──▶ Stripe | Polar
                                       ▲                          │ Webhook (signiert)
   Bestellseite ◀──── 303 ─────────────┘◀── POST /webhook/:provider┘
   /order/:provider?checkout_id=…           │  idempotent (Event-ID)
     ├─ /download/:token ─▶ R2              ▼
     │   HMAC, 7 Tage, max. 5×        D1: orders, licenses,
     └─ Lizenzschlüssel CLK1.…            download_grants,
         (Ed25519, offline prüfbar)       webhook_events
   Erstattung / Dispute ─▶ Lizenz und Downloads gesperrt
Ablauf eines Kaufs vom Kaufknopf bis zur Sperre nach Erstattung

Endpunkte

RouteAufgabe
GET|POST /buy/:skuCheckout anlegen und weiterleiten; nur Katalog-SKUs, Ratenbegrenzung
POST /webhook/:providerSignatur prüfen, Bestellung speichern, ausliefern, nach Erstattung sperren
GET /order/:providerBestellseite mit Download, Lizenz und Rechtshinweisen
GET /download/:tokenDatei aus R2, nur mit gültigem, unverändertem Token
GET /license/public-keyöffentlicher Schlüssel für die Offline-Prüfung
GET|POST /license/verifyOnline-Prüfung inklusive Sperre und Ablauf
GET /products.json, /price/:skuPreise mit Pflichthinweis für deine Seiten
GET /stats, /healthzKennzahlen (mit Token) und Zustand

Daten in D1

Schlüssel

Alle Schlüssel stammen aus einem einzigen Secret PAY_SECRET und werden per HKDF getrennt abgeleitet: HMAC-Schlüssel für Download-Links, Salz für IP-Hashes und der Ed25519-Schlüssel für Lizenzen. So genügt ein Secret, und keiner der Zwecke kann einen anderen ersetzen.

Sicherheit

Tests

Über 100 automatische Tests: Vitest läuft direkt in der Workers-Laufzeit (Miniflare) mit nachgebildeten Antworten von Stripe, Polar und dem E-Mail-Dienst; node:test deckt Katalog-Generator, Deploy-Skript und die Prüfbibliotheken ab.