Skip to content

Add resource_edits review pipeline: holding table, queues, approve/reject/rollback - #24

Merged
vontell merged 6 commits into
mainfrom
claude/gifted-noether-7wb82h
Jul 27, 2026
Merged

Add resource_edits review pipeline: holding table, queues, approve/reject/rollback#24
vontell merged 6 commits into
mainfrom
claude/gifted-noether-7wb82h

Conversation

@vontell

@vontell vontell commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Problem

Crowdsourced edits and new-site submissions need a place to be held, reviewed in queues, approved/rejected, applied to the live resources table with the ability to roll back — none of which exists in a usable form yet.

Solution

A new dedicated resource_edits holding table plus the review pipeline around it. Migration: supabase/migrations/20260714231214_resource_editing.sql.

  • resource_edits — a typed mirror of the ResourceEntry fields (easy side-by-side compare) + mapped_resource link (null = new site) + a dedicated review_status (PENDING/APPROVED/REJECTED). Keeping review status separate from the mirrored operational status avoids the overloading in the earlier scratch table.
  • Integer (bigint) keys to match the real resources.id.
  • Views: resource_edits_queue, new_resources_queue, resource_edit_counts, resource_change_log.
  • RPCs (SECURITY DEFINER): approve_edit (applies the edit into resources — updates the mapped resource, or inserts a new site and auto-maps it), reject_edit, rollback_to_edit. The apply uses jsonb_populate_record, so it adapts to the real resources column types.
  • RLS: anon may only INSERT a PENDING edit; authenticated reviewers read the queues and run the RPCs.

Leaves the throwaway resource_revisions table untouched.

Verification

