Files
fourge-portal/supabase/migrations/add_external_role.sql
T
Krao Hasanee d6e49a4c67 Add Stripe fee tracking on paid invoices + backfill function
- Store stripe_fee on invoices when webhook receives checkout.session.completed
- Display Stripe fee and net received in InvoiceDetail when paid via Stripe
- Add backfill-stripe-fees edge function to populate fee on existing paid invoices
- Migration: add stripe_fee column to invoices table
- Includes all pending portal changes (brand book, sign survey, task/project/company updates, etc.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 12:16:22 -04:00

124 lines
4.4 KiB
PL/PgSQL

-- ============================================================
-- Migration: Add external role and project_members table
-- Run this in Supabase → SQL Editor → Run
-- ============================================================
-- 1. Update profiles.role check constraint to include 'external'
do $$
declare
cname text;
begin
select constraint_name into cname
from information_schema.table_constraints
where table_schema = 'public'
and table_name = 'profiles'
and constraint_type = 'CHECK'
and constraint_name ilike '%role%';
if cname is not null then
execute 'alter table public.profiles drop constraint ' || quote_ident(cname);
end if;
end;
$$;
alter table public.profiles
add constraint profiles_role_check check (role in ('team', 'client', 'external'));
-- 2. project_members table
create table public.project_members (
id uuid default gen_random_uuid() primary key,
project_id uuid references public.projects(id) on delete cascade not null,
profile_id uuid references public.profiles(id) on delete cascade not null,
created_at timestamptz default now() not null,
unique(project_id, profile_id)
);
alter table public.project_members enable row level security;
-- 3. Helper function
create or replace function public.is_external()
returns boolean as $$
select get_my_role() = 'external';
$$ language sql security definer stable;
-- 4. RLS: project_members
create policy "Team all project_members" on public.project_members
for all using (get_my_role() = 'team');
create policy "External reads own memberships" on public.project_members
for select using (profile_id = auth.uid());
-- 5. RLS: projects (external reads assigned only)
create policy "External reads assigned projects" on public.projects
for select using (
get_my_role() = 'external' and
id in (select project_id from public.project_members where profile_id = auth.uid())
);
-- 6. RLS: tasks (external reads + updates assigned projects)
create policy "External reads assigned tasks" on public.tasks
for select using (
get_my_role() = 'external' and
project_id in (select project_id from public.project_members where profile_id = auth.uid())
);
create policy "External updates assigned tasks" on public.tasks
for update using (
get_my_role() = 'external' and
project_id in (select project_id from public.project_members where profile_id = auth.uid())
);
-- 7. RLS: submissions
create policy "External reads assigned submissions" on public.submissions
for select using (
get_my_role() = 'external' and
task_id in (
select t.id from public.tasks t
join public.project_members pm on pm.project_id = t.project_id
where pm.profile_id = auth.uid()
)
);
create policy "External inserts submissions" on public.submissions
for insert with check (
get_my_role() = 'external' and submitted_by = auth.uid()
);
-- 8. RLS: submission_files
create policy "External reads assigned submission_files" on public.submission_files
for select using (
get_my_role() = 'external' and
submission_id in (
select s.id from public.submissions s
join public.tasks t on t.id = s.task_id
join public.project_members pm on pm.project_id = t.project_id
where pm.profile_id = auth.uid()
)
);
create policy "External inserts submission_files" on public.submission_files
for insert with check (get_my_role() = 'external');
-- 9. RLS: deliveries (read only)
create policy "External reads assigned deliveries" on public.deliveries
for select using (
get_my_role() = 'external' and
submission_id in (
select s.id from public.submissions s
join public.tasks t on t.id = s.task_id
join public.project_members pm on pm.project_id = t.project_id
where pm.profile_id = auth.uid()
)
);
-- 10. RLS: delivery_files (read only)
create policy "External reads assigned delivery_files" on public.delivery_files
for select using (
get_my_role() = 'external' and
delivery_id in (
select d.id from public.deliveries d
join public.submissions s on s.id = d.submission_id
join public.tasks t on t.id = s.task_id
join public.project_members pm on pm.project_id = t.project_id
where pm.profile_id = auth.uid()
)
);
-- 11. RLS: profiles (external reads own profile only — already covered by existing policy)
-- "Own profile select" policy already handles this with: id = auth.uid()
-- No additional policy needed.