Files
dogfather-universe/cloudflare-worker

DOGFATHER UNIVERSE — Interner Bereich (Cloudflare Worker + D1)

Setzt das Anforderungsdokument „Geschützter Zugang, Rollen und Benutzerverwaltung" (Geschuetzter_Zugang_Rollen_Benutzerverwaltung.pdf) vollständig um: Session-basierte Anmeldung, verschlüsselte (aber für Dogi jederzeit einsehbare) Zugangscodes, frei konfigurierbare Rollen mit granularen Rechten, individuelle Ausnahmen pro Person, Aktivitätsprotokoll, Login-Lockout.

Kosten: läuft im kostenlosen Cloudflare-Tier (Workers Free, D1 Free, KV Free reichen locker).

Bereits deployed

Die Schritte unten sind nur nötig, falls der Worker mal neu aufgesetzt werden muss.

Architektur

src/worker.js              Router — verteilt Requests an die Handler unten
src/lib/crypto.js          SHA-256-Hashing, AES-256-GCM-Verschlüsselung, ID/Token-Erzeugung
src/lib/auth.js            Login-Prüfung, Sessions, Rate-Limiting/Lockout
src/lib/permissions.js     Vollständiger Permission-Katalog aus dem Anforderungsdokument
src/lib/audit.js           Aktivitätsprotokoll schreiben (nie mit Codes!)
src/lib/http.js            CORS/JSON-Helfer
src/routes/auth.js         Login/Logout
src/routes/users.js        Zugänge und Teammitglieder (inkl. Code-Funktionen, NUR Owner)
src/routes/roles.js        Rollen erstellen/umbenennen/löschen
src/routes/applications.js Bewerbungen: Status, Zuweisung, Notizen, Antwortentwürfe
src/routes/audit.js        Aktivitätsprotokoll auslesen
migrations/0001_init.sql   D1-Schema (users, roles, sessions, audit_log, applications, ...)

Das Kernprinzip (aus dem Anforderungsdokument)

Nur der Hauptadministrator sieht jederzeit alle vollständigen Zugangscodes und nur der Hauptadministrator darf sie erstellen, ändern, kopieren, zurücksetzen oder sperren.

Technisch umgesetzt:

  • Owner-Code = das POSTFACH_CODE-Secret. Kein Datenbankeintrag, kann nicht gelöscht/verändert werden außer von Dogi selbst per wrangler secret put.
  • Team-Codes werden zweifach gespeichert:
    • code_hash (SHA-256, nicht umkehrbar) — für den schnellen Login-Vergleich.
    • code_enc (AES-256-GCM, umkehrbar) — nur damit kann der Owner sich den Klartext-Code später wieder anzeigen lassen. Der Schlüssel dafür liegt ausschließlich im ENCRYPTION_KEY-Secret.
  • Code anzeigen verlangt zusätzlich eine Re-Authentifizierung (Owner-Code erneut eingeben), bevor der Klartext entschlüsselt und zurückgegeben wird.
  • Folgende Aktionen sind fest an isOwner === true gebunden und erscheinen nirgends als wählbare Berechtigung: Code anzeigen/kopieren/erstellen/ändern/zurücksetzen, den eigenen Owner-Zugang bearbeiten, die Owner-Rolle löschen/einschränken, jemanden zum Owner machen.

Voraussetzungen

  • Ein (kostenloser) Cloudflare-Account
  • Node.js installiert (für npx wrangler)

Deploy von Grund auf (falls je nötig)

Alles im Ordner cloudflare-worker/ ausführen:

cd cloudflare-worker

# 1. Bei Cloudflare einloggen
npx wrangler login

# 2. D1-Datenbank anlegen
npx wrangler d1 create dogfather-universe-db
# -> "database_id" aus der Ausgabe in wrangler.toml eintragen

# 3. Schema anlegen
npx wrangler d1 execute dogfather-universe-db --remote --file=migrations/0001_init.sql

# 4. KV-Namespace anlegen (nur noch für den Live-Status-Schalter genutzt)
npx wrangler kv namespace create BEWERBUNGEN
# -> "id" aus der Ausgabe in wrangler.toml eintragen

# 5. Owner-Code festlegen (dein persönlicher Hauptadministrator-Zugang)
npx wrangler secret put POSTFACH_CODE

