From e4f4c3e963edee9ea5e1a7f561d9b98fb6be4560 Mon Sep 17 00:00:00 2001 From: biosxxx Date: Sun, 16 Aug 2026 14:23:23 +0300 Subject: [PATCH 1/4] Document the Supabase work that needs project access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things are pending that a checkout cannot do on its own, and one of them is time-sensitive: PR #164 is merged and deployed, so the production bundle already calls an Edge Function that does not exist yet. Error reports are being dropped, and the anon INSERT grant the PR exists to remove is still in place until the migration is applied. Also records the second half of the preview-check story. PR #166 fixes the is_admin() ordering; the check then fails on public.profiles, which is referenced by five migrations and defined by none. Closing that needs the real table definition dumped from production — reconstructing it from the columns the migrations happen to touch would turn the check green while describing a schema that does not exist. Co-Authored-By: Claude Opus 5 --- dev-plans/supabase-pending-work-2026-08.md | 240 +++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 dev-plans/supabase-pending-work-2026-08.md diff --git a/dev-plans/supabase-pending-work-2026-08.md b/dev-plans/supabase-pending-work-2026-08.md new file mode 100644 index 0000000..55245a2 --- /dev/null +++ b/dev-plans/supabase-pending-work-2026-08.md @@ -0,0 +1,240 @@ +# Supabase: work that must be finished from a machine with project access + +Written 2026-08-16. Everything below needs the Supabase CLI logged in against the +production project; none of it can be done from CI or from a checkout alone. + +Read task 1 first — it is the only item where production is currently in a +half-applied state, and it is losing data every hour it stays that way. + +--- + +## Task 1 — finish landing the client_error_log hardening (PR #164, merged) + +### What is already true + +PR #164 is merged and Vercel has deployed `main`. The browser bundle in +production now calls `supabase.functions.invoke('report-client-error', …)` +instead of inserting into `client_error_log` directly. + +That function does not exist yet, and the migration has not been applied. + +### What that means right now + +- **Client error reports are being dropped.** The invoke fails, the failure is + caught in `src/lib/errorReporting.ts` and logged to the console, and nothing + is stored. Nothing crashes — reporting is deliberately incapable of throwing — + but production errors are invisible until the function is deployed. +- **The hole PR #164 exists to close is still open.** `anon` keeps its `INSERT` + grant on `client_error_log` until `20260816000000` is applied, so the public + anon key can still write unbounded rows straight to PostgREST. + +Neither is an emergency, but the window should be short. Deploy the function +first (restores reporting), then apply the migration (closes the hole). + +### 1a. Deploy the Edge Function + +```bash +supabase functions deploy report-client-error --project-ref +``` + +The project ref is in the Supabase dashboard URL, or in `supabase projects list`. +Do not use a ref taken from a PR check link — those are ephemeral preview +branches and differ on every PR. + +Verify it answers before moving on: + +```bash +curl -s -X POST "https://.supabase.co/functions/v1/report-client-error" -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{"message":"deploy smoke test","source":"/manual-check"}' +``` + +Expect `{"ok":true}`. The function answers `{"ok":true}` for every outcome by +design, including throttled and malformed input, so this proves it is reachable, +not that the row landed. Confirm the row separately: + +```sql +select message, source, created_at from public.client_error_log order by created_at desc limit 5; +``` + +Delete the smoke-test row afterwards if you care about a clean table. + +### 1b. Set the IP salt (optional) + +```bash +supabase secrets set ERROR_LOG_IP_SALT="$(openssl rand -hex 32)" --project-ref +``` + +Skipping this is safe: the function falls back to the service role key as the +salt, which is unguessable and never leaves the server. Set it if you would +rather the rate-limit hashes not be derived from the service key. Changing it +later only resets the current hour's quota buckets. + +### 1c. Apply the migration + +```bash +supabase db push +``` + +This applies `20260816000000_harden_client_error_log.sql` and nothing else — +earlier versions are already recorded as applied and are not re-run, including +the historical files edited in PR #166. + +Verify the outcome. All four should hold: + +```sql +-- 1. anon has no table-level or column-level INSERT +select grantee, privilege_type from information_schema.role_table_grants +where table_name = 'client_error_log' and grantee in ('anon', 'authenticated'); +select count(*) from information_schema.column_privileges +where table_name = 'client_error_log' and grantee in ('anon', 'authenticated') + and privilege_type = 'INSERT'; + +-- 2. no INSERT policy remains +select * from pg_policies where tablename = 'client_error_log' and cmd = 'INSERT'; + +-- 3. the quota-checked path exists +select proname from pg_proc where proname = 'record_client_error'; +select tablename from pg_tables where tablename = 'client_error_report_quota'; + +-- 4. reporting still works end to end — re-run the curl above, then: +select count(*) from public.client_error_log where created_at > now() - interval '5 minutes'; +``` + +Expected: `authenticated: SELECT` only; `0` column grants; no INSERT policy; +both objects present; the count increases after the curl. + +### 1d. Confirm the direct path is actually closed + +The point of the change. This must now fail: + +```bash +curl -s -X POST "https://.supabase.co/rest/v1/client_error_log" -H "apikey: " -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{"message":"should be rejected","source":"/direct"}' +``` + +Expect a permission-denied error, not `201`. If it succeeds, the migration did +not apply — recheck 1c before assuming otherwise. + +--- + +## Task 2 — close the `public.profiles` gap in the migration history + +### Background + +The `Supabase Preview` check builds a database from `supabase/migrations/` +alone. It has been failing since 2 July. PR #166 fixed the first cause +(`is_admin()` was defined by hand in production and never entered the migration +history); the check now gets three migrations further and fails on the next +instance of the same problem: + +``` +ERROR: relation "public.profiles" does not exist (SQLSTATE 42P01) +At statement: 2 +drop trigger if exists trg_log_role_change on public.profiles +``` + +`public.profiles` is an application table created by hand in the dashboard. It +is referenced by five migrations and defined by none: + +- `20260613000001_add_admin_utility_usage_fn.sql` — first mention (inside a + function body, so it resolves lazily and does not fail at apply time) +- `20260702000000_create_admin_audit_log.sql` +- `20260702000001_account_self_service_fns.sql` +- `20260702000002_admin_analytics_fns.sql` +- `20260702000003_role_change_audit_trigger.sql` — first hard failure, because a + trigger names its table at creation time + +This is why the check fails on exactly the PRs that touch `supabase/` and is +skipped on all others: **no migration has been validated by CI since 2 July.** + +### Why this needs the real database + +The migrations only reveal the columns they happen to touch — `id`, `email`, +`full_name`, `username`, `role`. The real table certainly has more, and it +certainly has RLS policies and grants that the migrations never mention. + +Writing `create table if not exists public.profiles (…)` from those five columns +would not affect production, where the table already exists — but every preview +branch and any future rebuild would get a truncated, probably unprotected +`profiles`, and the check would go green while describing a schema that does not +exist. A green check that lies is worse than the red one. + +### Dump the real definition + +```bash +supabase db dump --project-ref --schema public > /tmp/public-schema.sql +``` + +From that file, extract everything about `profiles`, not just the table: + +- `CREATE TABLE public.profiles (…)` with all columns, defaults and constraints +- indexes +- `ALTER TABLE … ENABLE ROW LEVEL SECURITY` +- every `CREATE POLICY … ON public.profiles` +- `GRANT` / `REVOKE` statements naming `profiles` +- any trigger or function attached to it that is not already in + `supabase/migrations/` (`handle_new_user` and similar are common) + +Also dump `is_admin()` itself while you are there and compare it against the +deny-all stub PR #166 adds — the stub is only a fallback for fresh databases, +but knowing the real definition is worth having written down: + +```bash +supabase db dump --project-ref --schema public | grep -A 20 "FUNCTION public.is_admin" +``` + +### Where to put it + +Follow the pattern PR #166 established: bootstrap the object in the earliest +migration that references it, guarded so production is never touched. + +That is `20260613000001_add_admin_utility_usage_fn.sql` — the same file, which +already carries the `is_admin()` guard and is the first to mention `profiles`. +Add a guarded `create table if not exists public.profiles (…)` plus its RLS, +policies and grants above the existing function definition. + +Editing an applied migration is safe: Supabase records migrations by version and +will not re-run them, and `if not exists` means the block is inert against a +database that already has the table. + +### Verify locally before pushing + +No Supabase access needed for this part — it is the same harness used to verify +PR #166: + +```bash +docker run -d --name mig-check -e POSTGRES_PASSWORD=test -p 55440:5432 postgres:17-alpine +``` + +Scaffold **only** what Supabase itself provides, so anything missing from the +migration history shows up as a failure rather than being papered over: + +```sql +create role anon; create role authenticated; create role service_role; +create schema if not exists auth; +create table auth.users (id uuid primary key default gen_random_uuid(), email text); +create function auth.uid() returns uuid language sql stable as $$ select null::uuid $$; +``` + +Do **not** create `profiles` or `is_admin()` in the scaffold — those are the +things under test. Then apply every migration in filename order and confirm all +of them succeed. When that passes with nothing but the four lines above, the +preview check will pass too. + +--- + +## Task 3 — make the check mean something + +Once preview goes green, make it required on `main` in the branch protection +settings. It is the only thing that would have caught either of these gaps, and +while it fails for an unrelated reason it silently protects nothing. + +--- + +## Status at the time of writing + +| Item | State | +|---|---| +| PR #164 — client_error_log via Edge Function | merged; **function not deployed, migration not applied** | +| PR #165 — camera scoped to QR Master | open, CI green, needs a preview smoke test (see the PR body) | +| PR #166 — `is_admin()` bootstrap order | open, verified locally; preview still red on `profiles` | +| PR #163 — dompurify 3.4.12 → 3.4.13 | open, CI green, closes the last dependabot alert | +| dependabot `image-size` ×2 | dismissed as not-used (build-time only, no patch exists) | From 11c6770c10794b6c774743086f63b042b1abdc48 Mon Sep 17 00:00:00 2001 From: biosxxx Date: Mon, 17 Aug 2026 08:17:42 +0300 Subject: [PATCH 2/4] Add the production-sync failure to the Supabase runbook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Supabase check reports two different failures depending on where it runs, and the runbook only covered one of them. On a pull request it builds a database from the migration files and dies on public.profiles. On main it syncs to production and dies on "Remote migration versions not found in local migrations directory" — which it has been doing since at least 7 August, before any of the recent work. That second failure matters for task 1: nothing has synced to production for weeks, so db push is not going to apply the migration cleanly the way the document originally implied. Added the diagnosis, the migration list step, and the choice between capturing a remote-only version and discarding the record — with a warning against reaching for migration repair to silence the error, since that is how the drift got this far. Also frames the whole document around that drift: the repository and the production database disagree in both directions, and every task here is a symptom of it. Status table refreshed — #165 and #166 are merged, nanoid opened a new high alert today. Co-Authored-By: Claude Opus 5 --- dev-plans/supabase-pending-work-2026-08.md | 92 +++++++++++++++++++--- 1 file changed, 80 insertions(+), 12 deletions(-) diff --git a/dev-plans/supabase-pending-work-2026-08.md b/dev-plans/supabase-pending-work-2026-08.md index 55245a2..aba8cae 100644 --- a/dev-plans/supabase-pending-work-2026-08.md +++ b/dev-plans/supabase-pending-work-2026-08.md @@ -1,11 +1,20 @@ # Supabase: work that must be finished from a machine with project access -Written 2026-08-16. Everything below needs the Supabase CLI logged in against the -production project; none of it can be done from CI or from a checkout alone. +Written 2026-08-16, updated 2026-08-17. Everything below needs the Supabase CLI +logged in against the production project; none of it can be done from CI or from +a checkout alone. Read task 1 first — it is the only item where production is currently in a half-applied state, and it is losing data every hour it stays that way. +The underlying theme, worth holding in mind throughout: **`supabase/migrations/` +and the production database have drifted apart in both directions.** Objects +exist in production that the repository never defines (`is_admin()`, +`public.profiles`), and migration versions are recorded in production that the +repository does not contain. Every failure below is a symptom of that one +problem, and the work is as much about reconciling the two as about any +individual fix. + --- ## Task 1 — finish landing the client_error_log hardening (PR #164, merged) @@ -70,13 +79,61 @@ later only resets the current hour's quota buckets. ### 1c. Apply the migration +Read the next section before running this — `db push` will probably refuse. + ```bash supabase db push ``` -This applies `20260816000000_harden_client_error_log.sql` and nothing else — -earlier versions are already recorded as applied and are not re-run, including -the historical files edited in PR #166. +The intent is to apply `20260816000000_harden_client_error_log.sql` and nothing +else: earlier versions are already recorded as applied and are not re-run, +including the historical files edited in PR #166. + +#### Expect a version mismatch first + +The `Supabase Preview` check has been failing on every push to `main` since at +least 7 August — before any of the recent work — with: + +``` +Remote migration versions not found in local migrations directory. +``` + +The production database has migration versions recorded in +`supabase_migrations.schema_migrations` that do not exist as files in +`supabase/migrations/`. Someone applied migrations directly against the project +and they were never committed. This is the same problem as `is_admin()` and +`profiles`, seen from the other side: the repository is not a faithful record of +production. + +Two consequences worth being clear about: + +- **Nothing has been applied automatically.** The GitHub integration has not + successfully synced `main` to production for weeks, so `20260816000000` is + certainly not applied — and possibly neither are others. +- **`db push` will hit the same wall** until the histories agree. + +Start by seeing exactly where they diverge: + +```bash +supabase migration list --project-ref +``` + +That prints local and remote versions side by side. For each version that is +remote-only, decide deliberately: + +- **Capture it** — the right default. The migration represents real schema that + exists in production and is missing from the repo. `supabase db pull` writes + the current remote schema into a new migration file; use it to recover the + definitions (this is also where `profiles` and `is_admin()` will come from, so + it doubles up with task 2). +- **Discard the record** — `supabase migration repair --status reverted ` + tells the CLI to forget a remote entry. Only do this for versions you have + confirmed are obsolete or were superseded. It changes bookkeeping only; it + does not undo any schema change that migration made. + +Do not reach for `migration repair` to make the error go away quickly. Marking +real, applied migrations as reverted is how the repo drifts further from +production, and the drift is what caused every problem in this document. Verify the outcome. All four should hold: @@ -223,18 +280,29 @@ preview check will pass too. ## Task 3 — make the check mean something -Once preview goes green, make it required on `main` in the branch protection -settings. It is the only thing that would have caught either of these gaps, and -while it fails for an unrelated reason it silently protects nothing. +Once it goes green, make `Supabase Preview` required on `main` in the branch +protection settings. It is the only thing that would have caught any of these +gaps, and while it fails it silently protects nothing. + +Note that the check reports two different failures depending on where it runs, +and both must be fixed: + +- **on a pull request** it builds a database from `supabase/migrations/` alone — + this is the one that fails on `profiles` (task 2); +- **on `main`** it syncs to production — this is the one that fails on the + version mismatch (task 1c). --- -## Status at the time of writing +## Status as of 2026-08-17 | Item | State | |---|---| | PR #164 — client_error_log via Edge Function | merged; **function not deployed, migration not applied** | -| PR #165 — camera scoped to QR Master | open, CI green, needs a preview smoke test (see the PR body) | -| PR #166 — `is_admin()` bootstrap order | open, verified locally; preview still red on `profiles` | -| PR #163 — dompurify 3.4.12 → 3.4.13 | open, CI green, closes the last dependabot alert | +| PR #165 — camera scoped to QR Master | merged; smoke-test QR Master scanning on `/utilities/qr-master/` and `/ru/utilities/qr-master/`, plus the whisper microphone on a non-English page | +| PR #166 — `is_admin()` bootstrap order | merged; PR-side preview now gets past it and fails on `profiles` (task 2) | +| PR #167 — this document | open | +| PR #163 — dompurify 3.4.12 → 3.4.13 | open, CI green | +| dependabot `nanoid` (high, new 2026-08-17) | open; `nanoid@3.3.16` via `postcss`, patched in 3.3.18, fits the existing `pnpm.overrides` pattern in `package.json` | | dependabot `image-size` ×2 | dismissed as not-used (build-time only, no patch exists) | +| `Supabase Preview` on `main` | failing since ≥ 7 August on the version mismatch — nothing is syncing to production automatically | From 13e8666cf70a76039513c434e87e143170a4fefb Mon Sep 17 00:00:00 2001 From: biosxxx Date: Mon, 17 Aug 2026 09:47:39 +0300 Subject: [PATCH 3/4] Fix the runbook's CLI flags and its claim about what the deploy restores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both from the Codex review on this PR, and both were real. The db commands were written with --project-ref, which they do not accept. `db dump`, `migration list`, `migration repair` and `db push` select their target with --linked / --db-url / --local; only `functions deploy` and `secrets set` take --project-ref. As written, three of the commands would have exited on an unknown flag. Added a `supabase link` step up front, switched the db and migration commands to --linked, and said explicitly which two commands are the exception so the next person does not "fix" them back. The bigger one: the document told the operator to deploy the function to restore error reporting, then confirm a row had landed. Neither holds. The function stores nothing by itself — it calls record_client_error(), which the migration creates — so deploying it alone restores nothing, and the row check would have failed and made the urgent recovery step look broken. Split the verification: reachability at the deploy step, storage after the migration, with the reason stated in both places. The ordering advice stands, but for the honest reason — the deploy is cheap and unblocked while the migration is tangled up in the version mismatch. While checking flags against the CLI reference I found I had reached for `supabase functions logs` in the fix itself; there is no such subcommand, so that now points at the dashboard and says so. Steps renumbered 1a–1e. Co-Authored-By: Claude Opus 5 --- dev-plans/supabase-pending-work-2026-08.md | 90 ++++++++++++++-------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/dev-plans/supabase-pending-work-2026-08.md b/dev-plans/supabase-pending-work-2026-08.md index aba8cae..314d5bf 100644 --- a/dev-plans/supabase-pending-work-2026-08.md +++ b/dev-plans/supabase-pending-work-2026-08.md @@ -32,41 +32,67 @@ That function does not exist yet, and the migration has not been applied. - **Client error reports are being dropped.** The invoke fails, the failure is caught in `src/lib/errorReporting.ts` and logged to the console, and nothing is stored. Nothing crashes — reporting is deliberately incapable of throwing — - but production errors are invisible until the function is deployed. + but production errors are invisible. - **The hole PR #164 exists to close is still open.** `anon` keeps its `INSERT` grant on `client_error_log` until `20260816000000` is applied, so the public anon key can still write unbounded rows straight to PostgREST. -Neither is an emergency, but the window should be short. Deploy the function -first (restores reporting), then apply the migration (closes the hole). +**Reporting needs both halves — neither one alone restores it.** The function is +only a front door: it stores nothing by itself, it calls +`record_client_error()`, and that function is created by the migration. Deploy +the function without the migration and the RPC fails, the function swallows the +error and still answers `{"ok":true}`, and no row is written. -### 1a. Deploy the Edge Function +Do the function first anyway. It is a one-liner and nothing depends on it, +whereas the migration is entangled with the version mismatch described in 1d and +may take real work. Just do not read a successful deploy as reporting being +fixed — that is only true after 1d. + +Neither problem is an emergency, but the window should be short. + +### 1a. Link the project + +Every `supabase db …` and `supabase migration …` command below acts on the +*linked* project. They select their target with `--linked` / `--db-url` / +`--local` and do **not** accept `--project-ref`, so link once up front: ```bash -supabase functions deploy report-client-error --project-ref +supabase link --project-ref ``` The project ref is in the Supabase dashboard URL, or in `supabase projects list`. Do not use a ref taken from a PR check link — those are ephemeral preview branches and differ on every PR. -Verify it answers before moving on: +(`functions deploy` and `secrets set` do take `--project-ref`, and it is spelled +out below so those two steps work whether or not the link succeeded.) + +### 1b. Deploy the Edge Function ```bash -curl -s -X POST "https://.supabase.co/functions/v1/report-client-error" -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{"message":"deploy smoke test","source":"/manual-check"}' +supabase functions deploy report-client-error --project-ref ``` -Expect `{"ok":true}`. The function answers `{"ok":true}` for every outcome by -design, including throttled and malformed input, so this proves it is reachable, -not that the row landed. Confirm the row separately: +Verify it is reachable: -```sql -select message, source, created_at from public.client_error_log order by created_at desc limit 5; +```bash +curl -s -X POST "https://.supabase.co/functions/v1/report-client-error" -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{"message":"deploy smoke test","source":"/manual-check"}' ``` -Delete the smoke-test row afterwards if you care about a clean table. +Expect `{"ok":true}`. That is all this proves. The function answers `{"ok":true}` +for every outcome by design — stored, throttled, malformed, or RPC-missing — so +it cannot tell you the row landed, and at this point the row will *not* have +landed, because `record_client_error()` does not exist until 1d. The end-to-end +check that does confirm storage is at the end of 1d. -### 1b. Set the IP salt (optional) +If you want to see why nothing was stored, the function says so in its logs — +Edge Function logs live in the dashboard, under Edge Functions → +`report-client-error` → Logs. Expect a `[report-client-error] record failed` +line naming the missing function. (There is no `supabase functions logs` +subcommand; the CLI has `list`, `deploy`, `download`, `delete`, `new` and +`serve`.) + +### 1c. Set the IP salt (optional) ```bash supabase secrets set ERROR_LOG_IP_SALT="$(openssl rand -hex 32)" --project-ref @@ -77,12 +103,12 @@ salt, which is unguessable and never leaves the server. Set it if you would rather the rate-limit hashes not be derived from the service key. Changing it later only resets the current hour's quota buckets. -### 1c. Apply the migration +### 1d. Apply the migration Read the next section before running this — `db push` will probably refuse. ```bash -supabase db push +supabase db push --linked ``` The intent is to apply `20260816000000_harden_client_error_log.sql` and nothing @@ -115,18 +141,18 @@ Two consequences worth being clear about: Start by seeing exactly where they diverge: ```bash -supabase migration list --project-ref +supabase migration list --linked ``` That prints local and remote versions side by side. For each version that is remote-only, decide deliberately: - **Capture it** — the right default. The migration represents real schema that - exists in production and is missing from the repo. `supabase db pull` writes - the current remote schema into a new migration file; use it to recover the - definitions (this is also where `profiles` and `is_admin()` will come from, so - it doubles up with task 2). -- **Discard the record** — `supabase migration repair --status reverted ` + exists in production and is missing from the repo. `supabase db pull --linked` + writes the current remote schema into a new migration file; use it to recover + the definitions (this is also where `profiles` and `is_admin()` will come from, + so it doubles up with task 2). +- **Discard the record** — `supabase migration repair --linked --status reverted ` tells the CLI to forget a remote entry. Only do this for versions you have confirmed are obsolete or were superseded. It changes bookkeeping only; it does not undo any schema change that migration made. @@ -152,14 +178,18 @@ select * from pg_policies where tablename = 'client_error_log' and cmd = 'INSERT select proname from pg_proc where proname = 'record_client_error'; select tablename from pg_tables where tablename = 'client_error_report_quota'; --- 4. reporting still works end to end — re-run the curl above, then: -select count(*) from public.client_error_log where created_at > now() - interval '5 minutes'; +-- 4. reporting now works end to end — re-run the 1b curl, then: +select message, source, created_at from public.client_error_log +order by created_at desc limit 5; ``` Expected: `authenticated: SELECT` only; `0` column grants; no INSERT policy; -both objects present; the count increases after the curl. +both objects present; and the smoke-test row appearing for the first time — this +is the check that proves reporting is restored, which the deploy in 1b could not. + +Delete the smoke-test row afterwards if you care about a clean table. -### 1d. Confirm the direct path is actually closed +### 1e. Confirm the direct path is actually closed The point of the change. This must now fail: @@ -168,7 +198,7 @@ curl -s -X POST "https://.supabase.co/rest/v1/client_error_log" ``` Expect a permission-denied error, not `201`. If it succeeds, the migration did -not apply — recheck 1c before assuming otherwise. +not apply — recheck 1d before assuming otherwise. --- @@ -217,7 +247,7 @@ exist. A green check that lies is worse than the red one. ### Dump the real definition ```bash -supabase db dump --project-ref --schema public > /tmp/public-schema.sql +supabase db dump --linked --schema public > /tmp/public-schema.sql ``` From that file, extract everything about `profiles`, not just the table: @@ -235,7 +265,7 @@ deny-all stub PR #166 adds — the stub is only a fallback for fresh databases, but knowing the real definition is worth having written down: ```bash -supabase db dump --project-ref --schema public | grep -A 20 "FUNCTION public.is_admin" +supabase db dump --linked --schema public | grep -A 20 "FUNCTION public.is_admin" ``` ### Where to put it @@ -290,7 +320,7 @@ and both must be fixed: - **on a pull request** it builds a database from `supabase/migrations/` alone — this is the one that fails on `profiles` (task 2); - **on `main`** it syncs to production — this is the one that fails on the - version mismatch (task 1c). + version mismatch (task 1d). --- From fea1836084f209c9dea9ee4ca1f1b8b7615b6f01 Mon Sep 17 00:00:00 2001 From: biosxxx Date: Mon, 17 Aug 2026 21:55:57 +0300 Subject: [PATCH 4/4] Refresh the status table after #163, #168 and #169 merged No dependabot alerts remain open. What is left in the runbook is now exactly the work that needs Supabase project access, which is worth saying explicitly so the next reader does not re-audit the closed items. Co-Authored-By: Claude Opus 5 --- dev-plans/supabase-pending-work-2026-08.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dev-plans/supabase-pending-work-2026-08.md b/dev-plans/supabase-pending-work-2026-08.md index 314d5bf..961eb1e 100644 --- a/dev-plans/supabase-pending-work-2026-08.md +++ b/dev-plans/supabase-pending-work-2026-08.md @@ -331,8 +331,13 @@ and both must be fixed: | PR #164 — client_error_log via Edge Function | merged; **function not deployed, migration not applied** | | PR #165 — camera scoped to QR Master | merged; smoke-test QR Master scanning on `/utilities/qr-master/` and `/ru/utilities/qr-master/`, plus the whisper microphone on a non-English page | | PR #166 — `is_admin()` bootstrap order | merged; PR-side preview now gets past it and fails on `profiles` (task 2) | +| PR #169 — related tools use the catalog card | merged | +| PR #168 — nanoid pinned to a patched 3.x | merged | | PR #167 — this document | open | -| PR #163 — dompurify 3.4.12 → 3.4.13 | open, CI green | -| dependabot `nanoid` (high, new 2026-08-17) | open; `nanoid@3.3.16` via `postcss`, patched in 3.3.18, fits the existing `pnpm.overrides` pattern in `package.json` | -| dependabot `image-size` ×2 | dismissed as not-used (build-time only, no patch exists) | +| PR #163 — dompurify 3.4.12 → 3.4.13 | merged | +| dependabot alerts | **none open.** dompurify closed by #163, nanoid by #168, and the two `image-size` highs dismissed as not-used (build-time only, no patch exists) | | `Supabase Preview` on `main` | failing since ≥ 7 August on the version mismatch — nothing is syncing to production automatically | + +Everything that could be finished from a checkout is finished. What is left in +this document is exactly the part that needs project access, and task 1 is the +one carrying a cost while it waits.