create table if not exists public.workspace_billing_accounts ( id uuid primary key default gen_random_uuid(), workspace_id uuid not null references public.workspaces (id) on delete cascade, plan_code text, billing_interval text check (billing_interval in ('monthly', 'annual', 'custom')), status text not null check (status in ('not_configured', 'inactive', 'active', 'past_due', 'canceled')), current_period_starts_at timestamptz, current_period_ends_at timestamptz, cancel_at_period_end boolean not null default false, canceled_at timestamptz, trial_ends_at timestamptz, external_customer_ref text, external_subscription_ref text, created_at timestamptz not null default now(), updated_at timestamptz not null default now(), constraint workspace_billing_accounts_workspace_id_key unique (workspace_id), constraint workspace_billing_accounts_period_bounds_check check ( (current_period_starts_at is null and current_period_ends_at is null) or (current_period_starts_at is not null and current_period_ends_at is not null) ) ); create table if not exists public.workspace_usage_periods ( id uuid primary key default gen_random_uuid(), workspace_id uuid not null references public.workspaces (id) on delete cascade, billing_account_id uuid not null references public.workspace_billing_accounts (id) on delete cascade, period_starts_at timestamptz not null, period_ends_at timestamptz not null, created_at timestamptz not null default now(), updated_at timestamptz not null default now(), constraint workspace_usage_periods_workspace_period_key unique (workspace_id, period_starts_at, period_ends_at), constraint workspace_usage_periods_bounds_check check (period_starts_at < period_ends_at) ); create table if not exists public.workspace_usage_counters ( id uuid primary key default gen_random_uuid(), usage_period_id uuid not null references public.workspace_usage_periods (id) on delete cascade, workspace_id uuid not null references public.workspaces (id) on delete cascade, resource text not null check (resource in ('research_credits', 'exports', 'enrichments', 'api_requests')), consumed_quantity integer not null default 0 check (consumed_quantity >= 0), created_at timestamptz not null default now(), updated_at timestamptz not null default now(), constraint workspace_usage_counters_period_resource_key unique (usage_period_id, resource) ); create table if not exists public.workspace_addon_purchases ( id uuid primary key default gen_random_uuid(), workspace_id uuid not null references public.workspaces (id) on delete cascade, addon_code text not null check (addon_code in ('export_pack_10k', 'export_pack_50k', 'enrichment_pack_1k', 'ai_assistant_monthly', 'white_label_monthly')), resource text not null check (resource in ('research_credits', 'exports', 'enrichments', 'api_requests')), purchased_quantity integer not null check (purchased_quantity >= 0), remaining_quantity integer not null check (remaining_quantity >= 0), purchased_at timestamptz not null default now(), expires_at timestamptz, external_purchase_ref text, created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); create table if not exists public.workspace_addon_balances ( id uuid primary key default gen_random_uuid(), workspace_id uuid not null references public.workspaces (id) on delete cascade, addon_code text not null check (addon_code in ('export_pack_10k', 'export_pack_50k', 'enrichment_pack_1k', 'ai_assistant_monthly', 'white_label_monthly')), resource text not null check (resource in ('research_credits', 'exports', 'enrichments', 'api_requests')), remaining_quantity integer not null default 0 check (remaining_quantity >= 0), expires_at timestamptz, created_at timestamptz not null default now(), updated_at timestamptz not null default now(), constraint workspace_addon_balances_workspace_addon_resource_key unique (workspace_id, addon_code, resource) ); create index if not exists workspace_billing_accounts_status_idx on public.workspace_billing_accounts (status); create index if not exists workspace_billing_accounts_plan_code_idx on public.workspace_billing_accounts (plan_code); create index if not exists workspace_usage_periods_workspace_id_idx on public.workspace_usage_periods (workspace_id); create index if not exists workspace_usage_counters_workspace_id_idx on public.workspace_usage_counters (workspace_id); create index if not exists workspace_addon_purchases_workspace_id_idx on public.workspace_addon_purchases (workspace_id); create index if not exists workspace_addon_balances_workspace_id_idx on public.workspace_addon_balances (workspace_id); drop trigger if exists set_workspace_billing_accounts_updated_at on public.workspace_billing_accounts; create trigger set_workspace_billing_accounts_updated_at before update on public.workspace_billing_accounts for each row execute function public.set_updated_at(); drop trigger if exists set_workspace_usage_periods_updated_at on public.workspace_usage_periods; create trigger set_workspace_usage_periods_updated_at before update on public.workspace_usage_periods for each row execute function public.set_updated_at(); drop trigger if exists set_workspace_usage_counters_updated_at on public.workspace_usage_counters; create trigger set_workspace_usage_counters_updated_at before update on public.workspace_usage_counters for each row execute function public.set_updated_at(); drop trigger if exists set_workspace_addon_purchases_updated_at on public.workspace_addon_purchases; create trigger set_workspace_addon_purchases_updated_at before update on public.workspace_addon_purchases for each row execute function public.set_updated_at(); drop trigger if exists set_workspace_addon_balances_updated_at on public.workspace_addon_balances; create trigger set_workspace_addon_balances_updated_at before update on public.workspace_addon_balances for each row execute function public.set_updated_at(); insert into public.workspace_billing_accounts ( workspace_id, plan_code, billing_interval, status, current_period_starts_at, current_period_ends_at ) select w.id, 'starter_monthly', 'monthly', 'active', now(), now() + interval '1 month' from public.workspaces w where not exists ( select 1 from public.workspace_billing_accounts billing where billing.workspace_id = w.id ); update public.workspace_billing_accounts set plan_code = 'starter_monthly', billing_interval = 'monthly', status = 'active', current_period_starts_at = coalesce(current_period_starts_at, now()), current_period_ends_at = coalesce(current_period_ends_at, now() + interval '1 month') where plan_code is null and status = 'not_configured';