# 6. Verschlüsselungs-Schlüssel für Team-Codes festlegen (32 zufällige Bytes, base64)
#    z.B. erzeugen mit: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
npx wrangler secret put ENCRYPTION_KEY

# 7. (Optional) Bewerbungen zusätzlich automatisch als Ticket bei
#    Ticketanizer anlegen (dort in Discord sichtbar) — siehe Abschnitt
#    "Bewerbungen als Ticketanizer-Tickets" unten. Ohne diesen Schritt
#    läuft alles wie gehabt, es fehlt nur das automatische Ticket.

# 8. Deployen
npx wrangler deploy

Bewerbungen als Ticketanizer-Tickets

Jede eingehende Bewerbung wird zusätzlich zur Speicherung in der eigenen Datenbank als echtes Ticket bei Ticketanizer angelegt — im passenden Bereich (Modi/Scout/Creator/Kooperation), exakt wie auf der Website getrennt. Das läuft über die offizielle Ticketanizer-Inbound-Ticket-API (POST https://api.ticketanizer.com/v1/tickets), kein Discord-Bot-Code nötig.

Einrichtung (einmalig, ca. 2 Minuten)

  1. Im Ticketanizer-Dashboard: API & Webhooks → API-Keys → Key erstellen (Name z.B. "DOGFATHER UNIVERSE Homepage"). Den Key sofort kopieren — wird meist nur einmal im Klartext angezeigt.
  2. Als Secret im Worker hinterlegen:
npx wrangler secret put TICKETANIZER_API_KEY
  1. Danach einmal npx wrangler deploy.

Die Zuordnung Bewerbungsbereich → Ticketanizer-Panel ist fest in src/lib/ticketanizer.js (PANEL_IDS) hinterlegt, abgelesen aus dem Ticketanizer-Dashboard unter Panels:

Bewerbung auf der Website Ticketanizer-Panel panel_id
Modi Modi-Bewerbung 4
Kooperation Kooperationsbewerbung 5
Scout Scout-Bewerbung 6
Creator Manager-Bewerbung 7

Ändert sich ein Panel (neu angelegt, andere ID), einfach die Zahlen in PANEL_IDS in src/lib/ticketanizer.js anpassen und neu deployen.

Wichtig

  • Ticketanizer ist rein informativ, kein Ausfallpunkt. Fehlt der API-Key oder ist Ticketanizer kurz nicht erreichbar, wird die Bewerbung trotzdem ganz normal in der eigenen Datenbank gespeichert — nur das Zusatz-Ticket entfällt dann.
  • Der Key steht nie im Code oder in wrangler.toml (die ist eingecheckt), sondern ausschließlich verschlüsselt bei Cloudflare — genau wie POSTFACH_CODE und ENCRYPTION_KEY.
  • Ändern/Ersetzen des Keys: wrangler secret put TICKETANIZER_API_KEY erneut ausführen, überschreibt den alten Wert.
  • Es wird bewusst nur Schritt 1 der Ticketanizer-API genutzt (Ticket eröffnen). Das Nachladen von Staff-Antworten (Schritt 3, "pollen") ist hier nicht eingebaut, da eine Bewerbung ein einmaliger Vorgang ist und kein dauerhaft laufender Chat.
  • Wichtige Einschränkung (2026-08-01 festgestellt): Über die Inbound- Ticket-API angelegte Tickets landen bei Ticketanizer nur in der Web-Inbox (eigene Weboberfläche, siehe Dashboard → "Inbox") und lösen lediglich einen Rollen-Ping im Log-Kanal aus — es entsteht kein echter, sichtbarer Ticket-Kanal in Discord (auch nicht nach manuellem "Übernehmen" in der Inbox). Deshalb zusätzlich der Discord-Webhook-Weg weiter unten, der die Bewerbung garantiert sichtbar direkt in den passenden Kanal postet.

Bewerbungen direkt in Discord-Kanälen (Webhooks)

Zusätzlich zu Ticketanizer wird jede Bewerbung als formatierte Nachricht (Embed) direkt per normalem Discord-Webhook in den passenden Kanal gepostet — das ist der Weg, der garantiert sichtbar in Discord ankommt (siehe Einschränkung oben).

Kanal-Zuordnung (von Dogi aus Discord kopiert, 2026-08-01)

Bewerbung auf der Website Discord-Kanal Secret
Modi #modi-bewerbung DISCORD_WEBHOOK_MODI
Kooperation #kooperations-bewerbung DISCORD_WEBHOOK_KOOPERATION
Scout und Creator #scout-bewerbung (gemeinsam) DISCORD_WEBHOOK_SCOUT_MANAGER

Einrichtung (pro Kanal ca. 1 Minute)

  1. Im jeweiligen Discord-Kanal: Kanal bearbeiten → IntegrationenWebhooksNeuer WebhookWebhook-URL kopieren.
  2. Als Secret hinterlegen:
npx wrangler secret put DISCORD_WEBHOOK_MODI
npx wrangler secret put DISCORD_WEBHOOK_KOOPERATION
npx wrangler secret put DISCORD_WEBHOOK_SCOUT_MANAGER
  1. Danach einmal npx wrangler deploy.

Genau wie bei Ticketanizer: rein informativ, kein Ausfallpunkt. Fehlt eine Webhook-URL oder ist Discord kurz nicht erreichbar, wird die Bewerbung trotzdem ganz normal gespeichert. Die Zuordnung Typ → Webhook steht in src/lib/discord-webhooks.js (WEBHOOK_ENV_KEYS).

Wer den Owner-Code kennen darf

Nur du. Er ist dein Hauptadministrator-Zugang — sieht ausnahmslos alles, kann Zugänge/Rollen/Codes verwalten. Ändern: wrangler secret put POSTFACH_CODE erneut ausführen.

Zugänge und Teammitglieder verwalten

Auf zugaenge.html (verlinkt von postfach.html, wenn du als Owner eingeloggt bist):

  • Neue Zugänge erstellen — Name, Benutzername, E-Mail, Rolle, Gültigkeit, Notiz. Code manuell festlegen oder automatisch sicher generieren lassen. Wird einmalig im Klartext angezeigt — danach nur noch über „Code anzeigen" (mit Re-Auth) abrufbar.
  • Rollen frei erstellen — jedes einzelne Recht per Checkbox an-/abschaltbar (Bewerbungsbereiche, Bearbeitung, Antworten, Notizen, Teamverwaltung, Einstellungen). Die Code-Funktionen tauchen dort bewusst nirgends auf.
  • Individuelle Ausnahmen pro Person — zusätzlich zur Rolle einzelne Rechte gezielt erlauben oder entziehen.
  • Delegierbare Teilfunktion: Personen mit dem Recht „Neue Benutzer vorbereiten" können einen Entwurf anlegen (Name, Benutzername, Rolle) — der Zugang bleibt inaktiv, bis du ihn im Bereich „Zugänge" mit „Freigeben & Code erstellen" final aktivierst.
  • Pro Person: Code anzeigen/kopieren/neu erstellen (nur Owner), Sperren/Entsperren, alle Sitzungen beenden (nur Owner), Rolle ändern, Rechte verwalten, vollständig löschen (nur Owner).

Sicherheitsmaßnahmen

  • Nach 5 falschen Codes pro Client 15 Minuten Sperre (login_attempts-Tabelle).
  • Sessions: 30 Minuten Inaktivitäts-Timeout, 12 Stunden absolute Höchstdauer.
  • Zugangscodes erscheinen niemals im Aktivitätsprotokoll, im Quelltext oder in Fehlermeldungen.
  • CORS ist aktuell offen (*) — sobald die finale Domain feststeht, in src/lib/http.jscorsHeaders() auf die echte Domain einschränken.

Supporter-Abo (Dogfather) — Setup

Setzt Dogfather_VanVan_Supporter_Abo.odt um: eigener, öffentlicher Supporter-Bereich mit PayPal-Abo (4,99 €/Monat), 30-Monats-Prämienzyklus (Hasen-Teddys → Tasse & Autogrammkarte → Hoodie) und wechselnden Kollektionen. Wichtig: Das Abo selbst gehört nur Dogfather — die Teddy-Kollektion/Sammlerstücke entstehen in Kooperation mit VanVan, aber das Abonnement ist NICHT gemeinsames Branding (klargestellt 03.08.2026). Code ist vollständig fertig implementiert, kann aber erst wirklich Geld verarbeiten bzw. E-Mails verschicken, sobald folgende zwei externe Dienste eingerichtet sind — beides Dinge, die nur der Website-Betreiber selbst einrichten kann (eigene Identität/Bankkonto):

src/lib/supporter-cycle.js    Reine Rechenlogik: 30-Monats-Zyklus/Meilensteine
src/lib/supporter-auth.js     Registrierung/Login (E-Mail-Code, eigene Sessions)
src/lib/supporter-mail.js     Transaktions-E-Mails (Resend-Adapter)
src/lib/paypal.js             PayPal Subscriptions API + Webhook-Signaturprüfung
src/routes/supporter.js       Öffentlicher Supporter-Bereich (Profil/Prämien/Archiv)
src/routes/supporter-paypal.js  Abo starten/kündigen + Webhook-Verarbeitung
src/routes/supporter-admin.js Interner Administrationsbereich (Abonnentenübersicht etc.)
migrations/0003_supporter_abo.sql  D1-Schema (komplett getrennt vom Team-Zugangssystem)

1) D1-Migration ausführen (einmalig)

