-- User consent to the user agreement and the privacy policy -- (docs/tasks/PROGRESS-legal-consent-20260930.md). -- -- One row per (user, document, version) the user accepted. Rows are -- append-only: a user can read and insert their own, never update or delete -- them, so the record of what was accepted and when stays as it was written. -- `ip_hash` is a salted SHA-256 of the client address (never the address), and -- `user_agent` is truncated to 160 characters. -- -- Rows cascade with the account (account deletion removes them). -- -- Backward compatibility: additive only. One new table, its index and -- policies; no existing table, column, function or grant changes. begin; create table if not exists public.user_consents ( id uuid primary key default gen_random_uuid(), user_id uuid not null references auth.users(id) on delete cascade, document text not null check (document in ('terms', 'privacy')), version text not null check (version ~ '^[A-Za-z0-9][A-Za-z0-9._:+-]{0,63}$'), accepted_at timestamptz not null default now(), ip_hash text check (ip_hash is null or ip_hash ~ '^[a-f0-9]{64}$'), user_agent text check (user_agent is null or char_length(user_agent) <= 160), unique (user_id, document, version) ); create index if not exists user_consents_user_document_idx on public.user_consents (user_id, document, accepted_at desc); alter table public.user_consents enable row level security; drop policy if exists user_consents_select_own on public.user_consents; create policy user_consents_select_own on public.user_consents for select to authenticated using ((select auth.uid()) = user_id); drop policy if exists user_consents_insert_own on public.user_consents; create policy user_consents_insert_own on public.user_consents for insert to authenticated with check ((select auth.uid()) = user_id); revoke all on table public.user_consents from anon, authenticated, service_role; grant select on table public.user_consents to authenticated; grant insert (user_id, document, version, ip_hash, user_agent) on table public.user_consents to authenticated; commit;