-- ===================================================================== -- TeeCup — Slag-for-slag GPS-avstandsmåling for org-turneringer, -- migrasjon 091 (ADR-103). Speiler 060_round_shot.sql/ -- 061_round_shot_end_method.sql (ADR-048, frittstående runder) -- strukturelt, men org-scopet (RLS) og med en annen eierskaps-nøkkel. -- -- Eierskap: FK direkte til (organization_id, tournament_round_ -- participant_id) + hole_number -- IKKE tournament_round_hole_id. -- `tournament_round_hole` opprettes (ulikt frittstående round_hole, -- som pre-oppretter alle 18 ved rundestart) FØRST ved første -- score-innsending (update_hole sin INSERT ... ON CONFLICT, -- individual_tournaments.py) -- en spiller skal kunne måle et slag -- FØR de fullfører hullets score, så en FK mot en hull-rad som kanskje -- ikke finnes ennå ville vært feil. Samme LEFT JOIN-tolerante mønster -- som get_tournament_round_hole_target_points/list_round_participant_ -- holes allerede bruker for nøyaktig dette problemet. -- -- Turneringsmodellen har ALDRI en side/lag-XOR (kun individuelt) -- -- ingen tilsvarende round_side-gren trengs her, ulikt round_shot. -- -- Koordinater: samme rene double precision lat/lng-par som round_shot -- (ADR-048 Beslutning D) -- ingen PostGIS. -- ===================================================================== \set ON_ERROR_STOP on CREATE TABLE tournament_round_shot ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), organization_id uuid NOT NULL, tournament_round_participant_id uuid NOT NULL, hole_number smallint NOT NULL CHECK (hole_number BETWEEN 1 AND 18), -- Hvem som MÅLTE slaget -- ikke nødvendigvis samme som deltakeren selv, -- samme "en lenket medspiller/org-admin kan føre" som update_hole. recorded_by_user_id uuid NOT NULL REFERENCES app_user(id), -- Eksplisitt, hull-tolerant rekkefølge (IKKE ORDER BY captured_at) -- -- samme begrunnelse som round_shot.shot_number. shot_number integer NOT NULL CHECK (shot_number > 0), club text NOT NULL CHECK (char_length(club) <= 50), distance_meters numeric(6,1) NOT NULL CHECK (distance_meters > 0 AND distance_meters < 500), start_method text NOT NULL CHECK (start_method IN ('gps', 'map_tap')), start_lat double precision NOT NULL CHECK (start_lat BETWEEN -90 AND 90), start_lng double precision NOT NULL CHECK (start_lng BETWEEN -180 AND 180), end_method text NOT NULL CHECK (end_method IN ('gps', 'map_tap')) DEFAULT 'gps', end_lat double precision NOT NULL CHECK (end_lat BETWEEN -90 AND 90), end_lng double precision NOT NULL CHECK (end_lng BETWEEN -180 AND 180), -- Deling til den rundespesifikke kommentartråden (ADR-102) -- lenke, -- ikke bare et bool-flagg, samme prinsipp som round_shot. shared_tournament_round_message_id uuid REFERENCES tournament_round_message(id) ON DELETE SET NULL, captured_at timestamptz NOT NULL DEFAULT now(), FOREIGN KEY (organization_id, tournament_round_participant_id) REFERENCES tournament_round_participant(organization_id, id) ON DELETE CASCADE, UNIQUE (tournament_round_participant_id, hole_number, shot_number) ); CREATE INDEX ON tournament_round_shot (organization_id, tournament_round_participant_id, hole_number, shot_number); DO $$ BEGIN ALTER TABLE tournament_round_shot ENABLE ROW LEVEL SECURITY; ALTER TABLE tournament_round_shot FORCE ROW LEVEL SECURITY; CREATE POLICY org_isolation ON tournament_round_shot USING (organization_id = current_setting('app.current_org', true)::uuid) WITH CHECK (organization_id = current_setting('app.current_org', true)::uuid); END $$; -- Samme "slett og opprett på nytt, aldri rediger"-prinsipp som round_shot -- -- ett smalt UPDATE-unntak for delings-lenken. GRANT SELECT, INSERT, DELETE ON tournament_round_shot TO teecup_app; GRANT UPDATE (shared_tournament_round_message_id) ON tournament_round_shot TO teecup_app;