npx wrangler d1 execute dogfather-universe-db --remote --file=migrations/0003_supporter_abo.sql

2) PayPal-Business-Konto + Abo-Plan einrichten

  1. PayPal-Business-Konto anlegen (falls noch nicht vorhanden): https://www.paypal.com/business
  2. Developer-App anlegen: https://developer.paypal.com/dashboard/applicationsCreate App (zuerst im Sandbox-Modus testen, siehe unten).
  3. Ein Produkt anlegen (Katalog-Produkt, Typ "Service") mit dem Namen „Dogfather Supporter-Abo".
  4. Einen Abo-Plan zu diesem Produkt anlegen: 4,99 € / Monat, EUR, monatliche automatische Verlängerung, keine Testphase, keine Einrichtungsgebühr.
  5. Einen Webhook anlegen, Ziel-URL: https://dogfather-universe-postfach.dogfather1608.workers.dev/supporter/paypal-webhook Mindestens folgende Ereignisse abonnieren: BILLING.SUBSCRIPTION.ACTIVATED, BILLING.SUBSCRIPTION.UPDATED, BILLING.SUBSCRIPTION.CANCELLED, BILLING.SUBSCRIPTION.SUSPENDED, BILLING.SUBSCRIPTION.EXPIRED, PAYMENT.SALE.COMPLETED, PAYMENT.SALE.DENIED, PAYMENT.SALE.REFUNDED, PAYMENT.SALE.REVERSED.

