Developer reference
Proof shares: access rules
A proof share is a public, token-addressed pointer to one sealed prescription. Owners need to be able to relabel a share without ever being able to re-point it, so the write path is deliberately narrow: row-level security limits updates to the owner's own rows, and a database trigger limits those updates to a single column.
1. Row-level security — the update policy applies to the authenticated role only, with both USING and WITH CHECK requiring auth.uid() = user_id. A signed-in user simply matches zero rows for someone else's share, so the update silently affects nothing.
2. Column guard trigger — private.proof_shares_guard_update runs BEFORE UPDATE. For any non-service role it compares old and new values and raises an exception unless the only change is note. Even a mistaken app query cannot rewrite a token.
View counting — the public verification endpoint calls public.bump_proof_share_views(token), a SECURITY DEFINER routine that increments atomically. EXECUTE is revoked from PUBLIC, anon and authenticated, and granted only to the server role, so there is no read-then-write race and no client write path to the counter.
| Column | Owner may edit | Why |
|---|---|---|
| note | editable | Owner-editable label shown on the public verification page. |
| token | immutable | Public share identifier — changing it would re-point an already-published link. |
| prescription_id | immutable | Binds the share to one sealed ledger row; must stay fixed for the proof to mean anything. |
| user_id | immutable | Ownership cannot be transferred or reassigned. |
| views | immutable | Incremented only by the trusted server routine, never from a client write. |
| created_at | immutable | Issue time is part of the audit story. |
A rejected update surfaces the database message only the note can be updated.
tests/proof-shares.test.ts — run locally with bunx vitest run tests/proof-shares.test.ts. It runs on every pull request in the Proof-shares RLS + hash-chain integrity job of .github/workflows/security-gate.yml.
- lets the owner update the note
- blocks owner updates to token
- blocks owner updates to prescription_id
- blocks owner updates to views
- blocks owner updates to created_at
- blocks reassigning the share to another user
- does not let a different signed-in user update the share
- keeps immutable fields intact after all attempts
Related reading: docs/SECURITY_CHANGELOG.md for the change that introduced the policy, and src/routes/api/public/v1/verify.ts for the public read path.