Clean up superseded profile migrations

This commit is contained in:
Ivan Cacciari
2026-08-31 17:15:58 +02:00
parent e4f963d170
commit 5a6aaad885
3 changed files with 135 additions and 0 deletions
@@ -1,89 +0,0 @@
-- M2 — Profilo Giocatore: dati personali, documento d'identità, certificato medico (DD-016)
-- Migration additiva: solo CREATE, nessuna modifica alle tabelle v1.0 esistenti.
-- I file non stanno qui: la tabella conserva solo i path dentro il bucket privato
-- `profili-giocatore` creato dalla migration M3.
CREATE TABLE public.profili_giocatore (
giocatore_id text PRIMARY KEY REFERENCES public.giocatori_squadra(id) ON DELETE CASCADE,
-- Dati personali richiesti dal tesseramento CSI
data_nascita date,
luogo_nascita text,
indirizzo text,
telefono text,
email text,
-- Documento di identità
documento_tipo text,
documento_numero text,
documento_rilasciato_da text,
documento_emissione date,
documento_scadenza date,
-- Il documento si carica fronte e retro: il CSI li vuole entrambi.
documento_fronte_path text,
documento_retro_path text,
-- Certificato medico (storico non conservato in v1: DD-010)
certificato_scadenza date,
certificato_path text,
-- Foto tessera
foto_path text,
creato_il timestamptz NOT NULL DEFAULT now(),
aggiornato_il timestamptz NOT NULL DEFAULT now()
);
COMMENT ON TABLE public.profili_giocatore IS
'Dati personali, documento e certificato di ciascun giocatore, 1:1 con giocatori_squadra. Vedi DD-016.';
CREATE TRIGGER update_profili_giocatore_aggiornato_il
BEFORE UPDATE ON public.profili_giocatore
FOR EACH ROW
EXECUTE FUNCTION public.update_aggiornato_il();
ALTER TABLE public.profili_giocatore ENABLE ROW LEVEL SECURITY;
-- Il giocatore vede e modifica solo il proprio profilo: il collegamento passa
-- da giocatori_squadra.auth_user_id, che solo un admin può riassegnare (M1).
CREATE POLICY "Il giocatore legge il proprio profilo" ON public.profili_giocatore
FOR SELECT TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = giocatore_id AND g.auth_user_id = auth.uid()
)
);
CREATE POLICY "Il giocatore crea il proprio profilo" ON public.profili_giocatore
FOR INSERT TO authenticated
WITH CHECK (
EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = giocatore_id AND g.auth_user_id = auth.uid()
)
);
CREATE POLICY "Il giocatore aggiorna il proprio profilo" ON public.profili_giocatore
FOR UPDATE TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = giocatore_id AND g.auth_user_id = auth.uid()
)
)
WITH CHECK (
EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = giocatore_id AND g.auth_user_id = auth.uid()
)
);
-- Gli admin leggono tutti i profili ed esportano i dati per il tesseramento.
CREATE POLICY "Gli admin gestiscono tutti i profili" ON public.profili_giocatore
FOR ALL TO authenticated
USING (public.has_role(auth.uid(), 'admin'::public.app_role))
WITH CHECK (public.has_role(auth.uid(), 'admin'::public.app_role));
GRANT SELECT, INSERT, UPDATE ON public.profili_giocatore TO authenticated;
GRANT ALL ON public.profili_giocatore TO service_role;
@@ -1,36 +0,0 @@
-- M3 — Bucket privato per documenti, certificati e foto tessera (DD-016 regole 3 e 4)
-- Migration additiva. Il bucket nasce privato e resta privato: documenti d'identità e
-- dati sanitari non devono mai essere raggiungibili da un URL pubblico. L'accesso avviene
-- solo con client autenticato o con signed URL a scadenza breve generata per gli admin.
INSERT INTO storage.buckets (id, name, public)
VALUES ('profili-giocatore', 'profili-giocatore', false)
ON CONFLICT (id) DO NOTHING;
-- Convenzione dei path: `<giocatore_id>/<sezione>.<estensione>` (es. `g4/certificato.pdf`).
-- La prima cartella è l'ID del giocatore: è così che si riconosce il proprietario del file.
CREATE POLICY "Il giocatore gestisce i propri file" ON storage.objects
FOR ALL TO authenticated
USING (
bucket_id = 'profili-giocatore'
AND EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = (storage.foldername(name))[1] AND g.auth_user_id = auth.uid()
)
)
WITH CHECK (
bucket_id = 'profili-giocatore'
AND EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = (storage.foldername(name))[1] AND g.auth_user_id = auth.uid()
)
);
-- Gli admin scaricano i file di tutti, ma non li modificano: i documenti restano
-- in mano al giocatore che li ha caricati.
CREATE POLICY "Gli admin scaricano tutti i file dei profili" ON storage.objects
FOR SELECT TO authenticated
USING (
bucket_id = 'profili-giocatore'
AND public.has_role(auth.uid(), 'admin'::public.app_role)
);
@@ -0,0 +1,135 @@
-- Correzione schema profili_giocatore (post 20260830123000)
--
-- Prerequisito: la migration 20260830123000 deve essere già applicata (schema doc_*,
-- enum doc_identita_tipo, funzione mio_giocatore_id, policy inglesi).
-- Porta il database allo schema atteso dal codice di develop (20260830120000 + 20100).
-- Non modifica giocatori_squadra né le tabelle v1.0.
-- Supabase avvolge ogni migration in una transazione: non serve BEGIN/COMMIT esplicito
-- (inserirli nel file può interferire con db push).
-- ── 1. Policy tabella: rimuovi quelle che dipendono da mio_giocatore_id() ───
DROP POLICY "Players can view own profile" ON public.profili_giocatore;
DROP POLICY "Players can insert own profile" ON public.profili_giocatore;
DROP POLICY "Players can update own profile" ON public.profili_giocatore;
-- Policy admin separata: va sostituita dal modello Davide (FOR ALL).
DROP POLICY "Admins can delete profiles" ON public.profili_giocatore;
-- ── 2. Policy Storage: tutte usano mio_giocatore_id() ──────────────────────
DROP POLICY "Players can read own profile files" ON storage.objects;
DROP POLICY "Players can upload own profile files" ON storage.objects;
DROP POLICY "Players can overwrite own profile files" ON storage.objects;
DROP POLICY "Players can delete own profile files" ON storage.objects;
-- ── 3. Trigger e funzione PK enforcement (assenti nello schema Davide) ─────
DROP TRIGGER enforce_profili_giocatore_pk ON public.profili_giocatore;
DROP FUNCTION public.enforce_profili_giocatore_pk();
-- ── 4. Vincolo sulle date documento (prima delle rinomine di colonna) ────────
ALTER TABLE public.profili_giocatore
DROP CONSTRAINT profilo_date_doc_valide;
-- ── 5. doc_tipo enum → documento_tipo text (valori UI del codice) ──────────
ALTER TABLE public.profili_giocatore
ALTER COLUMN doc_tipo TYPE text
USING (
CASE doc_tipo::text
WHEN 'carta_identita' THEN 'Carta d''identità'
WHEN 'patente' THEN 'Patente'
WHEN 'passaporto' THEN 'Passaporto'
ELSE doc_tipo::text
END
);
ALTER TABLE public.profili_giocatore
RENAME COLUMN doc_tipo TO documento_tipo;
-- ── 6. Rinomina colonne allo schema atteso da profili-core.ts ───────────────
ALTER TABLE public.profili_giocatore RENAME COLUMN doc_numero TO documento_numero;
ALTER TABLE public.profili_giocatore RENAME COLUMN doc_rilasciato_da TO documento_rilasciato_da;
ALTER TABLE public.profili_giocatore RENAME COLUMN doc_data_emissione TO documento_emissione;
ALTER TABLE public.profili_giocatore RENAME COLUMN doc_data_scadenza TO documento_scadenza;
ALTER TABLE public.profili_giocatore RENAME COLUMN doc_fronte_path TO documento_fronte_path;
ALTER TABLE public.profili_giocatore RENAME COLUMN doc_retro_path TO documento_retro_path;
ALTER TABLE public.profili_giocatore RENAME COLUMN cert_scadenza TO certificato_scadenza;
ALTER TABLE public.profili_giocatore RENAME COLUMN cert_file_path TO certificato_path;
ALTER TABLE public.profili_giocatore RENAME COLUMN foto_tessera_path TO foto_path;
-- ── 7. Colonna non usata dal codice ─────────────────────────────────────────
ALTER TABLE public.profili_giocatore DROP COLUMN avatar_path;
-- ── 8. Oggetti della migration 123000 non più necessari ─────────────────────
DROP FUNCTION public.mio_giocatore_id();
DROP TYPE public.doc_identita_tipo;
COMMENT ON TABLE public.profili_giocatore IS
'Dati personali, documento e certificato di ciascun giocatore, 1:1 con giocatori_squadra. Vedi DD-016.';
-- ── 9. RLS tabella (modello Davide, DD-017) ─────────────────────────────────
CREATE POLICY "Il giocatore legge il proprio profilo" ON public.profili_giocatore
FOR SELECT TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = giocatore_id AND g.auth_user_id = auth.uid()
)
);
CREATE POLICY "Il giocatore crea il proprio profilo" ON public.profili_giocatore
FOR INSERT TO authenticated
WITH CHECK (
EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = giocatore_id AND g.auth_user_id = auth.uid()
)
);
CREATE POLICY "Il giocatore aggiorna il proprio profilo" ON public.profili_giocatore
FOR UPDATE TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = giocatore_id AND g.auth_user_id = auth.uid()
)
)
WITH CHECK (
EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = giocatore_id AND g.auth_user_id = auth.uid()
)
);
CREATE POLICY "Gli admin gestiscono tutti i profili" ON public.profili_giocatore
FOR ALL TO authenticated
USING (public.has_role(auth.uid(), 'admin'::public.app_role))
WITH CHECK (public.has_role(auth.uid(), 'admin'::public.app_role));
-- ── 10. Policy Storage (DD-017: admin solo lettura) ─────────────────────────
CREATE POLICY "Il giocatore gestisce i propri file" ON storage.objects
FOR ALL TO authenticated
USING (
bucket_id = 'profili-giocatore'
AND EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = (storage.foldername(name))[1] AND g.auth_user_id = auth.uid()
)
)
WITH CHECK (
bucket_id = 'profili-giocatore'
AND EXISTS (
SELECT 1 FROM public.giocatori_squadra g
WHERE g.id = (storage.foldername(name))[1] AND g.auth_user_id = auth.uid()
)
);
CREATE POLICY "Gli admin scaricano tutti i file dei profili" ON storage.objects
FOR SELECT TO authenticated
USING (
bucket_id = 'profili-giocatore'
AND public.has_role(auth.uid(), 'admin'::public.app_role)
);
-- ── 11. Bucket: resta privato; limiti MIME/dimensione invariati ─────────────
UPDATE storage.buckets
SET public = false
WHERE id = 'profili-giocatore';