Three tables keyed on (user_id, id), two timestamps for a reason, and the column-level GRANT that is the actual paywall.
Three tables, all with (user_id, id) composite primary keys.
updated_at is the client’s own and is what LWW compares; server_updated_at is trigger-stamped. Collapsing them breaks sync in a way that looks fine until two devices disagree.docs.data is the truth. The flat columns beside it are a projection so the grid can draw without pulling every slide and image down the wire. If they ever disagree, the blob wins.posts is columnar because analytics groups and filters by those fields and a jsonb blob cannot be indexed usefully for that.doc_id has no foreign key, deliberately: a composite FK would need ON DELETE SET NULL (doc_id), which is Postgres 15+ only, and it makes account deletion order-sensitive.revoke update on public.profiles from authenticated, anon;
grant update (display_name) on public.profiles to authenticated;
revoke insert on public.profiles from authenticated, anon;
grant insert (id, email, display_name) on public.profiles to authenticated;This is the single most security-relevant passage in the repo. RLS cannot express "this row but not that column". Supabase grants authenticated UPDATE on the whole table by default, and in Postgres a column-level REVOKE does nothing while a table-wide grant stands. The only way to narrow it is to drop the table privilege and grant back the one safe column.
Get it wrong and the paywall is decorative: any signed-in user can PATCH /rest/v1/profiles with {"plan":"pro"} from the console. The INSERT narrowing matters more — without it someone creates their own row at plan: 'pro' on first sign-in and never pays.
02-pro-gate.sql makes the cloud pipeline Pro-only and has not been run. Until it is, a free account syncs its pipeline exactly like a paying one. Reads stay open to lapsed subscribers, because cancelling should not look like confiscation. Carousels are never gated — the editor is the free tier; the history is what compounds, so the history is what costs money.