Aus diesen Schritten bekommst du 4 Werte, die als Secrets gesetzt werden (NIE im Code, NIE im Repo):

npx wrangler secret put PAYPAL_CLIENT_ID
npx wrangler secret put PAYPAL_CLIENT_SECRET
npx wrangler secret put PAYPAL_PLAN_ID
npx wrangler secret put PAYPAL_WEBHOOK_ID

Und in wrangler.toml unter [vars] (unkritisch, kein Geheimnis):

PAYPAL_ENV = "sandbox"   # später auf "live" umstellen, siehe Abschnitt 7 des Auftrags

Erst vollständig in der Sandbox testen (eigenes Sandbox-Business- und Sandbox-Privatkonto unter https://developer.paypal.com/dashboard/accounts), danach PAYPAL_ENV auf "live" umstellen und Schritte 2-5 mit den echten Live-Zugangsdaten wiederholen. Solange die Secrets fehlen, antworten alle PayPal-Endpunkte kontrolliert mit PAYPAL_NOT_CONFIGURED statt abzustürzen.

Zahlarten-Abdeckung (03.08.2026 ergänzt): Das Frontend nutzt jetzt die offiziellen PayPal Smart Payment Buttons (abonnieren.html) statt einer reinen Weiterleitung — dadurch zeigt PayPal automatisch ALLE für die jeweilige Käuferin/den jeweiligen Käufer verfügbaren, in Deutschland gängigen Zahlarten an (PayPal-Guthaben/-Bankkonto, Kreditkarte auch als Gast ohne eigenes PayPal-Konto). Das ist bewusst PayPal selbst überlassen (kein eigenes Karten-/SEPA-/Klarna-Backend nötig) — das Geld landet dabei immer direkt auf deinem eigenen PayPal-Business-Konto (dieselben PAYPAL_CLIENT_ID/PAYPAL_PLAN_ID wie oben). Es ist keine zusätzliche Einstellung nötig — welche Zahlarten genau angezeigt werden, entscheidet PayPal automatisch je nach Land/Konto deiner Supporter.

3) "Mit Google anmelden" einrichten (optional, aber empfohlen)