Dry-run against a local stub of the real integer-keyed schema (with resources.images text[] vs the edit's images jsonb, to test type adaptation):

  • queues/counts correct; approve_edit applies an update and auto-maps a new site; images converts jsonb→text[]; reject_edit and rollback_to_edit work.

Draft — needs a staging run to confirm the real resources column types and that resources.id has a default/identity for the new-site insert path.

Reference

Implements #3.

Screenshots

N/A — schema-only change.

Checklist

  • Changes have been tested locally
  • Changes have been self-reviewed

🤖 Generated with Claude Code

https://claude.ai/code/session_01DQCnNexihkvzxUYee3NUa1

claude added 3 commits July 14, 2026 22:40
Registers the read-capable Slack MCP server (browser-session token auth)
so sessions can query the Code for Philly / phlask workspace. Tokens are
supplied via SLACK_MCP_XOXC_TOKEN / SLACK_MCP_XOXD_TOKEN environment
secrets and referenced (not embedded) here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQCnNexihkvzxUYee3NUa1
… RPCs

Introduces the Supabase migration behind the crowdsourced resource-editing
review flow (#3):

- resource_edits holding table (PENDING edits, NEW/UPDATE, base_version)
- resource_history: one row per version + change log (folds in #1)
- accept_edit / reject_edit / rollback_resource transactional RPCs (#2)
- dashboard views: two review queues, per-resource counts, change log
- RLS: anon may only INSERT pending edits; reviewers run the RPCs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQCnNexihkvzxUYee3NUa1
Local dry-run against a stub Postgres surfaced that _apply_resource_snapshot
overwrote every resources column from the suggested payload, nulling any field
the edit omitted (e.g. date_created -> not-null violation).

Now overlays the suggested changes onto the current row so omitted fields are
preserved, and never lets an edit change id / date_created / creator.

Verified end-to-end: CREATE -> UPDATE -> REJECT -> ROLLBACK, with history
versions [1,2,3] = [CREATE,UPDATE,ROLLBACK] and both queues draining to 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQCnNexihkvzxUYee3NUa1

vontell commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Local dry-run ✅

Ran the migration against a throwaway Postgres 16 with a stubbed resources (columns mirroring ResourceEntry) + auth.users and the Supabase anon/authenticated roles.

  • Migration applies cleanly (enums, tables, views, RPCs, RLS, grants).
  • Exercised the full lifecycle via the RPCs:
(1) CREATE   -> v1  images preserved
(2) UPDATE   -> v2  description applied, date_created/creator preserved
(3) REJECT   -> status = REJECTED
(4) ROLLBACK -> v3  v1 state restored
    resource_history versions = [1,2,3]  change_types = [CREATE,UPDATE,ROLLBACK]
    new_resources_queue = 0   resource_edits_queue = 0

Bug caught & fixed by the dry-run (3ca7d23): _apply_resource_snapshot overwrote every resources column from the suggested payload, so any field an edit omitted got nulled (date_created hit the not-null constraint). It now overlays the suggested changes onto the current row — omitted fields are preserved — and never lets an edit change id / date_created / creator.

Caveat: this ran against a stub schema, so it validates SQL structure + RPC logic, not the exact production resources column set. Still needs a run against a real Supabase (staging branch) to confirm the column mapping.


Generated by Claude Code

-- resource_edits: holding table for pending crowdsourced submissions.
-- ---------------------------------------------------------------------------
create table public.resource_edits (
id uuid primary key default gen_random_uuid(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something to note is that our other tables are not using uuids as primary keys. Should we enforce our existing patterns here for consistency?

-- and RLS policies below.
-- ---------------------------------------------------------------------------

-- Apply a pending edit; snapshot the resulting version into history.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the use case for these SQL functions? I wonder if these should belong in our code rather than in SQL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're not planning on using these, perhaps will be good to remove to simplify these migration files

@RNR1 RNR1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a few questions

Inspecting the live Supabase schema showed the earlier design was wrong: the
team already has a `resource_revisions` table (full copy of the resources
columns + mapped_resource/mapped_resources + a review `status` of
PENDING/APPROVED/REJECTED), and `resources.id` is a bigint, not a uuid. The old
resource_edits/resource_history/uuid design would have created a parallel,
conflicting system.

Reworked to be additive and non-destructive — no new tables, no alters, no RLS
changes:
- Views: revision_edits_queue, revision_new_queue, revision_edit_counts,
  resource_change_log (all over resource_revisions).
- SECURITY DEFINER RPCs: approve_revision / reject_revision (review-state only).

Deliberately defers copying an approved revision into `resources` (and any
version bump / rollback): `status` is overloaded (operational vs review) and
`version` is a schema version, so the write-path needs the data circle to
confirm before automating a production write. Proposed path is in comments.

Dry-run against a stub matching the real integer-keyed schema: migration applies
clean; queues/counts correct; approve->APPROVED, reject->REJECTED, non-PENDING
guarded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQCnNexihkvzxUYee3NUa1
@vontell vontell changed the title Add resource-editing schema: holding table, versioned history, review RPCs Add resource-revisions review layer: queues + review-state RPCs Jul 21, 2026

vontell commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Reworked to match the live schema

Heads-up for the data circle 👀 — I inspected the live Supabase schema and reworked this PR, because the original design didn't match production:

  • resources.id is a bigint (not uuid), and it already has version.
  • resource_revisions already exists and is the holding/edits table — a full copy of the resources columns + mapped_resource/mapped_resources + a review status (PENDING/APPROVED/REJECTED). The 4 current rows are seeded edits (mapped to resources 1176–1179).

So instead of a parallel resource_edits/resource_history system, this is now additive: read-only queue/count/change-log views + approve_revision/reject_revision RPCs. Dry-run against a stub of the real schema passes (queues correct, approve→APPROVED, reject→REJECTED, non-PENDING guarded).

Two things I need confirmation on before finishing the write-path (applying an approved revision into resources):

  1. status is overloaded — operational status in resources, review status in resource_revisions. When a revision is approved, where does the operational status for the resource come from?
  2. version looks like the ResourceEntry schema version, not a per-resource counter — so how do you want version history / rollback keyed? Per-revision, or a new counter?
  3. mapped_resource vs mapped_resources currently hold the same value — is the plural replacing the singular?

Once those are settled I'll wire up approve_revision to copy into resources and add rollback. cc @marcbachan @AnilKumar3494


Generated by Claude Code

…-approve

Per design decision: resource_revisions was a throwaway table, so build a new
dedicated holding table instead and leave resource_revisions alone.

- New resource_edits table: typed mirror of the ResourceEntry fields + a
  mapped_resource link (null = new site) + a DEDICATED review_status
  (PENDING/APPROVED/REJECTED), fixing the operational-vs-review status overload.
- Integer (bigint) keys to match resources.id.
- Views: resource_edits_queue, new_resources_queue, resource_edit_counts,
  resource_change_log.
- RPCs: approve_edit (applies the edit into resources — update mapped or insert
  new site), reject_edit, rollback_to_edit. The copy uses jsonb_populate_record
  so it adapts to the real resources column types.
- RLS: anon may only INSERT a PENDING edit; reviewers read + run the RPCs.

Dry-run against a stub (resources.images text[] vs edit.images jsonb) passes:
queues correct, approve applies + auto-maps new sites, images converts across
types, reject + rollback work.

DRAFT: still needs a staging run to confirm real resources column types and
that resources.id has a default/identity for the new-site insert path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQCnNexihkvzxUYee3NUa1
@vontell vontell changed the title Add resource-revisions review layer: queues + review-state RPCs Add resource_edits review pipeline: holding table, queues, approve/reject/rollback Jul 22, 2026

vontell commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Update / correction to my earlier comment: resource_revisions turned out to be a throwaway/experiment table, so this PR now creates a new dedicated resource_edits table (typed mirror of the resource fields + mapped_resource + a dedicated review_status) and leaves resource_revisions alone. My earlier questions about its overloaded status no longer apply. The PR description above reflects the current design. cc @marcbachan @AnilKumar3494


Generated by Claude Code

Drops the views, functions, and resource_edits table (with its policies and
indexes); leaves resources and resource_revisions untouched. Kept in
supabase/rollback/ so the Supabase CLI won't apply it as a forward migration.
Verified: up -> down leaves the schema as it started.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQCnNexihkvzxUYee3NUa1
@vontell
vontell merged commit 851d8f4 into main Jul 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants