mirror of
https://github.com/willchen96/mike.git
synced 2026-06-08 20:25:13 +02:00
1047 lines
33 KiB
MySQL
1047 lines
33 KiB
MySQL
|
|
-- Mike Supabase schema
|
||
|
|
-- Based on supabase-migration.sql plus the later backend/migrations/*.sql files.
|
||
|
|
-- Use this for a fresh Supabase database. Existing deployments should continue
|
||
|
|
-- to apply the incremental migration files instead.
|
||
|
|
|
||
|
|
create extension if not exists "pgcrypto";
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
-- User profiles
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
create table if not exists public.user_profiles (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
user_id uuid not null unique references auth.users(id) on delete cascade,
|
||
|
|
display_name text,
|
||
|
|
organisation text,
|
||
|
|
tier text not null default 'Free',
|
||
|
|
message_credits_used integer not null default 0,
|
||
|
|
credits_reset_date timestamptz not null default (now() + interval '30 days'),
|
||
|
|
tabular_model text not null default 'gemini-3-flash-preview',
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
updated_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_user_profiles_user
|
||
|
|
on public.user_profiles(user_id);
|
||
|
|
|
||
|
|
alter table public.user_profiles enable row level security;
|
||
|
|
|
||
|
|
drop policy if exists "Users can view their own profile" on public.user_profiles;
|
||
|
|
create policy "Users can view their own profile"
|
||
|
|
on public.user_profiles for select
|
||
|
|
using (auth.uid() = user_id);
|
||
|
|
|
||
|
|
drop policy if exists "Users can update their own profile" on public.user_profiles;
|
||
|
|
create policy "Users can update their own profile"
|
||
|
|
on public.user_profiles for update
|
||
|
|
using (auth.uid() = user_id);
|
||
|
|
|
||
|
|
create or replace function public.handle_new_user()
|
||
|
|
returns trigger
|
||
|
|
language plpgsql
|
||
|
|
security definer
|
||
|
|
set search_path = public
|
||
|
|
as $$
|
||
|
|
begin
|
||
|
|
insert into public.user_profiles (user_id)
|
||
|
|
values (new.id)
|
||
|
|
on conflict (user_id) do nothing;
|
||
|
|
return new;
|
||
|
|
exception when others then
|
||
|
|
-- Never block signup if the profile insert fails.
|
||
|
|
return new;
|
||
|
|
end;
|
||
|
|
$$;
|
||
|
|
|
||
|
|
drop trigger if exists on_auth_user_created on auth.users;
|
||
|
|
create trigger on_auth_user_created
|
||
|
|
after insert on auth.users
|
||
|
|
for each row execute procedure public.handle_new_user();
|
||
|
|
|
||
|
|
create table if not exists public.user_api_keys (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
user_id uuid not null references auth.users(id) on delete cascade,
|
||
|
|
provider text not null check (provider in ('claude', 'gemini')),
|
||
|
|
encrypted_key text not null,
|
||
|
|
iv text not null,
|
||
|
|
auth_tag text not null,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
updated_at timestamptz not null default now(),
|
||
|
|
unique(user_id, provider)
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_user_api_keys_user
|
||
|
|
on public.user_api_keys(user_id);
|
||
|
|
|
||
|
|
alter table public.user_api_keys enable row level security;
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
-- Projects and documents
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
create table if not exists public.projects (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
user_id text not null,
|
||
|
|
name text not null,
|
||
|
|
cm_number text,
|
||
|
|
visibility text not null default 'private',
|
||
|
|
shared_with jsonb not null default '[]'::jsonb,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
updated_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_projects_user
|
||
|
|
on public.projects(user_id);
|
||
|
|
|
||
|
|
create index if not exists projects_shared_with_idx
|
||
|
|
on public.projects using gin (shared_with);
|
||
|
|
|
||
|
|
create table if not exists public.project_subfolders (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
project_id uuid not null references public.projects(id) on delete cascade,
|
||
|
|
user_id text not null,
|
||
|
|
name text not null,
|
||
|
|
parent_folder_id uuid references public.project_subfolders(id) on delete cascade,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
updated_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_project_subfolders_project
|
||
|
|
on public.project_subfolders(project_id);
|
||
|
|
|
||
|
|
create table if not exists public.documents (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
project_id uuid references public.projects(id) on delete cascade,
|
||
|
|
user_id text not null,
|
||
|
|
filename text not null,
|
||
|
|
file_type text,
|
||
|
|
size_bytes integer not null default 0,
|
||
|
|
page_count integer,
|
||
|
|
structure_tree jsonb,
|
||
|
|
status text not null default 'pending',
|
||
|
|
folder_id uuid references public.project_subfolders(id) on delete set null,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
updated_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_documents_user_project
|
||
|
|
on public.documents(user_id, project_id);
|
||
|
|
|
||
|
|
create index if not exists idx_documents_project_folder
|
||
|
|
on public.documents(project_id, folder_id);
|
||
|
|
|
||
|
|
create table if not exists public.document_versions (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
document_id uuid not null references public.documents(id) on delete cascade,
|
||
|
|
storage_path text not null,
|
||
|
|
pdf_storage_path text,
|
||
|
|
source text not null default 'upload',
|
||
|
|
version_number integer,
|
||
|
|
display_name text,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
constraint document_versions_source_check
|
||
|
|
check (source = any (array[
|
||
|
|
'upload'::text,
|
||
|
|
'user_upload'::text,
|
||
|
|
'assistant_edit'::text,
|
||
|
|
'user_accept'::text,
|
||
|
|
'user_reject'::text,
|
||
|
|
'generated'::text
|
||
|
|
]))
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists document_versions_document_id_idx
|
||
|
|
on public.document_versions(document_id, created_at desc);
|
||
|
|
|
||
|
|
create index if not exists document_versions_doc_vnum_idx
|
||
|
|
on public.document_versions(document_id, version_number);
|
||
|
|
|
||
|
|
alter table public.documents
|
||
|
|
add column if not exists current_version_id uuid
|
||
|
|
references public.document_versions(id) on delete set null;
|
||
|
|
|
||
|
|
create table if not exists public.document_edits (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
document_id uuid not null references public.documents(id) on delete cascade,
|
||
|
|
chat_message_id uuid,
|
||
|
|
version_id uuid not null references public.document_versions(id) on delete cascade,
|
||
|
|
change_id text not null,
|
||
|
|
del_w_id text,
|
||
|
|
ins_w_id text,
|
||
|
|
deleted_text text not null default '',
|
||
|
|
inserted_text text not null default '',
|
||
|
|
context_before text,
|
||
|
|
context_after text,
|
||
|
|
status text not null default 'pending'
|
||
|
|
check (status = any (array[
|
||
|
|
'pending'::text,
|
||
|
|
'accepted'::text,
|
||
|
|
'rejected'::text
|
||
|
|
])),
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
resolved_at timestamptz
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists document_edits_document_id_idx
|
||
|
|
on public.document_edits(document_id, created_at desc);
|
||
|
|
|
||
|
|
create index if not exists document_edits_message_id_idx
|
||
|
|
on public.document_edits(chat_message_id);
|
||
|
|
|
||
|
|
create index if not exists document_edits_version_id_idx
|
||
|
|
on public.document_edits(version_id);
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
-- Workflows
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
create table if not exists public.workflows (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
user_id text,
|
||
|
|
title text not null,
|
||
|
|
type text not null,
|
||
|
|
prompt_md text,
|
||
|
|
columns_config jsonb,
|
||
|
|
practice text,
|
||
|
|
is_system boolean not null default false,
|
||
|
|
created_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_workflows_user
|
||
|
|
on public.workflows(user_id);
|
||
|
|
|
||
|
|
create table if not exists public.hidden_workflows (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
user_id text not null,
|
||
|
|
workflow_id text not null,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
unique(user_id, workflow_id)
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_hidden_workflows_user
|
||
|
|
on public.hidden_workflows(user_id);
|
||
|
|
|
||
|
|
create table if not exists public.workflow_shares (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
workflow_id uuid not null references public.workflows(id) on delete cascade,
|
||
|
|
shared_by_user_id text not null,
|
||
|
|
shared_with_email text not null,
|
||
|
|
allow_edit boolean not null default false,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
constraint workflow_shares_workflow_email_unique
|
||
|
|
unique(workflow_id, shared_with_email)
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists workflow_shares_workflow_id_idx
|
||
|
|
on public.workflow_shares(workflow_id);
|
||
|
|
|
||
|
|
create index if not exists workflow_shares_email_idx
|
||
|
|
on public.workflow_shares(shared_with_email);
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
-- Assistant chats
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
create table if not exists public.chats (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
project_id uuid references public.projects(id) on delete cascade,
|
||
|
|
user_id text not null,
|
||
|
|
title text,
|
||
|
|
created_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_chats_user
|
||
|
|
on public.chats(user_id);
|
||
|
|
|
||
|
|
create index if not exists idx_chats_project
|
||
|
|
on public.chats(project_id);
|
||
|
|
|
||
|
|
create table if not exists public.chat_messages (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
chat_id uuid not null references public.chats(id) on delete cascade,
|
||
|
|
role text not null,
|
||
|
|
content jsonb,
|
||
|
|
files jsonb,
|
||
|
|
annotations jsonb,
|
||
|
|
created_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_chat_messages_chat
|
||
|
|
on public.chat_messages(chat_id);
|
||
|
|
|
||
|
|
do $$
|
||
|
|
begin
|
||
|
|
if not exists (
|
||
|
|
select 1
|
||
|
|
from pg_constraint
|
||
|
|
where conname = 'document_edits_chat_message_id_fkey'
|
||
|
|
and conrelid = 'public.document_edits'::regclass
|
||
|
|
) then
|
||
|
|
alter table public.document_edits
|
||
|
|
add constraint document_edits_chat_message_id_fkey
|
||
|
|
foreign key (chat_message_id)
|
||
|
|
references public.chat_messages(id)
|
||
|
|
on delete set null;
|
||
|
|
end if;
|
||
|
|
end;
|
||
|
|
$$;
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
-- Tabular reviews
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
create table if not exists public.tabular_reviews (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
project_id uuid references public.projects(id) on delete cascade,
|
||
|
|
user_id text not null,
|
||
|
|
title text,
|
||
|
|
columns_config jsonb,
|
||
|
|
workflow_id uuid references public.workflows(id) on delete set null,
|
||
|
|
practice text,
|
||
|
|
shared_with jsonb not null default '[]'::jsonb,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
updated_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_tabular_reviews_user
|
||
|
|
on public.tabular_reviews(user_id);
|
||
|
|
|
||
|
|
create index if not exists idx_tabular_reviews_project
|
||
|
|
on public.tabular_reviews(project_id);
|
||
|
|
|
||
|
|
create index if not exists tabular_reviews_shared_with_idx
|
||
|
|
on public.tabular_reviews using gin (shared_with);
|
||
|
|
|
||
|
|
create table if not exists public.tabular_cells (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
review_id uuid not null references public.tabular_reviews(id) on delete cascade,
|
||
|
|
document_id uuid not null references public.documents(id) on delete cascade,
|
||
|
|
column_index integer not null,
|
||
|
|
content text,
|
||
|
|
citations jsonb,
|
||
|
|
status text not null default 'pending',
|
||
|
|
created_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists idx_tabular_cells_review
|
||
|
|
on public.tabular_cells(review_id, document_id, column_index);
|
||
|
|
|
||
|
|
create table if not exists public.tabular_review_chats (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
review_id uuid not null references public.tabular_reviews(id) on delete cascade,
|
||
|
|
user_id text not null,
|
||
|
|
title text,
|
||
|
|
created_at timestamptz not null default now(),
|
||
|
|
updated_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists tabular_review_chats_review_idx
|
||
|
|
on public.tabular_review_chats(review_id, updated_at desc);
|
||
|
|
|
||
|
|
create index if not exists tabular_review_chats_user_idx
|
||
|
|
on public.tabular_review_chats(user_id);
|
||
|
|
|
||
|
|
create table if not exists public.tabular_review_chat_messages (
|
||
|
|
id uuid primary key default gen_random_uuid(),
|
||
|
|
chat_id uuid not null references public.tabular_review_chats(id) on delete cascade,
|
||
|
|
role text not null,
|
||
|
|
content jsonb,
|
||
|
|
annotations jsonb,
|
||
|
|
created_at timestamptz not null default now()
|
||
|
|
);
|
||
|
|
|
||
|
|
create index if not exists tabular_review_chat_messages_chat_idx
|
||
|
|
on public.tabular_review_chat_messages(chat_id, created_at);
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
-- Row-level security
|
||
|
|
-- ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
create or replace function public.current_user_id_text()
|
||
|
|
returns text
|
||
|
|
language sql
|
||
|
|
stable
|
||
|
|
set search_path = public, auth
|
||
|
|
as $$
|
||
|
|
select auth.uid()::text;
|
||
|
|
$$;
|
||
|
|
|
||
|
|
create or replace function public.current_user_email()
|
||
|
|
returns text
|
||
|
|
language sql
|
||
|
|
stable
|
||
|
|
set search_path = public, auth
|
||
|
|
as $$
|
||
|
|
select lower(coalesce(auth.jwt() ->> 'email', ''));
|
||
|
|
$$;
|
||
|
|
|
||
|
|
create or replace function public.email_is_shared(shared_with jsonb)
|
||
|
|
returns boolean
|
||
|
|
language sql
|
||
|
|
stable
|
||
|
|
set search_path = public
|
||
|
|
as $$
|
||
|
|
select public.current_user_email() <> ''
|
||
|
|
and exists (
|
||
|
|
select 1
|
||
|
|
from jsonb_array_elements_text(coalesce(shared_with, '[]'::jsonb)) as emails(email)
|
||
|
|
where lower(emails.email) = public.current_user_email()
|
||
|
|
);
|
||
|
|
$$;
|
||
|
|
|
||
|
|
create or replace function public.project_is_accessible(target_project_id uuid)
|
||
|
|
returns boolean
|
||
|
|
language sql
|
||
|
|
stable
|
||
|
|
security definer
|
||
|
|
set search_path = public, auth
|
||
|
|
as $$
|
||
|
|
select exists (
|
||
|
|
select 1
|
||
|
|
from public.projects p
|
||
|
|
where p.id = target_project_id
|
||
|
|
and (
|
||
|
|
p.user_id = public.current_user_id_text()
|
||
|
|
or public.email_is_shared(p.shared_with)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
$$;
|
||
|
|
|
||
|
|
create or replace function public.review_is_accessible(target_review_id uuid)
|
||
|
|
returns boolean
|
||
|
|
language sql
|
||
|
|
stable
|
||
|
|
security definer
|
||
|
|
set search_path = public, auth
|
||
|
|
as $$
|
||
|
|
select exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_reviews r
|
||
|
|
where r.id = target_review_id
|
||
|
|
and (
|
||
|
|
r.user_id = public.current_user_id_text()
|
||
|
|
or public.email_is_shared(r.shared_with)
|
||
|
|
or (
|
||
|
|
r.project_id is not null
|
||
|
|
and public.project_is_accessible(r.project_id)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
$$;
|
||
|
|
|
||
|
|
create or replace function public.workflow_can_view(target_workflow_id uuid)
|
||
|
|
returns boolean
|
||
|
|
language sql
|
||
|
|
stable
|
||
|
|
security definer
|
||
|
|
set search_path = public, auth
|
||
|
|
as $$
|
||
|
|
select exists (
|
||
|
|
select 1
|
||
|
|
from public.workflows w
|
||
|
|
where w.id = target_workflow_id
|
||
|
|
and (
|
||
|
|
w.is_system
|
||
|
|
or w.user_id = public.current_user_id_text()
|
||
|
|
or exists (
|
||
|
|
select 1
|
||
|
|
from public.workflow_shares s
|
||
|
|
where s.workflow_id = w.id
|
||
|
|
and s.shared_with_email = public.current_user_email()
|
||
|
|
)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
$$;
|
||
|
|
|
||
|
|
create or replace function public.workflow_can_edit(target_workflow_id uuid)
|
||
|
|
returns boolean
|
||
|
|
language sql
|
||
|
|
stable
|
||
|
|
security definer
|
||
|
|
set search_path = public, auth
|
||
|
|
as $$
|
||
|
|
select exists (
|
||
|
|
select 1
|
||
|
|
from public.workflows w
|
||
|
|
where w.id = target_workflow_id
|
||
|
|
and (
|
||
|
|
w.user_id = public.current_user_id_text()
|
||
|
|
or exists (
|
||
|
|
select 1
|
||
|
|
from public.workflow_shares s
|
||
|
|
where s.workflow_id = w.id
|
||
|
|
and s.shared_with_email = public.current_user_email()
|
||
|
|
and s.allow_edit
|
||
|
|
)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
$$;
|
||
|
|
|
||
|
|
alter table public.user_profiles enable row level security;
|
||
|
|
alter table public.user_api_keys enable row level security;
|
||
|
|
alter table public.projects enable row level security;
|
||
|
|
alter table public.project_subfolders enable row level security;
|
||
|
|
alter table public.documents enable row level security;
|
||
|
|
alter table public.document_versions enable row level security;
|
||
|
|
alter table public.document_edits enable row level security;
|
||
|
|
alter table public.workflows enable row level security;
|
||
|
|
alter table public.hidden_workflows enable row level security;
|
||
|
|
alter table public.workflow_shares enable row level security;
|
||
|
|
alter table public.chats enable row level security;
|
||
|
|
alter table public.chat_messages enable row level security;
|
||
|
|
alter table public.tabular_reviews enable row level security;
|
||
|
|
alter table public.tabular_cells enable row level security;
|
||
|
|
alter table public.tabular_review_chats enable row level security;
|
||
|
|
alter table public.tabular_review_chat_messages enable row level security;
|
||
|
|
|
||
|
|
drop policy if exists "Users can insert their own profile" on public.user_profiles;
|
||
|
|
create policy "Users can insert their own profile"
|
||
|
|
on public.user_profiles for insert
|
||
|
|
with check (auth.uid() = user_id);
|
||
|
|
|
||
|
|
drop policy if exists "Users can view their own profile" on public.user_profiles;
|
||
|
|
create policy "Users can view their own profile"
|
||
|
|
on public.user_profiles for select
|
||
|
|
using (auth.uid() = user_id);
|
||
|
|
|
||
|
|
drop policy if exists "Users can update their own profile" on public.user_profiles;
|
||
|
|
create policy "Users can update their own profile"
|
||
|
|
on public.user_profiles for update
|
||
|
|
using (auth.uid() = user_id)
|
||
|
|
with check (auth.uid() = user_id);
|
||
|
|
|
||
|
|
-- user_api_keys is intentionally service-role only. The browser can only see
|
||
|
|
-- key status through backend routes, never encrypted key material.
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible projects" on public.projects;
|
||
|
|
create policy "Users can view accessible projects"
|
||
|
|
on public.projects for select
|
||
|
|
using (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
or public.email_is_shared(shared_with)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can insert their own projects" on public.projects;
|
||
|
|
create policy "Users can insert their own projects"
|
||
|
|
on public.projects for insert
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Owners can update projects" on public.projects;
|
||
|
|
create policy "Owners can update projects"
|
||
|
|
on public.projects for update
|
||
|
|
using (user_id = public.current_user_id_text())
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Owners can delete projects" on public.projects;
|
||
|
|
create policy "Owners can delete projects"
|
||
|
|
on public.projects for delete
|
||
|
|
using (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible project folders" on public.project_subfolders;
|
||
|
|
create policy "Users can view accessible project folders"
|
||
|
|
on public.project_subfolders for select
|
||
|
|
using (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
or public.project_is_accessible(project_id)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can insert their own project folders" on public.project_subfolders;
|
||
|
|
create policy "Users can insert their own project folders"
|
||
|
|
on public.project_subfolders for insert
|
||
|
|
with check (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
and public.project_is_accessible(project_id)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Owners can update project folders" on public.project_subfolders;
|
||
|
|
create policy "Owners can update project folders"
|
||
|
|
on public.project_subfolders for update
|
||
|
|
using (user_id = public.current_user_id_text())
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Owners can delete project folders" on public.project_subfolders;
|
||
|
|
create policy "Owners can delete project folders"
|
||
|
|
on public.project_subfolders for delete
|
||
|
|
using (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible documents" on public.documents;
|
||
|
|
create policy "Users can view accessible documents"
|
||
|
|
on public.documents for select
|
||
|
|
using (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
or (
|
||
|
|
project_id is not null
|
||
|
|
and public.project_is_accessible(project_id)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can insert their own documents" on public.documents;
|
||
|
|
create policy "Users can insert their own documents"
|
||
|
|
on public.documents for insert
|
||
|
|
with check (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
and (
|
||
|
|
project_id is null
|
||
|
|
or public.project_is_accessible(project_id)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Owners can update documents" on public.documents;
|
||
|
|
create policy "Owners can update documents"
|
||
|
|
on public.documents for update
|
||
|
|
using (user_id = public.current_user_id_text())
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Owners can delete documents" on public.documents;
|
||
|
|
create policy "Owners can delete documents"
|
||
|
|
on public.documents for delete
|
||
|
|
using (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible document versions" on public.document_versions;
|
||
|
|
create policy "Users can view accessible document versions"
|
||
|
|
on public.document_versions for select
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and (
|
||
|
|
d.user_id = public.current_user_id_text()
|
||
|
|
or (
|
||
|
|
d.project_id is not null
|
||
|
|
and public.project_is_accessible(d.project_id)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Document owners can insert versions" on public.document_versions;
|
||
|
|
create policy "Document owners can insert versions"
|
||
|
|
on public.document_versions for insert
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and d.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Document owners can update versions" on public.document_versions;
|
||
|
|
create policy "Document owners can update versions"
|
||
|
|
on public.document_versions for update
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and d.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
)
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and d.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Document owners can delete versions" on public.document_versions;
|
||
|
|
create policy "Document owners can delete versions"
|
||
|
|
on public.document_versions for delete
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and d.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible document edits" on public.document_edits;
|
||
|
|
create policy "Users can view accessible document edits"
|
||
|
|
on public.document_edits for select
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and (
|
||
|
|
d.user_id = public.current_user_id_text()
|
||
|
|
or (
|
||
|
|
d.project_id is not null
|
||
|
|
and public.project_is_accessible(d.project_id)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Document owners can insert edits" on public.document_edits;
|
||
|
|
create policy "Document owners can insert edits"
|
||
|
|
on public.document_edits for insert
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and d.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Document owners can update edits" on public.document_edits;
|
||
|
|
create policy "Document owners can update edits"
|
||
|
|
on public.document_edits for update
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and d.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
)
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and d.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Document owners can delete edits" on public.document_edits;
|
||
|
|
create policy "Document owners can delete edits"
|
||
|
|
on public.document_edits for delete
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.documents d
|
||
|
|
where d.id = document_id
|
||
|
|
and d.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible workflows" on public.workflows;
|
||
|
|
create policy "Users can view accessible workflows"
|
||
|
|
on public.workflows for select
|
||
|
|
using (public.workflow_can_view(id));
|
||
|
|
|
||
|
|
drop policy if exists "Users can insert their own workflows" on public.workflows;
|
||
|
|
create policy "Users can insert their own workflows"
|
||
|
|
on public.workflows for insert
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Workflow owners can update workflows" on public.workflows;
|
||
|
|
create policy "Workflow owners can update workflows"
|
||
|
|
on public.workflows for update
|
||
|
|
using (user_id = public.current_user_id_text())
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Workflow owners can delete workflows" on public.workflows;
|
||
|
|
create policy "Workflow owners can delete workflows"
|
||
|
|
on public.workflows for delete
|
||
|
|
using (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can manage their hidden workflows" on public.hidden_workflows;
|
||
|
|
create policy "Users can manage their hidden workflows"
|
||
|
|
on public.hidden_workflows for all
|
||
|
|
using (user_id = public.current_user_id_text())
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can view relevant workflow shares" on public.workflow_shares;
|
||
|
|
create policy "Users can view relevant workflow shares"
|
||
|
|
on public.workflow_shares for select
|
||
|
|
using (
|
||
|
|
shared_by_user_id = public.current_user_id_text()
|
||
|
|
or shared_with_email = public.current_user_email()
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Workflow owners can insert shares" on public.workflow_shares;
|
||
|
|
create policy "Workflow owners can insert shares"
|
||
|
|
on public.workflow_shares for insert
|
||
|
|
with check (
|
||
|
|
shared_by_user_id = public.current_user_id_text()
|
||
|
|
and exists (
|
||
|
|
select 1
|
||
|
|
from public.workflows w
|
||
|
|
where w.id = workflow_id
|
||
|
|
and w.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Workflow owners can update shares" on public.workflow_shares;
|
||
|
|
create policy "Workflow owners can update shares"
|
||
|
|
on public.workflow_shares for update
|
||
|
|
using (shared_by_user_id = public.current_user_id_text())
|
||
|
|
with check (shared_by_user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Workflow owners can delete shares" on public.workflow_shares;
|
||
|
|
create policy "Workflow owners can delete shares"
|
||
|
|
on public.workflow_shares for delete
|
||
|
|
using (shared_by_user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible chats" on public.chats;
|
||
|
|
create policy "Users can view accessible chats"
|
||
|
|
on public.chats for select
|
||
|
|
using (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
or (
|
||
|
|
project_id is not null
|
||
|
|
and public.project_is_accessible(project_id)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can insert their own chats" on public.chats;
|
||
|
|
create policy "Users can insert their own chats"
|
||
|
|
on public.chats for insert
|
||
|
|
with check (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
and (
|
||
|
|
project_id is null
|
||
|
|
or public.project_is_accessible(project_id)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Chat owners can update chats" on public.chats;
|
||
|
|
create policy "Chat owners can update chats"
|
||
|
|
on public.chats for update
|
||
|
|
using (user_id = public.current_user_id_text())
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Chat owners can delete chats" on public.chats;
|
||
|
|
create policy "Chat owners can delete chats"
|
||
|
|
on public.chats for delete
|
||
|
|
using (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible chat messages" on public.chat_messages;
|
||
|
|
create policy "Users can view accessible chat messages"
|
||
|
|
on public.chat_messages for select
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and (
|
||
|
|
c.user_id = public.current_user_id_text()
|
||
|
|
or (
|
||
|
|
c.project_id is not null
|
||
|
|
and public.project_is_accessible(c.project_id)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Chat owners can insert messages" on public.chat_messages;
|
||
|
|
create policy "Chat owners can insert messages"
|
||
|
|
on public.chat_messages for insert
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and c.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Chat owners can update messages" on public.chat_messages;
|
||
|
|
create policy "Chat owners can update messages"
|
||
|
|
on public.chat_messages for update
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and c.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
)
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and c.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Chat owners can delete messages" on public.chat_messages;
|
||
|
|
create policy "Chat owners can delete messages"
|
||
|
|
on public.chat_messages for delete
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and c.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible tabular reviews" on public.tabular_reviews;
|
||
|
|
create policy "Users can view accessible tabular reviews"
|
||
|
|
on public.tabular_reviews for select
|
||
|
|
using (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
or public.email_is_shared(shared_with)
|
||
|
|
or (
|
||
|
|
project_id is not null
|
||
|
|
and public.project_is_accessible(project_id)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can insert their own tabular reviews" on public.tabular_reviews;
|
||
|
|
create policy "Users can insert their own tabular reviews"
|
||
|
|
on public.tabular_reviews for insert
|
||
|
|
with check (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
and (
|
||
|
|
project_id is null
|
||
|
|
or public.project_is_accessible(project_id)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Review owners can update tabular reviews" on public.tabular_reviews;
|
||
|
|
create policy "Review owners can update tabular reviews"
|
||
|
|
on public.tabular_reviews for update
|
||
|
|
using (user_id = public.current_user_id_text())
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Review owners can delete tabular reviews" on public.tabular_reviews;
|
||
|
|
create policy "Review owners can delete tabular reviews"
|
||
|
|
on public.tabular_reviews for delete
|
||
|
|
using (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible tabular cells" on public.tabular_cells;
|
||
|
|
create policy "Users can view accessible tabular cells"
|
||
|
|
on public.tabular_cells for select
|
||
|
|
using (public.review_is_accessible(review_id));
|
||
|
|
|
||
|
|
drop policy if exists "Review owners can insert tabular cells" on public.tabular_cells;
|
||
|
|
create policy "Review owners can insert tabular cells"
|
||
|
|
on public.tabular_cells for insert
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_reviews r
|
||
|
|
where r.id = review_id
|
||
|
|
and r.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Review owners can update tabular cells" on public.tabular_cells;
|
||
|
|
create policy "Review owners can update tabular cells"
|
||
|
|
on public.tabular_cells for update
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_reviews r
|
||
|
|
where r.id = review_id
|
||
|
|
and r.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
)
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_reviews r
|
||
|
|
where r.id = review_id
|
||
|
|
and r.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Review owners can delete tabular cells" on public.tabular_cells;
|
||
|
|
create policy "Review owners can delete tabular cells"
|
||
|
|
on public.tabular_cells for delete
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_reviews r
|
||
|
|
where r.id = review_id
|
||
|
|
and r.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible tabular review chats" on public.tabular_review_chats;
|
||
|
|
create policy "Users can view accessible tabular review chats"
|
||
|
|
on public.tabular_review_chats for select
|
||
|
|
using (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
or public.review_is_accessible(review_id)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Users can insert their own tabular review chats" on public.tabular_review_chats;
|
||
|
|
create policy "Users can insert their own tabular review chats"
|
||
|
|
on public.tabular_review_chats for insert
|
||
|
|
with check (
|
||
|
|
user_id = public.current_user_id_text()
|
||
|
|
and public.review_is_accessible(review_id)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Tabular chat owners can update chats" on public.tabular_review_chats;
|
||
|
|
create policy "Tabular chat owners can update chats"
|
||
|
|
on public.tabular_review_chats for update
|
||
|
|
using (user_id = public.current_user_id_text())
|
||
|
|
with check (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Tabular chat owners can delete chats" on public.tabular_review_chats;
|
||
|
|
create policy "Tabular chat owners can delete chats"
|
||
|
|
on public.tabular_review_chats for delete
|
||
|
|
using (user_id = public.current_user_id_text());
|
||
|
|
|
||
|
|
drop policy if exists "Users can view accessible tabular chat messages" on public.tabular_review_chat_messages;
|
||
|
|
create policy "Users can view accessible tabular chat messages"
|
||
|
|
on public.tabular_review_chat_messages for select
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_review_chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and (
|
||
|
|
c.user_id = public.current_user_id_text()
|
||
|
|
or public.review_is_accessible(c.review_id)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Tabular chat owners can insert messages" on public.tabular_review_chat_messages;
|
||
|
|
create policy "Tabular chat owners can insert messages"
|
||
|
|
on public.tabular_review_chat_messages for insert
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_review_chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and c.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Tabular chat owners can update messages" on public.tabular_review_chat_messages;
|
||
|
|
create policy "Tabular chat owners can update messages"
|
||
|
|
on public.tabular_review_chat_messages for update
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_review_chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and c.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
)
|
||
|
|
with check (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_review_chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and c.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
drop policy if exists "Tabular chat owners can delete messages" on public.tabular_review_chat_messages;
|
||
|
|
create policy "Tabular chat owners can delete messages"
|
||
|
|
on public.tabular_review_chat_messages for delete
|
||
|
|
using (
|
||
|
|
exists (
|
||
|
|
select 1
|
||
|
|
from public.tabular_review_chats c
|
||
|
|
where c.id = chat_id
|
||
|
|
and c.user_id = public.current_user_id_text()
|
||
|
|
)
|
||
|
|
);
|