Initial working state: CL3.5 complete (Plesk sync + suspend/unsuspend)
This commit is contained in:
225
supabase/schema.sql
Normal file
225
supabase/schema.sql
Normal file
@@ -0,0 +1,225 @@
|
||||
-- Plesk Agency Portal MVP schema
|
||||
-- Run this in Supabase SQL editor.
|
||||
|
||||
create extension if not exists pgcrypto;
|
||||
|
||||
create table if not exists agencies (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
name text not null,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create table if not exists agency_members (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
agency_id uuid not null references agencies(id) on delete cascade,
|
||||
user_id uuid not null,
|
||||
role text not null check (role in ('owner', 'admin', 'member')),
|
||||
created_at timestamptz not null default now(),
|
||||
unique (agency_id, user_id)
|
||||
);
|
||||
|
||||
create table if not exists clients (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
agency_id uuid not null references agencies(id) on delete cascade,
|
||||
name text not null,
|
||||
email text,
|
||||
phone text,
|
||||
notes text,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create table if not exists plesk_instances (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
agency_id uuid not null references agencies(id) on delete cascade,
|
||||
name text not null,
|
||||
base_url text not null,
|
||||
auth_type text not null check (auth_type in ('api_key', 'basic', 'oauth_token')),
|
||||
auth_secret_encrypted text not null,
|
||||
status text not null default 'active' check (status in ('active', 'disabled')),
|
||||
last_connected_at timestamptz,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create table if not exists plesk_subscriptions (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
agency_id uuid not null references agencies(id) on delete cascade,
|
||||
plesk_instance_id uuid not null references plesk_instances(id) on delete cascade,
|
||||
client_id uuid references clients(id) on delete set null,
|
||||
|
||||
plesk_subscription_id text not null,
|
||||
name text,
|
||||
status text,
|
||||
owner_login text,
|
||||
plan_name text,
|
||||
created_at timestamptz not null default now(),
|
||||
updated_at timestamptz not null default now(),
|
||||
|
||||
unique (plesk_instance_id, plesk_subscription_id)
|
||||
);
|
||||
|
||||
create table if not exists plesk_domains (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
agency_id uuid not null references agencies(id) on delete cascade,
|
||||
plesk_instance_id uuid not null references plesk_instances(id) on delete cascade,
|
||||
subscription_id uuid not null references plesk_subscriptions(id) on delete cascade,
|
||||
|
||||
plesk_domain_id text not null,
|
||||
domain_name text not null,
|
||||
status text,
|
||||
created_at timestamptz not null default now(),
|
||||
|
||||
unique (plesk_instance_id, plesk_domain_id),
|
||||
unique (plesk_instance_id, domain_name)
|
||||
);
|
||||
|
||||
create table if not exists actions_log (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
agency_id uuid not null references agencies(id) on delete cascade,
|
||||
actor_user_id uuid,
|
||||
target_type text not null,
|
||||
target_id uuid,
|
||||
action text not null,
|
||||
status text not null default 'pending' check (status in ('pending', 'success', 'failed')),
|
||||
error_message text,
|
||||
metadata jsonb not null default '{}'::jsonb,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create table if not exists billing_accounts (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
agency_id uuid not null references agencies(id) on delete cascade,
|
||||
|
||||
stripe_customer_id text,
|
||||
stripe_subscription_id text,
|
||||
plan_id text,
|
||||
subscription_status text,
|
||||
current_period_end timestamptz,
|
||||
|
||||
created_at timestamptz not null default now(),
|
||||
updated_at timestamptz not null default now(),
|
||||
|
||||
unique (agency_id),
|
||||
unique (stripe_customer_id)
|
||||
);
|
||||
|
||||
create table if not exists entitlements (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
agency_id uuid not null references agencies(id) on delete cascade,
|
||||
key text not null,
|
||||
value jsonb not null default '{}'::jsonb,
|
||||
created_at timestamptz not null default now(),
|
||||
unique (agency_id, key)
|
||||
);
|
||||
|
||||
create or replace function set_updated_at()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
new.updated_at = now();
|
||||
return new;
|
||||
end;
|
||||
$$;
|
||||
|
||||
drop trigger if exists trg_plesk_subscriptions_updated_at on plesk_subscriptions;
|
||||
create trigger trg_plesk_subscriptions_updated_at
|
||||
before update on plesk_subscriptions
|
||||
for each row execute function set_updated_at();
|
||||
|
||||
drop trigger if exists trg_billing_accounts_updated_at on billing_accounts;
|
||||
create trigger trg_billing_accounts_updated_at
|
||||
before update on billing_accounts
|
||||
for each row execute function set_updated_at();
|
||||
|
||||
create or replace function is_agency_member(target_agency_id uuid)
|
||||
returns boolean
|
||||
language sql
|
||||
stable
|
||||
security definer
|
||||
set search_path = public
|
||||
as $$
|
||||
select exists (
|
||||
select 1
|
||||
from agency_members am
|
||||
where am.agency_id = target_agency_id
|
||||
and am.user_id = auth.uid()
|
||||
);
|
||||
$$;
|
||||
|
||||
create or replace function is_agency_admin(target_agency_id uuid)
|
||||
returns boolean
|
||||
language sql
|
||||
stable
|
||||
security definer
|
||||
set search_path = public
|
||||
as $$
|
||||
select exists (
|
||||
select 1
|
||||
from agency_members am
|
||||
where am.agency_id = target_agency_id
|
||||
and am.user_id = auth.uid()
|
||||
and am.role in ('owner', 'admin')
|
||||
);
|
||||
$$;
|
||||
|
||||
alter table agencies enable row level security;
|
||||
alter table agency_members enable row level security;
|
||||
alter table clients enable row level security;
|
||||
alter table plesk_instances enable row level security;
|
||||
alter table plesk_subscriptions enable row level security;
|
||||
alter table plesk_domains enable row level security;
|
||||
alter table actions_log enable row level security;
|
||||
alter table billing_accounts enable row level security;
|
||||
alter table entitlements enable row level security;
|
||||
|
||||
drop policy if exists agencies_select on agencies;
|
||||
create policy agencies_select on agencies
|
||||
for select using (is_agency_member(id));
|
||||
|
||||
drop policy if exists agencies_update on agencies;
|
||||
create policy agencies_update on agencies
|
||||
for update using (is_agency_admin(id));
|
||||
|
||||
drop policy if exists agency_members_select on agency_members;
|
||||
create policy agency_members_select on agency_members
|
||||
for select using (is_agency_member(agency_id));
|
||||
|
||||
drop policy if exists agency_members_manage on agency_members;
|
||||
create policy agency_members_manage on agency_members
|
||||
for all using (is_agency_admin(agency_id))
|
||||
with check (is_agency_admin(agency_id));
|
||||
|
||||
drop policy if exists clients_member_access on clients;
|
||||
create policy clients_member_access on clients
|
||||
for all using (is_agency_member(agency_id))
|
||||
with check (is_agency_member(agency_id));
|
||||
|
||||
drop policy if exists plesk_instances_member_access on plesk_instances;
|
||||
create policy plesk_instances_member_access on plesk_instances
|
||||
for all using (is_agency_member(agency_id))
|
||||
with check (is_agency_member(agency_id));
|
||||
|
||||
drop policy if exists plesk_subscriptions_member_access on plesk_subscriptions;
|
||||
create policy plesk_subscriptions_member_access on plesk_subscriptions
|
||||
for all using (is_agency_member(agency_id))
|
||||
with check (is_agency_member(agency_id));
|
||||
|
||||
drop policy if exists plesk_domains_member_access on plesk_domains;
|
||||
create policy plesk_domains_member_access on plesk_domains
|
||||
for all using (is_agency_member(agency_id))
|
||||
with check (is_agency_member(agency_id));
|
||||
|
||||
drop policy if exists actions_log_member_access on actions_log;
|
||||
create policy actions_log_member_access on actions_log
|
||||
for all using (is_agency_member(agency_id))
|
||||
with check (is_agency_member(agency_id));
|
||||
|
||||
drop policy if exists billing_accounts_member_access on billing_accounts;
|
||||
create policy billing_accounts_member_access on billing_accounts
|
||||
for all using (is_agency_member(agency_id))
|
||||
with check (is_agency_member(agency_id));
|
||||
|
||||
drop policy if exists entitlements_member_access on entitlements;
|
||||
create policy entitlements_member_access on entitlements
|
||||
for all using (is_agency_member(agency_id))
|
||||
with check (is_agency_member(agency_id));
|
||||
Reference in New Issue
Block a user