Skip to content

Read a snapshot's content only when it is asked for - #40

Merged
mgilardi merged 1 commit into
mainfrom
snapshot-content-on-request
Nov 12, 2026
Merged

mgilardi merged 1 commit into
mainfrom
snapshot-content-on-request

Conversation

@mgilardi

Copy link
Copy Markdown
Collaborator

A stored snapshot can be 15 MB. Payload read all of it for every list, every relationship it filled in and every admin page, and a snapshot's edit page carried the whole thing in a JSON editor under the panel.

What changes

  • A read, create, update or delete of a snapshot that names no select answers with every field except snapshot. select: { snapshot: true }, REST ?select[snapshot]=true or GraphQL's select: true gives the content. A caller's own select is left exactly as asked. The export endpoint and the read API are as before.
  • In the admin the content field is on the new-snapshot form only. A stored snapshot's page is sent without the content and without the JSON editor, and Payload's own Save there sends the status alone.
  • The lock on sealed content doesn't depend on this: an update is still compared with the stored document, read whole.
  • Fixed on the way: the admin panels showed the old status after Payload's own Save. They now read from the site again when Payload reports the document saved.

The plugin has no release yet, so nothing in use changes. Hosts' code that read doc.snapshot from a plain read, or from an after-read or after-change hook's document, has to select it. ADR 0012, point 17.

Tested

  • 631 unit tests, 247 in the plugin, 10 new: 8 on a real Payload with an in-memory MongoDB (one over HTTP), 2 in jsdom.
  • 58 smoke checks over HTTP on the built example site, 3 new.
  • Five deliberate breaks, each caught (listed in docs/test-audit.md).
  • Headless Chrome on the example site, from a scratch script that is not in CI: a stored snapshot's page has no content and no editor, a sealed fixture pasted into the new-snapshot form is stored with the same checksum, and Payload's Save sends one small PATCH with the status and no content.

Not explained, and not tested

  • In that browser run, after a snapshot was made through the form and its page loaded again, Payload's read-only Counts group showed its heading with no fields under it. Four shorter runs of the same steps drew them. The cause wasn't found.
  • Postgres, SQLite, a browser with a window.

No new service and no cost.

🤖 Generated with Claude Code

A stored snapshot can be 15 MB, and Payload read all of it for every
list, every relationship it filled in and every admin page. A snapshot's
edit page carried the whole thing in a JSON editor under the panel.

A read, create, update or delete that names no select now answers with
every field except the content. A select that names it gets it, and a
caller's own select is left as asked. The content field is on the
new-snapshot form only. The lock on sealed content doesn't depend on
this: an update is still compared with the stored document, read whole.

Also fixes the admin panels showing the old status after Payload's own
Save. They read from the site again when Payload reports the document
saved.

The plugin has no release, so nothing in use changes.

Tested: 631 unit tests (247 in the plugin, 10 new), 58 smoke checks on
the built example site, and five deliberate breaks, each caught. Run in
headless Chrome from a scratch script, outside CI. Not explained: in
that run Payload's read-only Counts group once showed no fields under
its heading after a snapshot was made through the form; four shorter
runs drew them. Not tested: Postgres, SQLite, a browser with a window.

Co-Authored-By: Claude <noreply@anthropic.com>
@mgilardi
mgilardi merged commit 7f23e47 into main Nov 12, 2026
1 check passed
@mgilardi
mgilardi deleted the snapshot-content-on-request branch November 12, 2026 02:09
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.

1 participant