veza/veza-backend-api/migrations_legacy/047_migrate_users_id_to_uuid.sql
okinrev 1ef0e0d6d6 P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.

Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.

Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).

Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.

Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 11:14:38 +01:00

307 lines
12 KiB
SQL

-- Migration: Convertir users.id de BIGINT vers UUID
-- CRITIQUE: Cette migration doit être exécutée AVANT tout déploiement utilisant les nouveaux modèles UUID
-- Date: 2024-11-27
-- Impact: BREAKING CHANGE - Toutes les FK doivent être migrées
-- =====================================================
-- ÉTAPE 1: Créer une colonne temporaire UUID
-- =====================================================
-- Activer l'extension UUID si pas déjà fait
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- Pour gen_random_uuid()
-- Ajouter une colonne temporaire pour stocker les nouveaux UUIDs
ALTER TABLE users ADD COLUMN IF NOT EXISTS id_uuid UUID;
-- Générer un UUID pour chaque utilisateur existant (mapping déterministe depuis l'ID)
-- Note: On utilise uuid_generate_v5 pour créer un UUID déterministe basé sur l'ID existant
UPDATE users
SET id_uuid = uuid_generate_v5(
'6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid, -- Namespace UUID arbitraire mais fixe
id::text
)
WHERE id_uuid IS NULL;
-- =====================================================
-- ÉTAPE 2: Migrer les tables dépendantes (FK)
-- =====================================================
-- Pour chaque table avec user_id en BIGINT, créer une colonne temporaire UUID
-- user_roles
ALTER TABLE user_roles ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE user_roles ur
SET user_id_uuid = u.id_uuid
FROM users u
WHERE ur.user_id = u.id AND ur.user_id_uuid IS NULL;
-- tracks
ALTER TABLE tracks ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE tracks t
SET user_id_uuid = u.id_uuid
FROM users u
WHERE t.user_id = u.id AND t.user_id_uuid IS NULL;
-- playlists
ALTER TABLE playlists ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE playlists p
SET user_id_uuid = u.id_uuid
FROM users u
WHERE p.user_id = u.id AND p.user_id_uuid IS NULL;
-- refresh_tokens
ALTER TABLE refresh_tokens ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE refresh_tokens rt
SET user_id_uuid = u.id_uuid
FROM users u
WHERE rt.user_id = u.id AND rt.user_id_uuid IS NULL;
-- sessions (déjà en UUID, mais vérifier cohérence)
-- Si sessions.user_id est déjà UUID, créer un mapping inverse
-- Note: Cette table semble déjà utiliser UUID, donc on va juste s'assurer de la cohérence
-- UPDATE sessions s SET user_id = u.id_uuid FROM users u WHERE ... (si nécessaire)
-- messages
ALTER TABLE messages ADD COLUMN IF NOT EXISTS sender_id_uuid UUID;
UPDATE messages m
SET sender_id_uuid = u.id_uuid
FROM users u
WHERE m.sender_id = u.id AND m.sender_id_uuid IS NULL;
-- rooms (owner_id)
ALTER TABLE rooms ADD COLUMN IF NOT EXISTS owner_id_uuid UUID;
UPDATE rooms r
SET owner_id_uuid = u.id_uuid
FROM users u
WHERE r.owner_id = u.id AND r.owner_id_uuid IS NULL;
-- room_members
ALTER TABLE room_members ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE room_members rm
SET user_id_uuid = u.id_uuid
FROM users u
WHERE rm.user_id = u.id AND rm.user_id_uuid IS NULL;
-- track_likes
ALTER TABLE track_likes ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE track_likes tl
SET user_id_uuid = u.id_uuid
FROM users u
WHERE tl.user_id = u.id AND tl.user_id_uuid IS NULL;
-- track_comments
ALTER TABLE track_comments ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE track_comments tc
SET user_id_uuid = u.id_uuid
FROM users u
WHERE tc.user_id = u.id AND tc.user_id_uuid IS NULL;
-- track_shares
ALTER TABLE track_shares ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE track_shares ts
SET user_id_uuid = u.id_uuid
FROM users u
WHERE ts.user_id = u.id AND ts.user_id_uuid IS NULL;
-- playlist_collaborators
ALTER TABLE playlist_collaborators ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE playlist_collaborators pc
SET user_id_uuid = u.id_uuid
FROM users u
WHERE pc.user_id = u.id AND pc.user_id_uuid IS NULL;
-- playlist_follows
ALTER TABLE playlist_follows ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE playlist_follows pf
SET user_id_uuid = u.id_uuid
FROM users u
WHERE pf.user_id = u.id AND pf.user_id_uuid IS NULL;
-- user_settings
ALTER TABLE user_settings ADD COLUMN IF NOT EXISTS user_id_uuid UUID;
UPDATE user_settings us
SET user_id_uuid = u.id_uuid
FROM users u
WHERE us.user_id = u.id AND us.user_id_uuid IS NULL;
-- =====================================================
-- ÉTAPE 3: Supprimer anciennes colonnes et renommer UUID
-- =====================================================
-- NOTE: Ces étapes sont DESTRUCTIVES et ne peuvent être annulées sans backup
-- En production, exécuter avec précaution et APRÈS validation complète
-- Supprimer les anciennes FK constraints
ALTER TABLE user_roles DROP CONSTRAINT IF EXISTS user_roles_user_id_fkey;
ALTER TABLE tracks DROP CONSTRAINT IF EXISTS tracks_user_id_fkey;
ALTER TABLE playlists DROP CONSTRAINT IF EXISTS playlists_user_id_fkey;
ALTER TABLE refresh_tokens DROP CONSTRAINT IF EXISTS refresh_tokens_user_id_fkey;
ALTER TABLE messages DROP CONSTRAINT IF EXISTS messages_sender_id_fkey;
ALTER TABLE rooms DROP CONSTRAINT IF EXISTS rooms_owner_id_fkey;
ALTER TABLE room_members DROP CONSTRAINT IF EXISTS room_members_user_id_fkey;
ALTER TABLE track_likes DROP CONSTRAINT IF EXISTS track_likes_user_id_fkey;
ALTER TABLE track_comments DROP CONSTRAINT IF EXISTS track_comments_user_id_fkey;
ALTER TABLE track_shares DROP CONSTRAINT IF EXISTS track_shares_user_id_fkey;
ALTER TABLE playlist_collaborators DROP CONSTRAINT IF EXISTS playlist_collaborators_user_id_fkey;
ALTER TABLE playlist_follows DROP CONSTRAINT IF EXISTS playlist_follows_user_id_fkey;
ALTER TABLE user_settings DROP CONSTRAINT IF EXISTS user_settings_user_id_fkey;
-- Supprimer anciennes colonnes INT
ALTER TABLE user_roles DROP COLUMN IF EXISTS user_id;
ALTER TABLE tracks DROP COLUMN IF EXISTS user_id;
ALTER TABLE playlists DROP COLUMN IF EXISTS user_id;
ALTER TABLE refresh_tokens DROP COLUMN IF EXISTS user_id;
ALTER TABLE messages DROP COLUMN IF EXISTS sender_id;
ALTER TABLE rooms DROP COLUMN IF EXISTS owner_id;
ALTER TABLE room_members DROP COLUMN IF EXISTS user_id;
ALTER TABLE track_likes DROP COLUMN IF EXISTS user_id;
ALTER TABLE track_comments DROP COLUMN IF EXISTS user_id;
ALTER TABLE track_shares DROP COLUMN IF EXISTS user_id;
ALTER TABLE playlist_collaborators DROP COLUMN IF EXISTS user_id;
ALTER TABLE playlist_follows DROP COLUMN IF EXISTS user_id;
ALTER TABLE user_settings DROP COLUMN IF EXISTS user_id;
-- Renommer colonnes UUID vers le nom standard
ALTER TABLE user_roles RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE tracks RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE playlists RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE refresh_tokens RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE messages RENAME COLUMN sender_id_uuid TO sender_id;
ALTER TABLE rooms RENAME COLUMN owner_id_uuid TO owner_id;
ALTER TABLE room_members RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE track_likes RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE track_comments RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE track_shares RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE playlist_collaborators RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE playlist_follows RENAME COLUMN user_id_uuid TO user_id;
ALTER TABLE user_settings RENAME COLUMN user_id_uuid TO user_id;
-- Définir NOT NULL sur les colonnes
ALTER TABLE user_roles ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE tracks ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE playlists ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE refresh_tokens ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE messages ALTER COLUMN sender_id SET NOT NULL;
ALTER TABLE rooms ALTER COLUMN owner_id SET NOT NULL;
ALTER TABLE room_members ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE track_likes ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE track_comments ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE track_shares ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE playlist_collaborators ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE playlist_follows ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE user_settings ALTER COLUMN user_id SET NOT NULL;
-- =====================================================
-- ÉTAPE 4: Migrer users.id vers UUID
-- =====================================================
-- Supprimer l'ancienne colonne id (BIGINT)
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_pkey;
ALTER TABLE users DROP COLUMN IF EXISTS id;
-- Renommer id_uuid vers id
ALTER TABLE users RENAME COLUMN id_uuid TO id;
-- Définir comme PRIMARY KEY
ALTER TABLE users ADD PRIMARY KEY (id);
-- =====================================================
-- ÉTAPE 5: Recréer les FK constraints avec UUID
-- =====================================================
ALTER TABLE user_roles
ADD CONSTRAINT fk_user_roles_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE tracks
ADD CONSTRAINT fk_tracks_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE playlists
ADD CONSTRAINT fk_playlists_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE refresh_tokens
ADD CONSTRAINT fk_refresh_tokens_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE messages
ADD CONSTRAINT fk_messages_users
FOREIGN KEY (sender_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE rooms
ADD CONSTRAINT fk_rooms_users
FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE room_members
ADD CONSTRAINT fk_room_members_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE track_likes
ADD CONSTRAINT fk_track_likes_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE track_comments
ADD CONSTRAINT fk_track_comments_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE track_shares
ADD CONSTRAINT fk_track_shares_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE playlist_collaborators
ADD CONSTRAINT fk_playlist_collaborators_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE playlist_follows
ADD CONSTRAINT fk_playlist_follows_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE user_settings
ADD CONSTRAINT fk_user_settings_users
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
-- =====================================================
-- ÉTAPE 6: Recréer les indexes
-- =====================================================
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON user_roles(user_id);
CREATE INDEX IF NOT EXISTS idx_tracks_user_id ON tracks(user_id);
CREATE INDEX IF NOT EXISTS idx_playlists_user_id ON playlists(user_id);
CREATE INDEX IF NOT EXISTS idx_refresh_tokens_user_id ON refresh_tokens(user_id);
CREATE INDEX IF NOT EXISTS idx_messages_sender_id ON messages(sender_id);
CREATE INDEX IF NOT EXISTS idx_rooms_owner_id ON rooms(owner_id);
CREATE INDEX IF NOT EXISTS idx_room_members_user_id ON room_members(user_id);
CREATE INDEX IF NOT EXISTS idx_track_likes_user_id ON track_likes(user_id);
CREATE INDEX IF NOT EXISTS idx_track_comments_user_id ON track_comments(user_id);
CREATE INDEX IF NOT EXISTS idx_track_shares_user_id ON track_shares(user_id);
CREATE INDEX IF NOT EXISTS idx_playlist_collaborators_user_id ON playlist_collaborators(user_id);
CREATE INDEX IF NOT EXISTS idx_playlist_follows_user_id ON playlist_follows(user_id);
CREATE INDEX IF NOT EXISTS idx_user_settings_user_id ON user_settings(user_id);
-- =====================================================
-- VERIFICATION
-- =====================================================
-- Vérifier que tous les users ont un UUID valide
DO $$
DECLARE
user_count INT;
null_uuid_count INT;
BEGIN
SELECT COUNT(*) INTO user_count FROM users;
SELECT COUNT(*) INTO null_uuid_count FROM users WHERE id IS NULL;
RAISE NOTICE 'Migration UUID - Total users: %, Users avec UUID NULL: %', user_count, null_uuid_count;
IF null_uuid_count > 0 THEN
RAISE EXCEPTION 'Migration échouée: % utilisateurs ont un UUID NULL', null_uuid_count;
END IF;
END $$;
-- Vérifier l'intégrité référentielle
-- TODO: Ajouter des checks supplémentaires si nécessaire
COMMENT ON COLUMN users.id IS 'UUID unique de l''utilisateur (migré de BIGINT)';