alter table public.profiles add column name_glow boolean not null default false; create function public.protect_name_glow() returns trigger language plpgsql security invoker set search_path='' as $$ begin if ((tg_op='INSERT' and new.name_glow) or (tg_op='UPDATE' and new.name_glow is distinct from old.name_glow)) and current_user not in ('postgres','service_role') then raise exception 'Reward permission required'; end if; return new; end; $$; create trigger profiles_protect_glow before insert or update on public.profiles for each row execute function public.protect_name_glow(); revoke all on function public.protect_name_glow() from public,anon,authenticated; create table public.bug_reports ( id uuid primary key default gen_random_uuid(), client_id uuid not null unique, owner_id uuid references public.profiles(id) on delete set null, access_hash text not null check(access_hash ~ '^[a-f0-9]{64}$'), display_name text not null, title text not null check(length(title) between 5 and 120), description text not null check(length(description) between 15 and 6000), page_path text not null default '/', state text not null default 'draft' check(state in ('draft','pending','open')), screenshot_expected boolean not null default false, screenshot_path text, linear_asset_url text, linear_identifier text, issue_synced boolean not null default false, glow_requested boolean not null default false, lease_owner text, lease_until timestamptz, retry_at timestamptz, created_at timestamptz not null default clock_timestamp(), updated_at timestamptz not null default clock_timestamp() ); create index bug_reports_owner on public.bug_reports(owner_id,created_at desc); create index bug_reports_guest on public.bug_reports(access_hash,created_at desc) where owner_id is null; create table public.bug_report_messages ( id uuid primary key default gen_random_uuid(), client_id uuid, report_id uuid not null references public.bug_reports(id) on delete cascade, kind text not null check(kind in ('user','staff','system')), body text not null check(length(body) between 1 and 6000), author_name text not null, delivered boolean not null default false, external_id uuid unique, created_at timestamptz not null default clock_timestamp(), unique(report_id,client_id) ); create index bug_messages_report on public.bug_report_messages(report_id,created_at,id); alter table public.bug_reports enable row level security; alter table public.bug_report_messages enable row level security; revoke all on public.bug_reports,public.bug_report_messages from public,anon,authenticated; grant all on public.bug_reports,public.bug_report_messages to service_role; create function public.claim_bug_sync(p_report uuid,p_worker text) returns boolean language plpgsql security invoker set search_path='' as $$ begin update public.bug_reports set lease_owner=p_worker,lease_until=clock_timestamp()+interval '2 minutes' where id=p_report and state<>'draft' and (lease_until is null or lease_until'draft' for update; if not found then return false; end if; if exists(select 1 from public.bug_report_messages where external_id=p_external) then return false; end if; if p_glow is null and (p_body is null or length(p_body) not between 1 and 6000) then raise exception 'Invalid support reply'; end if; if p_glow is not null then update public.bug_reports set glow_requested=p_glow,updated_at=clock_timestamp() where id=p_report; if report.owner_id is not null then update public.profiles set name_glow=p_glow where id=report.owner_id; end if; end if; insert into public.bug_report_messages(id,report_id,kind,body,author_name,delivered,external_id) values(gen_random_uuid(),p_report,case when p_glow is null then 'staff' else 'system' end, case when p_glow is null then p_body when p_glow then 'Username glow granted.' else 'Username glow removed.' end, left(coalesce(p_author,'Support'),80),true,p_external); return true; end; $$; create function public.claim_bug_report(p_report uuid,p_hash text,p_owner uuid) returns void language plpgsql security invoker set search_path='' as $$ declare report public.bug_reports; begin if p_owner is null then raise exception 'Sign in to link this report'; end if; select * into report from public.bug_reports where id=p_report and owner_id is null and access_hash=p_hash for update; if not found then raise exception 'Report not found'; end if; update public.bug_reports set owner_id=p_owner,updated_at=clock_timestamp() where id=p_report; if report.glow_requested then update public.profiles set name_glow=true where id=p_owner; end if; end; $$; revoke all on function public.claim_bug_sync(uuid,text),public.receive_bug_reply(uuid,uuid,text,text,boolean),public.claim_bug_report(uuid,text,uuid) from public,anon,authenticated; grant execute on function public.claim_bug_sync(uuid,text),public.receive_bug_reply(uuid,uuid,text,text,boolean),public.claim_bug_report(uuid,text,uuid) to service_role; insert into storage.buckets(id,name,public,file_size_limit) values('minegeo-support','minegeo-support',false,5242880) on conflict(id) do nothing;