Zusätzlich zum E-Mail-Code-Login gibt es jetzt einen "Mit Google anmelden"- Button (professionellerer, schnellerer Login — Google hat die E-Mail-Adresse bereits selbst bestätigt, kein Extra-Code nötig). Komplett optional: ohne GOOGLE_CLIENT_ID bleibt der Button einfach ausgeblendet, der normale E-Mail-Code-Login funktioniert unverändert.

  1. https://console.cloud.google.com/apis/credentials öffnen (kostenloses Google-Konto reicht, keine Kreditkarte nötig).
  2. Falls noch nicht vorhanden: OAuth-Zustimmungsbildschirm einmalig einrichten (App-Name z.B. "Dogfather Supporter-Abo", externe Nutzer).
  3. Anmeldedaten erstellen → OAuth-Client-ID → Webanwendung.
  4. Unter Autorisierte JavaScript-Quellen deine echte Domain eintragen (sobald vorhanden) sowie zum Testen https://dogfather-universe.dogfather1608.workers.dev.
  5. Die erzeugte Client-ID (endet auf .apps.googleusercontent.com) als Secret setzen:
npx wrangler secret put GOOGLE_CLIENT_ID

Kein Client-Secret nötig — die Anmeldung läuft komplett über Googles "Sign In With Google"-Button im Browser, der Worker prüft das dabei ausgestellte Token nur gegen Googles öffentlichen tokeninfo-Endpunkt.

4) E-Mail-Versand einrichten (Resend, kostenloser Tier reicht)

Ohne E-Mail-Versand können sich Supporter nicht registrieren/einloggen (E-Mail-Bestätigung/Login-Code). Benötigt außerdem eine eigene, per SPF/DKIM verifizierte Domain (auf *.workers.dev allein funktioniert zuverlässiger E-Mail-Versand nicht).

  1. Account auf https://resend.com anlegen (kostenlos bis 3.000 E-Mails/Monat).
  2. Eigene Domain hinzufügen und die angezeigten DNS-Einträge setzen.
  3. API-Key erstellen.
npx wrangler secret put RESEND_API_KEY

Und in wrangler.toml unter [vars]:

RESEND_FROM = "Dogfather Team <[email protected]>"

5) Deployen

npx wrangler deploy

6) Berechtigung für den Administrationsbereich vergeben

Auf zugaenge.html einer Rolle (oder dir selbst als Owner, der hat ohnehin alles) die neuen Rechte „Supporter-Abonnenten ansehen", „Supporter- Prämien & Versand verwalten" und „Supporter-Kollektionen verwalten" zuweisen (Gruppe „Supporter-Abo" in der Rechteverwaltung).

Verbindliche Prämienlogik (nicht verändern, Abschnitt 11-13 des Auftrags)

Erfolgreich bezahlte Monate (im laufenden Zyklus) Prämie
6 Kleiner Hasen-Teddy
12 Mittelgroßer Hasen-Teddy
18 Großer Hasen-Teddy
24 Tasse & Autogrammkarte
30 Exklusiver Hoodie — Zyklus abgeschlossen
31+ Neuer 30-Monats-Zyklus, neue Kollektion, Fortschritt bei 0 (Gesamt-Mitgliedschaftsdauer bleibt erhalten)

Testzahlungen (Sandbox) zählen nie als echter Monat. Jedes PayPal-Ereignis wird per paypal_event_id genau einmal verarbeitet (keine doppelte Anrechnung bei erneuter Zustellung).

Bewusst noch nicht gebaut (nächste Ausbaustufe, nicht Teil der Abnahmekriterien)

Abschnitt 20 des Auftrags ("Zusätzliche Vorteile") beschreibt optionale Bonus-Features — Abstimmungen, Downloads, Supporter-Wand, Jubiläums- Videobotschaften. Die Datenbankstruktur lässt Raum dafür, sie sind aber bewusst nicht Teil dieser ersten Ausbaustufe, da sie in den "Verbindlichen Abnahmekriterien" (Abschnitt 34) nicht gefordert sind.

Wartung

  • Bewerbungen/Zugänge/Rollen: alles über zugaenge.html bzw. postfach.html als Owner.
  • Direktzugriff auf die Datenbank bei Bedarf: npx wrangler d1 execute dogfather-universe-db --remote --command="SELECT ..."