Initial commit: application de gestion des competences
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
-- ============================================================
|
||||
-- Migration 001: Structure initiale
|
||||
-- Application de gestion des compétences
|
||||
-- ============================================================
|
||||
|
||||
-- 1. ENUMS
|
||||
CREATE TYPE user_role AS ENUM ('admin', 'member');
|
||||
|
||||
-- 2. TABLES
|
||||
|
||||
-- Catégories de compétences
|
||||
CREATE TABLE categories (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name text NOT NULL UNIQUE,
|
||||
color text,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- Compétences
|
||||
CREATE TABLE skills (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name text NOT NULL,
|
||||
category_id uuid NOT NULL REFERENCES categories(id) ON DELETE RESTRICT,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE(name, category_id)
|
||||
);
|
||||
|
||||
-- Profils membres (liés à auth.users)
|
||||
CREATE TABLE members (
|
||||
id uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
email text NOT NULL,
|
||||
full_name text NOT NULL DEFAULT '',
|
||||
role user_role NOT NULL DEFAULT 'member',
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- Descriptifs des niveaux
|
||||
CREATE TABLE level_descriptions (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
level int2 NOT NULL CHECK (level BETWEEN 1 AND 4),
|
||||
label text NOT NULL,
|
||||
description text NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- Niveaux de compétences par membre
|
||||
CREATE TABLE skill_levels (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
member_id uuid NOT NULL REFERENCES members(id) ON DELETE CASCADE,
|
||||
skill_id uuid NOT NULL REFERENCES skills(id) ON DELETE CASCADE,
|
||||
level int2 NOT NULL CHECK (level BETWEEN 1 AND 4),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE(member_id, skill_id)
|
||||
);
|
||||
|
||||
-- Historique des changements
|
||||
CREATE TABLE skill_history (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
member_id uuid NOT NULL REFERENCES members(id) ON DELETE CASCADE,
|
||||
skill_id uuid NOT NULL REFERENCES skills(id) ON DELETE CASCADE,
|
||||
old_level int2,
|
||||
new_level int2 NOT NULL,
|
||||
changed_by uuid NOT NULL REFERENCES members(id),
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- Invitations
|
||||
CREATE TABLE invitations (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
email text NOT NULL,
|
||||
token text NOT NULL UNIQUE,
|
||||
role user_role NOT NULL DEFAULT 'member',
|
||||
invited_by uuid NOT NULL REFERENCES members(id),
|
||||
accepted bool NOT NULL DEFAULT false,
|
||||
expires_at timestamptz NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- 3. INDEXES
|
||||
CREATE INDEX idx_skills_category ON skills(category_id);
|
||||
CREATE INDEX idx_skill_levels_member ON skill_levels(member_id);
|
||||
CREATE INDEX idx_skill_levels_skill ON skill_levels(skill_id);
|
||||
CREATE INDEX idx_skill_history_member ON skill_history(member_id);
|
||||
CREATE INDEX idx_skill_history_skill ON skill_history(skill_id);
|
||||
CREATE INDEX idx_skill_history_created ON skill_history(created_at DESC);
|
||||
CREATE INDEX idx_invitations_token ON invitations(token);
|
||||
CREATE INDEX idx_invitations_email ON invitations(email);
|
||||
|
||||
-- 4. SEED DATA
|
||||
|
||||
-- Catégories initiales
|
||||
INSERT INTO categories (name, color) VALUES
|
||||
('Réseau', '#3b82f6'),
|
||||
('Système', '#10b981'),
|
||||
('Cloud', '#f59e0b'),
|
||||
('Sécurité', '#ef4444'),
|
||||
('Base de données', '#8b5cf6'),
|
||||
('Monitoring', '#ec4899'),
|
||||
('Stockage', '#14b8a6');
|
||||
|
||||
-- Descriptifs des niveaux
|
||||
INSERT INTO level_descriptions (level, label, description) VALUES
|
||||
(1, 'Débutant', 'Connaissances théoriques, nécessite un accompagnement'),
|
||||
(2, 'Intermédiaire', 'Réalise les tâches courantes en autonomie'),
|
||||
(3, 'Avancé', 'Gère des situations complexes, forme les autres'),
|
||||
(4, 'Expert', 'Référence technique, conçoit l''architecture');
|
||||
|
||||
-- 5. ROW LEVEL SECURITY
|
||||
|
||||
ALTER TABLE categories ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE skills ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE members ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE level_descriptions ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE skill_levels ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE skill_history ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE invitations ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Categories: tout le monde peut lire, seuls les admins écrivent
|
||||
CREATE POLICY "categories_read_all" ON categories FOR SELECT USING (true);
|
||||
CREATE POLICY "categories_write_admin" ON categories FOR INSERT WITH CHECK (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "categories_update_admin" ON categories FOR UPDATE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "categories_delete_admin" ON categories FOR DELETE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
|
||||
-- Skills: tout le monde peut lire, seuls les admins écrivent
|
||||
CREATE POLICY "skills_read_all" ON skills FOR SELECT USING (true);
|
||||
CREATE POLICY "skills_write_admin" ON skills FOR INSERT WITH CHECK (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "skills_update_admin" ON skills FOR UPDATE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "skills_delete_admin" ON skills FOR DELETE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
|
||||
-- Members: tout le monde peut lire, les admins peuvent modifier
|
||||
CREATE POLICY "members_read_all" ON members FOR SELECT USING (true);
|
||||
CREATE POLICY "members_insert_self" ON members FOR INSERT WITH CHECK (id = auth.uid());
|
||||
CREATE POLICY "members_update_admin" ON members FOR UPDATE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "members_delete_admin" ON members FOR DELETE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
|
||||
-- Level descriptions: tout le monde peut lire
|
||||
CREATE POLICY "level_descriptions_read_all" ON level_descriptions FOR SELECT USING (true);
|
||||
|
||||
-- Skill levels: tout le monde peut lire, seuls les admins modifient
|
||||
CREATE POLICY "skill_levels_read_all" ON skill_levels FOR SELECT USING (true);
|
||||
CREATE POLICY "skill_levels_insert_admin" ON skill_levels FOR INSERT WITH CHECK (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "skill_levels_update_admin" ON skill_levels FOR UPDATE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "skill_levels_delete_admin" ON skill_levels FOR DELETE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
|
||||
-- Skill history: tout le monde peut lire, seuls les admins insèrent
|
||||
CREATE POLICY "skill_history_read_all" ON skill_history FOR SELECT USING (true);
|
||||
CREATE POLICY "skill_history_insert_admin" ON skill_history FOR INSERT WITH CHECK (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
|
||||
-- Invitations: seuls les admins peuvent tout faire
|
||||
CREATE POLICY "invitations_read_admin" ON invitations FOR SELECT USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "invitations_insert_admin" ON invitations FOR INSERT WITH CHECK (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "invitations_update_admin" ON invitations FOR UPDATE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
CREATE POLICY "invitations_delete_admin" ON invitations FOR DELETE USING (
|
||||
EXISTS (SELECT 1 FROM members WHERE id = auth.uid() AND role = 'admin')
|
||||
);
|
||||
|
||||
-- 6. TRIGGER: Mise à jour automatique de updated_at
|
||||
CREATE OR REPLACE FUNCTION update_updated_at()
|
||||
RETURNS trigger AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER update_skill_levels_updated_at
|
||||
BEFORE UPDATE ON skill_levels
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at();
|
||||
|
||||
-- 7. FONCTION: Créer automatiquement un membre lors de l'inscription
|
||||
CREATE OR REPLACE FUNCTION handle_new_user()
|
||||
RETURNS trigger AS $$
|
||||
BEGIN
|
||||
INSERT INTO public.members (id, email, full_name, role)
|
||||
VALUES (
|
||||
NEW.id,
|
||||
NEW.email,
|
||||
COALESCE(NEW.raw_user_meta_data->>'full_name', ''),
|
||||
'member'
|
||||
);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE TRIGGER on_auth_user_created
|
||||
AFTER INSERT ON auth.users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION handle_new_user();
|
||||
Reference in New Issue
Block a user