Flytte is_participant-logikk til team_authz.py (unngå sirkulær import)
Widen scoring.py: get_scorecard/submit_hole_score/submit_hole_result/concede_match
Widen matches.py: list_matches/add_participant/remove_participant/lock_lineup
Widen tournaments.py: list_sessions/list_teams/concede_tournament
Widen courses.py: list_holes
Widen messaging.py: team chat REST-endepunkter (list/send/delete)
Legge til my_session_id/my_match_id i /auth/me sin my_tournaments
Frontend: legge til lenker til lag-chat/scorekort fra «Mine runder»
Scratch-verifisere hele deltaker-tilgang-runden (positive + negative kontroller)
Ekte typesjekket frontend-produksjonsbuild + backend py_compile på nytt før deploy-forslag
Presentere plan, deploye og oppdatere .md-filer for deltaker-tilgang-runden
Bygge og scratch-verifisere sekundær e-postadresse (migrasjon 017)
Bygge HCP-historikk over tid
Sekundær e-postadresse (det enkle tilfellet) er bygget og scratch-verifisert (20/20 sjekker), test_isolation.sql fortsatt 12/12.
Hva er bygget:
Migrasjon 017_secondary_email.sql — to nye tabeller (secondary_email_token, user_secondary_email), samme bevis-eierskap-token-mønster som ADR-032.
Backend: POST /auth/secondary-email (send bekreftelseslenke), POST /auth/secondary-email/confirm (bekreft, ingen sesjon påkrevd), DELETE /auth/secondary-email/{id}. Viktigst: verify_magic_link og login_with_password løser nå en sekundær adresse til den eksisterende eierens konto i stedet for å opprette en ny, separat konto — dette er selve poenget med funksjonen.
Frontend: ny seksjon "Andre e-postadresser" i /account (ikke dashbordet — se merknad under), /verify-email håndterer nå både e-postbytte og ny-sekundær-adresse via en ?kind=secondary-parameter.
Én bevisst plasseringsavgjørelse jeg tok uten å spørre: du sa opprinnelig at hele multi-e-post-flyten burde skje "fra dashboard-siden". Jeg la likevel dette i /account, fordi jeg her kun bygger det enkle tilfellet (fri adresse) — konsistent med hvor e-postbytte (ADR-032) allerede ligger. Når/hvis den harde saken (ekte konto-sammenslåing, der data faktisk "dukker opp") bygges senere, er dashbordet trolig riktigere siden gevinsten vises der. Si fra hvis du vil at den skal flyttes allerede nå.
Verifisert grundig: ny sekundær-adresse legges IKKE til før bekreftet; token kan ikke gjenbrukes; adresse som allerede er en annens hovedadresse ELLER en annens sekundæradresse avvises tydelig; innlogging (magic-link OG passord) via sekundæradressen løses korrekt til samme, eksisterende konto; en fremmed kan ikke slette andres sekundæradresse; og — kritisk — etter sletting oppretter en ny innlogging på den adressen en helt ny, separat konto (beviser fjerningen er reell).
Ingen migrasjon kjørt mot ekte teecup_db ennå.
49 lines
2.5 KiB
SQL
49 lines
2.5 KiB
SQL
-- =====================================================================
|
|
-- TeeCup — sekundær, verifisert e-postadresse per konto (migrasjon 017)
|
|
-- =====================================================================
|
|
-- Oppfølging av ADR-032 (verifisert e-postbytte), reist av brukeren rett
|
|
-- etterpå: én person kan ha flere e-postadresser i omløp samtidig (privat
|
|
-- vs. jobb-adresse en organisator har lagt inn en spiller/invitasjon på).
|
|
-- Dette dekker BEVISST kun det enkle tilfellet -- en FRI, ukrevd adresse
|
|
-- legges til og verifiseres. Ekte konto-SAMMENSLÅING (adressen tilhører
|
|
-- allerede en annen, eksisterende konto) er en egen, større, separat sak
|
|
-- (se FEATURE_BACKLOG.md "Én person, flere e-postadresser") og håndheves
|
|
-- IKKE her -- unikheten under garanterer at en adresse aldri kan stå som
|
|
-- sekundær på to kontoer samtidig (samme rad ville krevd en eksplisitt
|
|
-- sammenslåingsbeslutning som ikke finnes ennå).
|
|
--
|
|
-- To tabeller, samme token-hash-og-utløp-mønster som email_change_token
|
|
-- (016): en midlertidig verifiseringstoken (bevis eierskap FØR raden
|
|
-- faktisk opprettes -- unngår en "krevd men aldri bekreftet"-adresse som
|
|
-- likevel opptar en unik plass), og selve den verifiserte adressen.
|
|
-- =====================================================================
|
|
|
|
\set ON_ERROR_STOP on
|
|
|
|
CREATE TABLE secondary_email_token (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
|
|
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 secondary_email_token (user_id);
|
|
|
|
CREATE TABLE user_secondary_email (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
|
|
-- Globalt unik -- kan aldri stå som sekundær på to kontoer samtidig,
|
|
-- og aldri samtidig være en ANNEN kontos primære e-post (håndhevet i
|
|
-- app-laget ved innsetting, se app/routers/auth.py -- en ren DB-CHECK
|
|
-- på tvers av to tabeller er ikke mulig i Postgres).
|
|
email citext NOT NULL UNIQUE,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX ON user_secondary_email (user_id);
|
|
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON secondary_email_token TO teecup_app;
|
|
GRANT SELECT, INSERT, DELETE ON user_secondary_email TO teecup_app;
|