Widerrufsbelehrung und Datenschutz
RECHERCHIERT, NICHT AUS DEM GEDAECHTNIS
Der Webdesign-Bereich hatte KEINE eigene Rechtsseite -- obwohl dort
Vertraege geschlossen und Zahlungen ausgeloest werden. Die Fusszeile
verwies auf die Kontaktseite des Universe, die ein Content-Projekt
beschreibt, kein Dienstleistungsgeschaeft.
Die Web-Recherche hat eine Pflicht zutage gefoerdert, die seit zwei
Monaten gilt und die die Seite nicht erfuellt hat:
§ 356a BGB -- elektronische Widerrufsfunktion, in Kraft seit
19.06.2026. Sie gilt fuer ALLE Fernabsatzvertraege, die ueber eine
Online-Benutzeroberflaeche geschlossen werden, nicht nur fuer
Finanzdienstleistungen.
WARUM DAS HIER GILT: Im Kundenportal nimmt der Kunde Zusatzangebote per
Klick VERBINDLICH an ("Damit nimmst du das Zusatzangebot verbindlich
an"). Das ist ein Vertragsschluss ueber eine Online-Benutzeroberflaeche.
Fuer die geplanten PayPal-Zahlungen gilt dasselbe.
Der Anbieter sitzt in Luxemburg. Fuer Verbraucher mit gewoehnlichem
Aufenthalt in Deutschland gilt nach Art. 6 Rom-I-VO trotzdem das
deutsche zwingende Verbraucherrecht, weil die Seite sich erkennbar an den
deutschsprachigen Markt richtet. Deshalb wurde der STRENGERE Standard
umgesetzt, nicht der bequemere.
WAS GEBAUT WURDE
webdesign/widerruf.html -- die Widerrufsfunktion, genau nach dem
Wortlaut der Vorschrift:
* Beschriftung "Vertrag widerrufen" (gesetzlich vorgegeben)
* ZWEITE Schaltflaeche "Widerruf bestaetigen" (ebenfalls vorgegeben --
ein einstufiges Formular wuerde die Vorschrift nicht erfuellen)
* unverzuegliche Eingangsbestaetigung mit Nummer, ZEITPUNKT (nicht nur
Datum), Empfaenger und dem Wortlaut der Erklaerung
* Link in der Fusszeile JEDER Seite -- "staendig verfuegbar,
hervorgehoben platziert, leicht zugaenglich" heisst nicht "in den AGB
versteckt"
Drei Entscheidungen, die unmittelbar aus dem Sinn der Vorschrift folgen:
KEINE ANMELDUNG. Die Seite ist von der Zugangswand ausgenommen. Wer
seinen Code verlegt hat, wuerde sonst seine Frist verlieren --
Fristverlust durch eine selbstgebaute Huerde ist der schlimmste
denkbare Fall.
KEINE MENGENBEGRENZUNG. Ueberall sonst richtig, hier ein
Rechtsverlust: Wer in der letzten Stunde seiner Frist wegen eines
hakenden Netzes dreimal klickt, darf nicht abgewiesen werden.
KEIN ZWISCHENSPEICHER. Beim Anfrageformular ein Segen, hier eine
Falle: Auf einem geteilten Rechner laege der halb ausgefuellte Widerruf
des einen im Browser des naechsten.
webdesign/rechtliches.html -- Impressum, AGB, Widerrufsbelehrung samt
Muster-Widerrufsformular, Datenschutzerklaerung. Alle Betreiberangaben
sind aus den bestehenden Seiten UEBERNOMMEN, nichts erfunden: Anschrift
in Mondercange, Kleinunternehmerregelung nach Art. 57 TVA-Gesetz LU und
Richtlinie (EU) 2020/285, netcup/Cloudflare, PayPal Luxemburg.
Migration 0014: wd_widerrufe (der dauerhafte Datentraeger und der
Nachweis, wird nie geleert) und wd_zustimmungen. Letztere speichert nicht
nur den Haken, sondern den WORTLAUT, den der Kunde gesehen hat -- die
Beweislast fuer die Zustimmung zum vorzeitigen Leistungsbeginn liegt beim
Unternehmer (§ 356 Abs. 4 BGB), und im Streit zaehlt, WAS bestaetigt
wurde. Bewusst OHNE Fremdschluessel: CASCADE wuerde den Nachweis mit dem
Kunden mitloeschen, RESTRICT wuerde eine DSGVO-Loeschung blockieren.
Druckansicht: Die Eingangsbestaetigung ist ein Rechtsnachweis. Auf Papier
schwarz auf weiss, ohne Navigation und Knoepfe -- ein Nachweis, den
niemand ausdruckt, weil er eine halbe Patrone kostet, erfuellt seinen
Zweck nicht.
ZWEI ECHTE FEHLER GEFUNDEN
1. Die Pflicht-Sternchen verschwanden nach der Uebersetzung. Ursache:
data-i18n stand auf dem <label> selbst und ersetzte dessen ganzen
Inhalt -- samt <span class="wd-pflicht">. Das Anfrageformular macht es
laengst richtig (data-i18n auf einem INNEREN span); die neue Seite
hatte das Muster nicht uebernommen. Aufgefallen ist es nur, weil der
Test die Pflichtfelder GEZAEHLT hat statt sie vorauszusetzen.
2. window.WD.sprache() gibt es nicht, die Funktion heisst getSprache().
Dadurch brach der Uebergang zur zweiten Stufe stumm ab.
GEPRUEFT: 58 Pruefungen, alle bestanden. Darunter die gesetzlich
vorgegebenen Beschriftungen in allen FUENF Sprachen, "kein Grund noetig",
genau drei Pflichtfelder, Datum UND Uhrzeit in der Bestaetigung, und die
Druckansicht.
WAS FILIPE NOCH PRUEFEN LASSEN MUSS: Diese Texte sind sorgfaeltig
recherchiert, aber ich bin keine Rechtsanwaeltin. Vor dem oeffentlichen
Start gehoert das Ganze einmal zu einer im luxemburgischen Recht
qualifizierten Fachperson -- besonders die grenzueberschreitende Lage
(Sitz LU, Kunden in DE/CH/FR/PT) und die Frage, ob die Seite in
Franzoesisch und Portugiesisch aktiv verkaufen soll. Dann muessen die
Rechtstexte auch dorthin uebersetzt werden, und zwar fachlich.
Versionsstempel und Cache-Name auf v7.
Co-Authored-By: Claude Opus 5 <[email protected]>
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
- Interner Worker: https://dogfather-universe-postfach.dogfather1608.workers.dev (Health-Check:
/health) - D1-Datenbank:
dogfather-universe-db - Website (
postfach.html,zugaenge.html,assets/js/*.js) zeigt bereits auf diese URL.
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 perwrangler 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 imENCRYPTION_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 === truegebunden 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)
- 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.
- Als Secret im Worker hinterlegen:
npx wrangler secret put TICKETANIZER_API_KEY
- 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 wiePOSTFACH_CODEundENCRYPTION_KEY. - Ändern/Ersetzen des Keys:
wrangler secret put TICKETANIZER_API_KEYerneut 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)
- Im jeweiligen Discord-Kanal: Kanal bearbeiten → Integrationen → Webhooks → Neuer Webhook → Webhook-URL kopieren.
- 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
- 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, insrc/lib/http.js→corsHeaders()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
- PayPal-Business-Konto anlegen (falls noch nicht vorhanden): https://www.paypal.com/business
- Developer-App anlegen: https://developer.paypal.com/dashboard/applications → Create App (zuerst im Sandbox-Modus testen, siehe unten).
- Ein Produkt anlegen (Katalog-Produkt, Typ "Service") mit dem Namen „Dogfather Supporter-Abo".
- Einen Abo-Plan zu diesem Produkt anlegen: 4,99 € / Monat, EUR, monatliche automatische Verlängerung, keine Testphase, keine Einrichtungsgebühr.
- Einen Webhook anlegen, Ziel-URL:
https://dogfather-universe-postfach.dogfather1608.workers.dev/supporter/paypal-webhookMindestens 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.
- https://console.cloud.google.com/apis/credentials öffnen (kostenloses Google-Konto reicht, keine Kreditkarte nötig).
- Falls noch nicht vorhanden: OAuth-Zustimmungsbildschirm einmalig einrichten (App-Name z.B. "Dogfather Supporter-Abo", externe Nutzer).
- Anmeldedaten erstellen → OAuth-Client-ID → Webanwendung.
- Unter Autorisierte JavaScript-Quellen deine echte Domain eintragen
(sobald vorhanden) sowie zum Testen
https://dogfather-universe.dogfather1608.workers.dev. - 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).
- Account auf https://resend.com anlegen (kostenlos bis 3.000 E-Mails/Monat).
- Eigene Domain hinzufügen und die angezeigten DNS-Einträge setzen.
- 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.htmlbzw.postfach.htmlals Owner. - Direktzugriff auf die Datenbank bei Bedarf:
npx wrangler d1 execute dogfather-universe-db --remote --command="SELECT ..."