This commit is contained in:
2026-07-01 12:39:59 +02:00
parent b054e36df0
commit 8a0fa70c10
26 changed files with 1804 additions and 724 deletions
+82 -28
View File
@@ -17,10 +17,6 @@ do $$ begin
create type priority_level as enum ('low','medium','high','urgent');
exception when duplicate_object then null; end $$;
do $$ begin
create type milestone_status as enum ('planned','in_progress','done');
exception when duplicate_object then null; end $$;
do $$ begin
create type bug_severity as enum ('low','medium','high','critical');
exception when duplicate_object then null; end $$;
@@ -33,8 +29,11 @@ exception when duplicate_object then null; end $$;
create table if not exists public.profiles (
id uuid primary key references auth.users(id) on delete cascade,
full_name text not null default 'Membre',
role member_role not null default 'other',
role member_role not null default 'other', -- rôle principal (= roles[0])
roles member_role[] not null default '{}', -- tous les pôles du membre
avatar_color text not null default '#7c5cff',
avatar_url text, -- photo de profil (optionnelle)
onboarded boolean not null default false, -- a terminé l'accueil
created_at timestamptz not null default now()
);
@@ -47,18 +46,9 @@ create table if not exists public.projects (
created_at timestamptz not null default now()
);
-- ---------- Jalons (milestones) --------------------------------------
create table if not exists public.milestones (
id uuid primary key default gen_random_uuid(),
project_id uuid not null references public.projects(id) on delete cascade,
title text not null,
description text,
due_date date,
status milestone_status not null default 'planned',
created_at timestamptz not null default now()
);
-- ---------- Tâches ---------------------------------------------------
-- Un « pôle » (= member_role) reçoit la tâche ; une ou plusieurs
-- personnes de ce pôle peuvent y être assignées (assignee_ids).
create table if not exists public.tasks (
id uuid primary key default gen_random_uuid(),
project_id uuid not null references public.projects(id) on delete cascade,
@@ -66,8 +56,8 @@ create table if not exists public.tasks (
description text,
status task_status not null default 'todo',
priority priority_level not null default 'medium',
assignee_id uuid references public.profiles(id) on delete set null,
milestone_id uuid references public.milestones(id) on delete set null,
pole member_role,
assignee_ids uuid[] not null default '{}',
due_date date,
position double precision not null default 0,
created_by uuid references public.profiles(id) on delete set null,
@@ -84,6 +74,7 @@ create table if not exists public.bugs (
severity bug_severity not null default 'medium',
status bug_status not null default 'open',
priority priority_level not null default 'medium',
pole member_role,
assignee_id uuid references public.profiles(id) on delete set null,
reporter_id uuid references public.profiles(id) on delete set null,
created_at timestamptz not null default now(),
@@ -92,7 +83,6 @@ create table if not exists public.bugs (
create index if not exists idx_tasks_project on public.tasks(project_id);
create index if not exists idx_bugs_project on public.bugs(project_id);
create index if not exists idx_milestones_project on public.milestones(project_id);
-- ---------- Maj automatique de updated_at ----------------------------
create or replace function public.touch_updated_at()
@@ -110,12 +100,15 @@ create trigger trg_bugs_touch before update on public.bugs
-- ---------- Création auto du profil à l'inscription ------------------
create or replace function public.handle_new_user()
returns trigger language plpgsql security definer set search_path = public as $$
declare r member_role;
begin
insert into public.profiles (id, full_name, role)
r := coalesce((new.raw_user_meta_data->>'role')::member_role, 'other');
insert into public.profiles (id, full_name, role, roles)
values (
new.id,
coalesce(new.raw_user_meta_data->>'full_name', split_part(new.email,'@',1)),
coalesce((new.raw_user_meta_data->>'role')::member_role, 'other')
r,
array[r]
)
on conflict (id) do nothing;
return new;
@@ -130,14 +123,13 @@ create trigger on_auth_user_created
-- Équipe privée et de confiance : tout membre connecté a accès complet.
alter table public.profiles enable row level security;
alter table public.projects enable row level security;
alter table public.milestones enable row level security;
alter table public.tasks enable row level security;
alter table public.bugs enable row level security;
do $$
declare t text;
begin
foreach t in array array['profiles','projects','milestones','tasks','bugs'] loop
foreach t in array array['profiles','projects','tasks','bugs'] loop
execute format('drop policy if exists %I_all on public.%I', t, t);
execute format(
'create policy %I_all on public.%I for all to authenticated using (true) with check (true)',
@@ -152,9 +144,6 @@ exception when duplicate_object then null; end $$;
do $$ begin
alter publication supabase_realtime add table public.bugs;
exception when duplicate_object then null; end $$;
do $$ begin
alter publication supabase_realtime add table public.milestones;
exception when duplicate_object then null; end $$;
do $$ begin
alter publication supabase_realtime add table public.profiles;
exception when duplicate_object then null; end $$;
@@ -223,10 +212,13 @@ create trigger trg_profiles_guard_admin before update on public.profiles
alter table public.tasks
add column if not exists tags text[] not null default '{}';
-- ---------- Journal du temps passé (par tâche, par membre) -----------
-- ---------- Journal du temps passé (par tâche OU activité libre) -----
-- task_id null + label => temps « libre » (réunion, etc.).
create table if not exists public.time_logs (
id uuid primary key default gen_random_uuid(),
task_id uuid not null references public.tasks(id) on delete cascade,
project_id uuid references public.projects(id) on delete cascade,
task_id uuid references public.tasks(id) on delete cascade,
label text,
user_id uuid references public.profiles(id) on delete set null,
minutes integer not null check (minutes > 0),
note text,
@@ -235,6 +227,7 @@ create table if not exists public.time_logs (
);
create index if not exists idx_time_logs_task on public.time_logs(task_id);
create index if not exists idx_time_logs_project on public.time_logs(project_id);
create index if not exists idx_time_logs_user on public.time_logs(user_id);
alter table public.time_logs enable row level security;
@@ -245,3 +238,64 @@ create policy time_logs_all on public.time_logs
do $$ begin
alter publication supabase_realtime add table public.time_logs;
exception when duplicate_object then null; end $$;
-- =====================================================================
-- NOTIFICATIONS (assignation d'une tâche / d'un bug à un pôle)
-- =====================================================================
create table if not exists public.notifications (
id uuid primary key default gen_random_uuid(),
user_id uuid not null references public.profiles(id) on delete cascade,
project_id uuid references public.projects(id) on delete cascade,
kind text not null, -- 'task' | 'bug'
title text not null, -- ex : « Nouvelle tâche »
body text, -- titre de la tâche / du bug
entity_id uuid, -- id de la tâche / du bug
pole member_role, -- pôle destinataire
read boolean not null default false,
created_at timestamptz not null default now()
);
create index if not exists idx_notifications_user on public.notifications(user_id);
alter table public.notifications enable row level security;
-- Chacun lit/modifie SES notifications ; l'insertion est ouverte à tout
-- membre connecté (afin de notifier les autres membres d'un pôle).
drop policy if exists notifications_select on public.notifications;
drop policy if exists notifications_insert on public.notifications;
drop policy if exists notifications_update on public.notifications;
drop policy if exists notifications_delete on public.notifications;
create policy notifications_select on public.notifications
for select to authenticated using (user_id = auth.uid());
create policy notifications_insert on public.notifications
for insert to authenticated with check (true);
create policy notifications_update on public.notifications
for update to authenticated using (user_id = auth.uid()) with check (user_id = auth.uid());
create policy notifications_delete on public.notifications
for delete to authenticated using (user_id = auth.uid());
do $$ begin
alter publication supabase_realtime add table public.notifications;
exception when duplicate_object then null; end $$;
-- =====================================================================
-- STOCKAGE : photos de profil (bucket "avatars")
-- =====================================================================
insert into storage.buckets (id, name, public)
values ('avatars', 'avatars', true)
on conflict (id) do nothing;
drop policy if exists avatars_read on storage.objects;
drop policy if exists avatars_insert on storage.objects;
drop policy if exists avatars_update on storage.objects;
drop policy if exists avatars_delete on storage.objects;
create policy avatars_read on storage.objects
for select using (bucket_id = 'avatars');
create policy avatars_insert on storage.objects
for insert to authenticated with check (bucket_id = 'avatars');
create policy avatars_update on storage.objects
for update to authenticated using (bucket_id = 'avatars');
create policy avatars_delete on storage.objects
for delete to authenticated using (bucket_id = 'avatars');