Skip to content

feat(api): revert a form to its previous published version - #229

Merged
josue-commits merged 6 commits into
developfrom
feat/api-v1-revert
Oct 13, 2026
Merged

josue-commits merged 6 commits into
developfrom
feat/api-v1-revert

Conversation

@josue-commits

Copy link
Copy Markdown
Contributor

Summary

Adds a one-step undo for publishing. POST /v1/forms/:id/revert (and a matching button in the editor) puts the previously published version of a form back live. Live destinations are kept, the draft is never touched, and reverting twice undoes the revert.

Changes

  • db: publishForm keeps the replaced config and its publish date; new revertForm swaps live and previous configs with a guarded UPDATE (retries on a concurrent write, returns STALE after 3 raced attempts). Uses the columns from migration 0024, so no new migration.
  • api: POST /v1/forms/:id/revert returns 200 with the form, 409 NOTHING_TO_REVERT ({error, message}) or 404. Scoped by account, allowed for API keys. The stored previous config is never returned and webhook secrets stay masked.
  • web: the publish menu gets a revert action with the previous publish date and a confirmation dialog; disabled when there is nothing to revert. After a revert the editor shows the reverted live config when no draft is pending.
  • shared: EN and ES copy in the shared i18n catalog.
  • Changeset for @quill/db and @quill/shared.

How it was tested

  • pnpm typecheck, pnpm lint and pnpm test on SQLite (db, api, web, shared and the other packages) all green on Node 22.
  • Full @quill/db suite on Postgres (366/366).
  • New specs: apps/api/src/form-revert.spec.ts, packages/db/src/form-revert.spec.ts, publish-button.spec.tsx (disabled state, date, dialog, 409, Spanish).
  • PUBLISH_GATE_LOCAL=1 pnpm run publish-gate passes.

Review notes

An independent review fixed two small gaps (commit 7db3908):

  • Restored an orphaned JSDoc in the form editor after openConfig was extracted.
  • Added tests for the guarded-UPDATE retry path and the STALE result.

Known, left as is: a brand kit applied after the last publish is not carried over by a revert (the spec keeps only destinations); onReverted in the editor is covered by Playwright, not vitest.

🤖 Generated with Claude Code

josue-commits and others added 6 commits October 12, 2026 17:48
publishForm now copies the live config it replaces into previous_config,
column to column in the same UPDATE, and dates it in
previous_published_at_ms (the last publish, or the form's creation for a
form that was live before its first publish).

revertForm swaps the live config with the previous one, dates included,
so reverting twice undoes the revert. It carries the destinations the
form has now over the restored version and never touches the pending
draft. NOTHING_TO_REVERT when there is no previous version. The swap is
one stamp-guarded UPDATE, retried on a concurrent write.

FormRow gains previousPublishedAt; the stored version stays server side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josue Hernandez <josue@daptatech.com>
Puts the previously published version back live and answers the form,
with publicUrl, editorUrl and previousPublishedAt like every form
response. 409 NOTHING_TO_REVERT when there is nothing to go back to.
Allowed with an API key. Documented in the OpenAPI document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josue Hernandez <josue@daptatech.com>
…version

admin.publish gains the publish menu label, the revert item with its
date hint and disabled hint, the confirmation (which names the date of
the version that goes live and says the draft does not change), and the
success and error messages. EN and ES.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josue Hernandez <josue@daptatech.com>
The Publish button gains a menu (the chevron beside it) with "Revert to
the previous published version". The item shows when that version went
live, is disabled while there is none, and asks first in a dialog that
names the date and says the draft does not change. Pending edits are
flushed before the call, as Publish does.

After a revert the editor adopts the new stamp, refreshes its option
locks, and, when no draft is pending, puts the reverted live config on
screen so the next edit does not resurrect the version just taken down.
A publish lights the item up without a reload, and a 409
NOTHING_TO_REVERT greys it out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josue Hernandez <josue@daptatech.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josue Hernandez <josue@daptatech.com>
Also move openConfig above reanchorAfterDelete's doc comment, which the
extraction had left orphaned above the wrong function.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josue Hernandez <josue@daptatech.com>
@josue-commits
josue-commits merged commit a9a7c64 into develop Oct 13, 2026
6 checks 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.

1 participant