pushword/page-workflow covers two distinct editorial scenarios:
page_editorial workflow) — a page that has never been published goes through draft → in_review → approved. Once approved, it can be published.page_pending_modification workflow) — an editor prepares a change to a live page in isolation. A reviewer compares the proposed payload against the live page and approves or rejects. Approval applies the payload atomically to the live row.The two workflows are independent. The live page row is never in in_review because of a pending change: only the PendingModification carries that workflow state, while the published row keeps serving.
PageEditorialState — companion entity (1:0..1 to Page), holds workflowState, reviewedBy, reviewedAt for the new-page workflow. Lives in its own table; the Page entity stays clean.PendingModification — value object snapshotting the editorial fields (h1, mainContent, title, name, metaRobots) that an editor proposes. Carries its own workflow state.PendingModificationStorageInterface — persistence boundary. Two implementations:FilePendingModificationStorage (default): JSON snapshot under var/page-workflow/{id}/pending.json.FlatPendingModificationStorage (auto-active when pushword/flat is installed): writes {slug}.pending.md next to the live {slug}.md so git captures the proposed change.# config/packages/pushword_page_workflow.yaml
pushword_page_workflow:
editorial_workflow: true # register page_editorial + page_pending_modification (default true)
require_approval_before_publish: false # block publishedAt until the page_editorial state is 'approved'
When editorial_workflow: false, neither workflow is registered and the admin UI hides itself.
In the EasyAdmin Page edit view:
PendingModification storage, never to the live row.The page index lists each page's current editorial state as a column.
The system does not block direct edits to the live row while a PendingModification is in review. If both happen, the compare view shows the diff between the current live and the pending payload — the reviewer sees exactly what approval would change, including any concurrent hotfix that would be overwritten.
When pushword/flat is installed:
{slug}.pending.md (YAML frontmatter + Markdown body). Git tracks every save.pw:flat:sync and the file watcher skip *.pending.md — only the live {slug}.md round-trips with the database.{slug}.md is rewritten by PageExporter, and {slug}.pending.md is removed. Git records both operations.The workflow guards inherit the existing security model:
approve (on either workflow) requires ROLE_EDITOR by default.submit and request_changes are open to any authenticated admin.Override by redeclaring the workflow under framework.workflows.page_editorial (or page_pending_modification) in your application config — the bundle's defaults are skipped when an entry with the same key already exists.