-- ===================================================================== -- TeeCup — migrasjon 009 -- Landingssider: synlighet, org-profil, sponsorer (ADR-018) -- ===================================================================== -- Kjøres etter 001-008. Alt additivt (nullable eller trygg default). -- ===================================================================== \set ON_ERROR_STOP on -- --------------------------------------------------------------------- -- 1. Turnering: synlighet + presenterende tekst (ADR-018 Beslutning A/E) -- -- Default 'org' -- ingen eksisterende eller nyopprettet turnering blir -- offentlig av seg selv, organisator må aktivt velge å åpne opp. -- --------------------------------------------------------------------- ALTER TABLE tournament ADD COLUMN visibility text NOT NULL DEFAULT 'org' CHECK (visibility IN ('public', 'org', 'participants')); ALTER TABLE tournament ADD COLUMN description text; -- Inert til MinIO-runden (bevisst utsatt, se ADR-018) -- kun kolonnen, -- ingen opplastingslogikk. ALTER TABLE tournament ADD COLUMN hero_image_key text; -- --------------------------------------------------------------------- -- 2. Organisasjon: offentlig profil (ADR-018 Beslutning F) -- -- MERK: `organization.slug` finnes ALLEREDE, helt siden migrasjon 001 -- ("f.eks. subdomene/URL-vennlig", plain UNIQUE -- Postgres sin UNIQUE -- behandler NULL som distinkt fra NULL, så "unik når satt" er allerede -- garantert uten en egen partiell indeks). Oppdaget ved at denne -- migrasjonen først feilet mot en fersk scratch-database ("column slug -- already exists") -- IKKE lagt til på nytt her, kun brukt. -- --------------------------------------------------------------------- ALTER TABLE organization ADD COLUMN public_profile boolean NOT NULL DEFAULT false; ALTER TABLE organization ADD CONSTRAINT organization_slug_format CHECK (slug IS NULL OR slug ~ '^[a-z0-9]+(-[a-z0-9]+)*$'); ALTER TABLE organization ADD CONSTRAINT organization_public_profile_requires_slug CHECK (NOT public_profile OR slug IS NOT NULL); -- --------------------------------------------------------------------- -- 3. Sponsorer (ADR-018 Beslutning E) -- navn+lenke aktivt, logo inert -- til MinIO-runden. -- --------------------------------------------------------------------- CREATE TABLE tournament_sponsor ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), organization_id uuid NOT NULL, tournament_id uuid NOT NULL, name text NOT NULL, url text, logo_key text, -- inert til MinIO-runden created_at timestamptz NOT NULL DEFAULT now(), FOREIGN KEY (organization_id, tournament_id) REFERENCES tournament(organization_id, id) ON DELETE CASCADE ); CREATE INDEX ON tournament_sponsor (organization_id, tournament_id); ALTER TABLE tournament_sponsor ENABLE ROW LEVEL SECURITY; ALTER TABLE tournament_sponsor FORCE ROW LEVEL SECURITY; CREATE POLICY org_isolation ON tournament_sponsor USING (organization_id = app_current_org()) WITH CHECK (organization_id = app_current_org()); GRANT SELECT, INSERT, UPDATE, DELETE ON tournament_sponsor TO teecup_app; -- --------------------------------------------------------------------- -- 4. public_org_by_slug() -- tredje SECURITY DEFINER-bro i dette -- prosjektet (etter public_tournament_org 007, link_player_by_email -- 008), samme mønster: løs kontekst-problemet FØR RLS kan håndheve -- noe. Returnerer NULL for BÅDE "finnes ikke" og "finnes, men er -- privat" -- samme anti-enumerering som magic-link (ADR-009). -- --------------------------------------------------------------------- CREATE FUNCTION public_org_by_slug(p_slug text) RETURNS uuid LANGUAGE sql SECURITY DEFINER SET search_path = public STABLE AS $$ SELECT id FROM organization WHERE slug = p_slug AND public_profile = true; $$; GRANT EXECUTE ON FUNCTION public_org_by_slug(text) TO teecup_app;