Panel admin, planning, tags, suivi du temps, thèmes clair/sombre
- Admin: création/suppression de comptes + rôles via Edge Function sécurisée - Config Supabase intégrée au build (.env), écran Setup supprimé - Page Planning (vue mois/semaine) - Tags "jobs" sur les tâches + filtres (membre / tag) - Suivi du temps par tâche, total par jalon - Toasts + confirmations in-app (fini alert/confirm natifs) - Thème Notion clair + mode sombre (accent monochrome, bascule persistée) - .env suivi par git (public uniquement) pour synchro multi-machines Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -155,3 +155,93 @@ 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 $$;
|
||||
|
||||
-- =====================================================================
|
||||
-- ADMINISTRATION : comptes & rôles gérés par un panel admin in-app
|
||||
-- =====================================================================
|
||||
|
||||
-- ---------- Champ "administrateur" sur les profils -------------------
|
||||
alter table public.profiles
|
||||
add column if not exists is_admin boolean not null default false;
|
||||
|
||||
-- ---------- Sécurité fine sur les profils ----------------------------
|
||||
-- On remplace la policy permissive "profiles_all" par des règles précises :
|
||||
-- * tout le monde (connecté) PEUT LIRE les profils (affichage de l'équipe)
|
||||
-- * chacun ne peut MODIFIER que SON propre profil
|
||||
-- * la création/suppression de comptes passe uniquement par l'Edge
|
||||
-- Function "admin-users" (clé service_role, côté serveur).
|
||||
drop policy if exists profiles_all on public.profiles;
|
||||
drop policy if exists profiles_select on public.profiles;
|
||||
drop policy if exists profiles_update_self on public.profiles;
|
||||
|
||||
create policy profiles_select on public.profiles
|
||||
for select to authenticated using (true);
|
||||
|
||||
create policy profiles_update_self on public.profiles
|
||||
for update to authenticated
|
||||
using (id = auth.uid()) with check (id = auth.uid());
|
||||
|
||||
-- ---------- Garde-fou : on ne se promeut pas admin soi-même ----------
|
||||
-- Empêche un membre connecté (rôle "authenticated") de changer le champ
|
||||
-- is_admin. Les opérations légitimes passent par l'Edge Function
|
||||
-- (rôle "service_role") ou par le SQL Editor (rôle "postgres"), tous deux
|
||||
-- autorisés ici. Un admin déjà en place peut aussi modifier le statut.
|
||||
create or replace function public.guard_is_admin()
|
||||
returns trigger language plpgsql security definer set search_path = public as $$
|
||||
begin
|
||||
if new.is_admin is distinct from old.is_admin
|
||||
and current_user = 'authenticated'
|
||||
and not exists (
|
||||
select 1 from public.profiles p where p.id = auth.uid() and p.is_admin
|
||||
) then
|
||||
raise exception 'Seul un administrateur peut modifier le statut admin.';
|
||||
end if;
|
||||
return new;
|
||||
end $$;
|
||||
|
||||
drop trigger if exists trg_profiles_guard_admin on public.profiles;
|
||||
create trigger trg_profiles_guard_admin before update on public.profiles
|
||||
for each row execute function public.guard_is_admin();
|
||||
|
||||
-- ---------- Amorçage du PREMIER admin (à faire UNE fois) -------------
|
||||
-- Après ta première inscription dans l'appli, exécute cette ligne en
|
||||
-- remplaçant l'email par le tien pour devenir administrateur :
|
||||
--
|
||||
-- update public.profiles set is_admin = true
|
||||
-- where id = (select id from auth.users where email = 'TON_EMAIL@ exemple.com');
|
||||
--
|
||||
-- Ensuite, tu pourras créer/gérer tous les autres comptes depuis l'appli.
|
||||
|
||||
-- =====================================================================
|
||||
-- TAGS (« jobs ») & SUIVI DU TEMPS
|
||||
-- =====================================================================
|
||||
|
||||
-- ---------- Tags sur les tâches (ex: Programmation, Art, Audio) ------
|
||||
alter table public.tasks
|
||||
add column if not exists tags text[] not null default '{}';
|
||||
|
||||
-- ---------- Journal du temps passé (par tâche, par membre) -----------
|
||||
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,
|
||||
user_id uuid references public.profiles(id) on delete set null,
|
||||
minutes integer not null check (minutes > 0),
|
||||
note text,
|
||||
logged_at date not null default current_date,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create index if not exists idx_time_logs_task on public.time_logs(task_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;
|
||||
drop policy if exists time_logs_all on public.time_logs;
|
||||
create policy time_logs_all on public.time_logs
|
||||
for all to authenticated using (true) with check (true);
|
||||
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.time_logs;
|
||||
exception when duplicate_object then null; end $$;
|
||||
|
||||
Reference in New Issue
Block a user