-- ===================================================================== -- TeeCup — migrasjon 004 -- Ekte autentisering: magic-link + JWT-sesjon -- ===================================================================== -- Kjøres etter 001 (skjema), 002 (roller) og 003 (scoring/blind draw). -- -- MERK om nummerering: dette klaimer migrasjonsnummer 004, som CLAUDE.md/ -- FEATURE_BACKLOG løst har forutsatt til en fremtidig "kommunikasjon"- -- migrasjon — den blir 005 i stedet. Ren nummerkonvensjon, ingen teknisk -- konflikt. -- ===================================================================== \set ON_ERROR_STOP on -- --------------------------------------------------------------------- -- 1. Unik e-post (mangler i 001 — nødvendig for at magic-link-flyten skal -- kunne bruke e-post som race-trygg oppslagsnøkkel via ON CONFLICT). -- --------------------------------------------------------------------- CREATE UNIQUE INDEX app_user_email_unique ON app_user (email) WHERE email IS NOT NULL; -- --------------------------------------------------------------------- -- 2. Magic-link-tokens -- --------------------------------------------------------------------- -- Lagrer e-post, IKKE en user_id-FK: app_user-raden opprettes først når -- noen faktisk beviser eierskap ved å løse inn en gyldig, uforbrukt token -- (se app/routers/auth.py) — ikke når lenken bare forespørres. Dette er -- identitetsnivå (som app_user), ingen organization_id/RLS. CREATE TABLE magic_link_token ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), email citext NOT NULL, token_hash text NOT NULL UNIQUE, expires_at timestamptz NOT NULL, consumed_at timestamptz, created_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX ON magic_link_token (email); -- Grants til runtime-rollen (den eier ikke tabellen, så den trenger eksplisitt DML). GRANT SELECT, INSERT, UPDATE, DELETE ON magic_link_token TO teecup_app;