-- ===================================================================== -- DOGFATHER UNIVERSE — Interner Bereich: Datenbankschema -- Setzt "Geschuetzter_Zugang_Rollen_Benutzerverwaltung.pdf" um. -- ===================================================================== -- Rollen: frei erstellbar/umbenennbar durch den Hauptadministrator (Owner). -- Die Owner-Rolle selbst ist NICHT in dieser Tabelle — sie ist fest an das -- POSTFACH_CODE-Secret gebunden und kann nicht gelöscht/verändert werden. CREATE TABLE IF NOT EXISTS roles ( id TEXT PRIMARY KEY, name TEXT NOT NULL, permissions TEXT NOT NULL DEFAULT '[]', -- JSON-Array erlaubter Permission-Keys created_at TEXT NOT NULL ); -- Zugänge/Teammitglieder. Jede Person hat einen eigenen Code. -- code_hash: SHA-256 für schnellen Login-Vergleich (nicht umkehrbar). -- code_enc: AES-GCM verschlüsselter Klartext-Code, NUR vom Owner nach -- Re-Auth entschlüsselbar (siehe crypto.js). Wird niemals an -- andere Personen oder über die API an Nicht-Owner ausgegeben. CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, name TEXT NOT NULL, username TEXT NOT NULL UNIQUE, email TEXT, role_id TEXT REFERENCES roles(id), code_hash TEXT, code_enc TEXT, status TEXT NOT NULL DEFAULT 'pending', -- pending | active | locked note TEXT, expires_at TEXT, -- NULL = dauerhaft created_at TEXT NOT NULL, created_by TEXT NOT NULL, last_login_at TEXT ); -- Individuelle Berechtigungs-Ausnahmen pro Person (haben Vorrang vor der Rolle). CREATE TABLE IF NOT EXISTS user_permission_overrides ( user_id TEXT NOT NULL REFERENCES users(id), permission TEXT NOT NULL, allowed INTEGER NOT NULL, -- 1 = zusätzlich erlaubt, 0 = entzogen PRIMARY KEY (user_id, permission) ); -- Sessions: token wird gehasht gespeichert (wie ein Passwort), nie im Klartext. CREATE TABLE IF NOT EXISTS sessions ( token_hash TEXT PRIMARY KEY, user_id TEXT NOT NULL, -- 'owner' oder users.id is_owner INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, last_active_at TEXT NOT NULL, expires_at TEXT NOT NULL ); -- Aktivitätsprotokoll — Codes erscheinen hier NIEMALS im Klartext. CREATE TABLE IF NOT EXISTS audit_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, actor TEXT NOT NULL, action TEXT NOT NULL, target TEXT, detail TEXT, created_at TEXT NOT NULL ); -- Login-Schutz: Fehlversuche pro Schlüssel (IP oder Benutzername) zählen, -- nach zu vielen Versuchen vorübergehend sperren. CREATE TABLE IF NOT EXISTS login_attempts ( key TEXT PRIMARY KEY, count INTEGER NOT NULL DEFAULT 0, locked_until TEXT, updated_at TEXT NOT NULL ); -- Bewerbungen (bisher in KV, jetzt in D1 für Status/Zuweisung/Notizen/Entwürfe). CREATE TABLE IF NOT EXISTS applications ( id TEXT PRIMARY KEY, type TEXT NOT NULL, -- creator | scout | kooperation data TEXT NOT NULL, -- JSON der Formularfelder status TEXT NOT NULL DEFAULT 'neu', -- neu | in_bearbeitung | beantwortet assigned_to TEXT, -- users.id oder 'owner' archived INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS application_notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, application_id TEXT NOT NULL REFERENCES applications(id), author TEXT NOT NULL, text TEXT NOT NULL, created_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS application_drafts ( id INTEGER PRIMARY KEY AUTOINCREMENT, application_id TEXT NOT NULL REFERENCES applications(id), author TEXT NOT NULL, content TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id); CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_log(created_at); CREATE INDEX IF NOT EXISTS idx_applications_status ON applications(status, archived); CREATE INDEX IF NOT EXISTS idx_notes_app ON application_notes(application_id); CREATE INDEX IF NOT EXISTS idx_drafts_app ON application_drafts(application_id);