Alle ausstehenden Aenderungen (Bilder, Texte) fuer den Server-Umzug uebernommen
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
-- =====================================================================
|
||||
-- DOGFATHER × VanVan Supporter-Abo — Datenbankschema
|
||||
-- Setzt "Dogfather_VanVan_Supporter_Abo.odt" um (Abschnitt 28 empfiehlt
|
||||
-- diese Struktur; hier leicht angepasst an die Konventionen des restlichen
|
||||
-- Workers: TEXT-IDs, ISO-Zeitstempel, Wiederverwendung von audit_log statt
|
||||
-- eines eigenen Änderungsprotokolls).
|
||||
--
|
||||
-- Bewusst eine EIGENE, von der internen Team-Zugangsverwaltung (users/
|
||||
-- roles/sessions) komplett GETRENNTE Nutzerwelt — Supporter sind
|
||||
-- öffentliche Fans/Kund:innen, keine Teammitglieder mit Rechten.
|
||||
-- =====================================================================
|
||||
|
||||
-- Öffentliche Supporter-Accounts. Nur Name, TikTok-Name, E-Mail bei
|
||||
-- Registrierung (siehe Abschnitt 5/30 — Datensparsamkeit).
|
||||
CREATE TABLE IF NOT EXISTS supporter_users (
|
||||
id TEXT PRIMARY KEY,
|
||||
display_name TEXT NOT NULL,
|
||||
tiktok_username TEXT, -- ohne "@", normalisiert
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
email_verified INTEGER NOT NULL DEFAULT 0,
|
||||
pending_email TEXT, -- neue E-Mail, bis sie bestätigt wird (Abschnitt 25)
|
||||
status TEXT NOT NULL DEFAULT 'active', -- active | deleted
|
||||
-- Versanddaten werden ERST bei der ersten Prämien-Einlösung abgefragt
|
||||
-- (Abschnitt 17/30), deshalb hier bewusst alles NULL-fähig.
|
||||
ship_name TEXT,
|
||||
ship_street TEXT,
|
||||
ship_zip TEXT,
|
||||
ship_city TEXT,
|
||||
ship_country TEXT,
|
||||
ship_save_address INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL,
|
||||
last_login_at TEXT
|
||||
);
|
||||
|
||||
-- Einmalcodes für E-Mail-Bestätigung UND Magic-Link-Login (Abschnitt 5/116).
|
||||
CREATE TABLE IF NOT EXISTS supporter_auth_codes (
|
||||
id TEXT PRIMARY KEY,
|
||||
supporter_id TEXT NOT NULL REFERENCES supporter_users(id),
|
||||
purpose TEXT NOT NULL, -- verify_email | login
|
||||
code_hash TEXT NOT NULL,
|
||||
expires_at TEXT NOT NULL,
|
||||
used_at TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Sessions für den öffentlichen Supporter-Bereich — eigenes, von der
|
||||
-- internen Team-Session-Tabelle getrenntes Token-System.
|
||||
CREATE TABLE IF NOT EXISTS supporter_sessions (
|
||||
token_hash TEXT PRIMARY KEY,
|
||||
supporter_id TEXT NOT NULL REFERENCES supporter_users(id),
|
||||
created_at TEXT NOT NULL,
|
||||
last_active_at TEXT NOT NULL,
|
||||
expires_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Eine (aktuell: genau eine) Abo-Stufe pro Supporter.
|
||||
CREATE TABLE IF NOT EXISTS supporter_subscriptions (
|
||||
id TEXT PRIMARY KEY,
|
||||
supporter_id TEXT NOT NULL REFERENCES supporter_users(id),
|
||||
paypal_subscription_id TEXT UNIQUE, -- erst nach PayPal-Freigabe gesetzt
|
||||
paypal_plan_id TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending', -- pending | active | suspended | cancelled | expired
|
||||
started_at TEXT,
|
||||
next_payment_at TEXT,
|
||||
paid_period_end_at TEXT, -- bis wann Zugang nach Kündigung bleibt
|
||||
cancelled_at TEXT,
|
||||
-- Fortschritt (Abschnitt 11-13): Gesamtzahl erfolgreich angerechneter
|
||||
-- Monate bleibt für IMMER erhalten (auch über Kündigung/Reaktivierung
|
||||
-- hinweg, Abschnitt 23) — daraus werden Zyklus/Meilenstein/Kollektion
|
||||
-- rein rechnerisch abgeleitet (siehe lib/supporter-cycle.js), NICHT
|
||||
-- redundant gespeichert, damit nichts auseinanderlaufen kann.
|
||||
total_paid_months INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Jede EINZELNE erfolgreiche/fehlgeschlagene PayPal-Zahlung. Idempotenz
|
||||
-- über paypal_event_id: jedes Webhook-Ereignis wird nur einmal verarbeitet
|
||||
-- (Abschnitt 8, "doppelt empfangenes PayPal-Ereignis: keine doppelte
|
||||
-- Anrechnung").
|
||||
CREATE TABLE IF NOT EXISTS supporter_payments (
|
||||
id TEXT PRIMARY KEY,
|
||||
supporter_id TEXT NOT NULL REFERENCES supporter_users(id),
|
||||
subscription_id TEXT NOT NULL REFERENCES supporter_subscriptions(id),
|
||||
paypal_transaction_id TEXT,
|
||||
paypal_event_id TEXT UNIQUE,
|
||||
amount TEXT,
|
||||
currency TEXT DEFAULT 'EUR',
|
||||
payment_status TEXT NOT NULL, -- completed | failed | refunded | reversed
|
||||
is_sandbox INTEGER NOT NULL DEFAULT 0, -- Testzahlungen zählen NIE als echter Monat
|
||||
counted_for_progress INTEGER NOT NULL DEFAULT 0,
|
||||
paid_at TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Supporter-Kollektionen (Abschnitt 14) — jeder abgeschlossene 30-Monats-
|
||||
-- Zyklus bekommt ein neues Design. Zyklus-Nummer 1 = Kollektion 01 usw.
|
||||
-- collection_number ist der 1-basierte Zyklus-Index (global, nicht pro
|
||||
-- Supporter — alle Supporter im selben Zyklus teilen sich EIN Design).
|
||||
CREATE TABLE IF NOT EXISTS supporter_collections (
|
||||
id TEXT PRIMARY KEY,
|
||||
collection_number INTEGER NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
theme TEXT,
|
||||
description TEXT,
|
||||
cover_image TEXT,
|
||||
small_teddy_design TEXT,
|
||||
medium_teddy_design TEXT,
|
||||
large_teddy_design TEXT,
|
||||
mug_design TEXT,
|
||||
card_design TEXT,
|
||||
hoodie_design TEXT,
|
||||
available_hoodie_sizes TEXT DEFAULT '["S","M","L","XL","XXL"]', -- JSON-Array
|
||||
status TEXT NOT NULL DEFAULT 'draft', -- draft | published
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Eine Zeile pro freigeschaltetem Meilenstein/Prämie eines Supporters.
|
||||
-- milestone_month ∈ {6,12,18,24,30}, cycle_number = welcher 30er-Zyklus.
|
||||
CREATE TABLE IF NOT EXISTS supporter_premiums (
|
||||
id TEXT PRIMARY KEY,
|
||||
supporter_id TEXT NOT NULL REFERENCES supporter_users(id),
|
||||
collection_id TEXT NOT NULL REFERENCES supporter_collections(id),
|
||||
cycle_number INTEGER NOT NULL,
|
||||
milestone_month INTEGER NOT NULL, -- 6 | 12 | 18 | 24 | 30
|
||||
premium_type TEXT NOT NULL, -- teddy_klein | teddy_mittel | teddy_gross | tasse_karte | hoodie
|
||||
unlocked_at TEXT NOT NULL,
|
||||
redeem_status TEXT NOT NULL DEFAULT 'verfuegbar',
|
||||
-- verfuegbar | eingeloest | wird_geprueft | wird_vorbereitet
|
||||
-- versandbereit | versendet | zugestellt | erhalten | problem | ersatz_wird_vorbereitet
|
||||
redeemed_at TEXT,
|
||||
hoodie_size TEXT,
|
||||
hoodie_variant TEXT,
|
||||
ship_name TEXT, ship_street TEXT, ship_zip TEXT, ship_city TEXT, ship_country TEXT,
|
||||
tracking_number TEXT,
|
||||
shipped_at TEXT,
|
||||
delivered_at TEXT,
|
||||
admin_note TEXT,
|
||||
UNIQUE (supporter_id, cycle_number, milestone_month)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_supp_sub_supporter ON supporter_subscriptions(supporter_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_supp_pay_supporter ON supporter_payments(supporter_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_supp_pay_sub ON supporter_payments(subscription_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_supp_premiums_supporter ON supporter_premiums(supporter_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_supp_sessions_supporter ON supporter_sessions(supporter_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_supp_codes_supporter ON supporter_auth_codes(supporter_id);
|
||||
|
||||
-- Kollektion 01 direkt mit anlegen, damit das System sofort nutzbar ist —
|
||||
-- Designs/Bilder können jederzeit im Admin-Bereich nachgepflegt werden.
|
||||
INSERT OR IGNORE INTO supporter_collections (id, collection_number, name, theme, description, status, created_at)
|
||||
VALUES ('collection-01', 1, 'Der Anfang', 'Babyblau & Silber', 'Die allererste Supporter-Kollektion von Dogfather × VanVan.', 'published', datetime('now'));
|
||||
Reference in New Issue
Block a user