Selvbetjent sammenslåing av to TeeCup-kontoer: keeper (initiativtaker) ber om sammenslåing, bekreftelseslenke sendt til taperens e-post beviser eierskap, taperens data (org-medlemskap/spillerkoblinger/runder/venner) flyttes over og taperens konto slettes. Ny migrasjon 077 (account_merge_ token, ikke kjørt mot ekte teecup_db ennå), ny app/account_merge.py (N+1-transaksjoner per RLS-grensen, fullt konfliktkart), nye endepunkter i app/routers/account_merge.py, ny frontend-seksjon i kontoinnstillinger + egen bekreftelsesside. Fant og fikset en reell RLS-relatert bug via testsuiten før produksjon: seks RLS-beskyttede tabeller var feilaktig plassert i den globale "trygt å re-peke"-løkken, forårsaket et krasj pga. en Postgres GUC-kvirk på pooled forbindelser. Se ADR-080 for full begrunnelse. 12 nye tester (95/95 backend totalt), full scratch-verifisert ende-til-ende inkl. lys/mørk, ekte teecup_db urørt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
42 lines
2.2 KiB
SQL
42 lines
2.2 KiB
SQL
-- =====================================================================
|
|
-- TeeCup — kontosammenslåing, "Del 2" av flere-e-postadresser (migrasjon 077)
|
|
-- =====================================================================
|
|
-- Oppfølging av ADR-032/migrasjon 017 (sekundær e-post) -- "Del 1" dekket
|
|
-- KUN det enkle tilfellet (fri, ukrevd adresse). Del 2: hva skjer når
|
|
-- adressen som legges til ALLEREDE er en annen, eksisterende kontos
|
|
-- primær- eller sekundæradresse -- samme reelle person har endt opp med
|
|
-- to separate TeeCup-kontoer. Selvbetjent (bruker bekreftet eksplisitt).
|
|
--
|
|
-- Samme token-hash-og-utløp-mønster som magic_link_token (004) ->
|
|
-- email_change_token (016) -> secondary_email_token (017): bevis
|
|
-- eierskap av MÅL-kontoens e-post FØR selve sammenslåingen utføres.
|
|
-- Lenken sendes til MÅL-kontoens (taperens) e-post -- beviser eierskap av
|
|
-- DEN kontoen, ikke bare at initiativtakeren (keeperen) fortsatt er
|
|
-- innlogget, samme prinsipp som ADR-032 Beslutning B.
|
|
--
|
|
-- `initiator_user_id`/`target_user_id` er BEVISST asymmetriske roller,
|
|
-- ikke to likeverdige parter: initiator (keeper) er den som ber om
|
|
-- sammenslåingen fra en aktiv økt, target (taper) er kontoen som slås
|
|
-- INN i keeperen og til slutt slettes (se app/account_merge.py -- ingen
|
|
-- sesjons-tilbakekallingsmekanisme finnes i denne appen, sletting av
|
|
-- app_user-raden er eneste måte å tvinge ut en gjenlevende
|
|
-- øktinformasjonskapsel for taper-kontoen).
|
|
-- =====================================================================
|
|
|
|
\set ON_ERROR_STOP on
|
|
|
|
CREATE TABLE account_merge_token (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
initiator_user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
|
|
target_user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
|
|
token_hash text NOT NULL UNIQUE,
|
|
expires_at timestamptz NOT NULL,
|
|
consumed_at timestamptz,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
CHECK (initiator_user_id <> target_user_id)
|
|
);
|
|
|
|
CREATE INDEX ON account_merge_token (initiator_user_id);
|
|
CREATE INDEX ON account_merge_token (target_user_id);
|
|
|
|
GRANT SELECT, INSERT, UPDATE ON account_merge_token TO teecup_app;
|