Skip to content

Admin board: check and repair the R2 objects' custom metadata - #262

Merged
bubulux merged 1 commit into
mainfrom
feat/255-repair-object-metadata
Oct 23, 2026
Merged

bubulux merged 1 commit into
mainfrom
feat/255-repair-object-metadata

Conversation

@bubulux

@bubulux bubulux commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator

Closes #255.

What changed

  • apps/admin/src/objects.ts:
    • expectedMetadata says what an object should carry: photos get workspace_id, shot_id and photo_id from D1 (through shot and project), renders get kind and id from their key.
    • repairPage lists 100 objects with their metadata, compares exactly, and rewrites those that differ with the same body and content type. Objects the app does not know (no photo row, another prefix) are counted and left alone.
  • POST /api/storage/repair-metadata takes { cursor?, check? }, validated strictly, and answers { checked, repaired, unknown, examples, cursor }. A page that rewrote objects is one storage.repair audit row.
  • Monitoring tab: a new "Object metadata" section with Check and Repair. Both walk every page and show the totals plus up to 10 example keys. The Audit tab labels the new action.
  • Docs: features/admin.md (API), features/monitoring.md (the section), infrastructure.md (R2 row), and the known-issues.md entry from the clone.

Decisions

  • Done in the admin Worker, which already has the bucket and D1 bindings. No new credentials, and the operator action sits behind Access and lands in the audit trail.
  • One page per call, so each request stays inside the Workers limits at any bucket size.
  • Exact comparison, so staging's rclone keys (mtime, btime) are replaced as well.
  • Rewriting puts the body again. The object's etag can change, so clients may download an image once more.

Checked

  • make check.
  • New objects.test.ts, with a bare object, a cloned one with rclone's keys, a correct one, a render and an orphan. A check counts 3 and changes nothing. A repair rewrites 3 with the body and type kept and leaves the orphan alone. A second repair finds nothing, and exactly one audit row is written. The request body is strict.

Not clicked through

  • The Monitoring section in a browser.
  • Paging with more than 100 objects (production has 191, so the first real run on staging covers it).

🤖 Generated with Claude Code

Production's objects lost their metadata (workspace_id, shot_id, photo_id; renders' kind and id) in the
bucket copy of the rename; a staging recreate loses it too (and rclone adds mtime/btime). The admin
Worker derives what each object should carry, photos from D1 and renders from their key, and
POST /api/storage/repair-metadata checks or rewrites one page of 100 objects per call (same body and
content type), leaving unknown objects alone. A page that rewrote objects is audited as storage.repair.
The Monitoring tab gets an Object metadata section with Check and Repair, which walk every page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bubulux
bubulux merged commit f0f489d into main Oct 23, 2026
5 checks passed
@bubulux
bubulux deleted the feat/255-repair-object-metadata branch October 23, 2026 13:39
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.

Production's R2 objects have lost their custom metadata (workspace_id, shot_id…)

1 participant