-- Admin-Self-Service-Onboarding. -- ==================================================================== -- Aktuell muessen neue Admins manuell per SQL in admin_users eingefuegt -- werden. Dieser Workflow stellt einen Magic-Link-basierten Onboarding- -- Pfad bereit: -- -- 1. Bestehender Admin gibt eine E-Mail-Adresse ein → Eintrag in -- `admin_invites` mit Token (Hash) + Ablauf (48h). -- 2. System schickt Mail mit Aktivierungs-URL `/admin/aktivieren/`. -- 3. Empfaenger oeffnet URL, setzt Passwort, ggf. Anzeigename. -- → Eintrag in `admin_users` wird angelegt, Invite `used_at` gestempelt. -- -- Zusatz: `admin_users.role` macht Berechtigungs-Differenzierung -- moeglich. Default = 'admin' (Vollzugriff). Spaeter ist `viewer` denkbar -- (lesen-only), aktuell nicht implementiert. alter table public.admin_users add column if not exists name text, add column if not exists role text not null default 'admin' check (role in ('admin', 'viewer')), add column if not exists invited_by uuid references public.admin_users(id) on delete set null, add column if not exists last_login_at timestamptz; create table if not exists public.admin_invites ( id uuid primary key default gen_random_uuid(), email text not null, -- SHA256(token); Klartext-Token nur einmal in der Mail-URL. token_hash text not null, role text not null default 'admin' check (role in ('admin', 'viewer')), invited_by uuid references public.admin_users(id) on delete set null, created_at timestamptz not null default now(), expires_at timestamptz not null, used_at timestamptz, revoked_at timestamptz ); create index if not exists admin_invites_token_idx on public.admin_invites (token_hash) where used_at is null and revoked_at is null; create index if not exists admin_invites_email_idx on public.admin_invites (email) where used_at is null and revoked_at is null; alter table public.admin_invites enable row level security; -- Default deny — Zugriff nur ueber Service-Role (Admin-Pfade).