Repository navigation
Put entry and entity operations in change sets - #2519
Merged
Merged
Conversation
4 tasks done
pournasserian
added a commit
that referenced
this pull request
Oct 19, 2026
Closes #2521 ## What The next F-CNT (#2416) slice: entries have the CNT-01 states (draft, in review, published, reverted and archived), and only change sets move them. Builds on entry operations in change sets (#2519). - **Core** (`FluentCMS.Core.Content`): `EntryState`, carried by `Entry` and `EntrySummary`. `EntryStates.Review` lists the change set states that hold an item in review (checks running, checks failed, awaiting review, approved). `EntryStates.AfterPublish` says what a publish leaves an entry as: published for a create or update, archived for a delete, and reverted for any item of a revert. - **In review is read, not stored**: `GetAsync` and `ListAsync` show an entry as in review while any set in a review state holds an operation on it. The query is one subquery on `ChangeSetOperations` and `ChangeSets`, so two sets reviewing one entry keep it in review until neither does, and a rejected or reopened set gives it back its earlier state with nothing to undo. - **The other states are stored** in `Entries.State` and written only by publish, in the same conditional update that moves the published version. A new entry starts as a draft. `IEntryDirectory` has no way to set a state, and writes, soft deletes and restores leave it alone. - **Migration** for SQLite and PostgreSQL: `State` defaults to `Draft`, entries that already have a published version become `Published`, and a check constraint allows only the four stored states. ## Why CNT-01 wants states that only governance moves. Storing only what publish decides, and reading in review from the sets themselves, means no write path can change a state, and there is no remembered "state before review" to get wrong when sets overlap. Choices worth a look: - **A published entry with a newer draft is still published.** The state describes what is live; the pending draft shows in `LatestVersion` against `PublishedVersion`. - **Checks failed counts as in review**, because the set is still on its way to a decision: it either goes back to open, which ends the review, or gets rejected. - **Every item of a published revert is reverted**, whether the revert republished it or took it offline, so the desk's reverted view (DSK-02) can find them. ## Tests Unit (Core): - A new entry is a draft; a revision keeps the published version and the state; `Restore` takes the state. Integration, each on SQLite and PostgreSQL: - Draft while its set is open, in review through checks running, checks failed, awaiting review and approval, draft again when reopened, published when published; `GetAsync` and `ListAsync` agree at every step. - Two sets review a published entry; rejecting one keeps it in review, rejecting both shows it as published with its pending draft. - A published delete archives the entry, its revert makes it reverted, a published update makes it published, and that update's revert makes it reverted. - A new draft, a soft delete and a restore leave a published entry published. - The migration turns an entry that already had a published version into published and leaves the other a draft, and the newest migration's `Down` works on both providers. The full suite ran locally against a `postgres:17` container as well as SQLite. No new package and no new project reference. ## Checklist - [x] Linked to an issue a maintainer has confirmed - [x] Targets `v2` - [x] Tests or docs updated where behaviour changed - [x] No tool-generated co-author trailers or footers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2515
What
The next F-CNT (#2416) slice: change sets hold operations on entries and entities, and diff, publish and revert them like schema operations (CHG-01, CHG-03, CHG-05, CHG-06). Builds on atomic publish (#2482) and revert (#2511). This is the first thing that moves
Entries.PublishedVersion.entryoperation must point at an entry of a plain content type, and anentityoperation at an entry of an entity type, in each case of a type the agent's scope allows for the operation (MCP-05). The wrong kind fails with the newitem_kind_mismatch. A missing or soft-deleted entry fails withitem_not_found, and a missing version withversion_not_found.change_set.operation_addedcarries the base version's row as previous version, as for schema items. Other kinds (media, rules) are stillitem_kind_unavailable.ItemDiff.ForEntryin Core): two versions of an entry, field by field, withValueDiff.Compare. On an entity a field's value is its whole fact, so a new source shows as a change. Fields follow the definition the shown version was written against, so the order is the same on SQLite and PostgreSQL even thoughjsonbreorders keys.DiffAsyncreads every version the entry operations name, with their definitions, in one query.base_version_stalebefore anything moves, and a soft-deleted entry fails withitem_not_found. Events:entry.published/entry.unpublished, orentity.*.EntryDirectorynow names entries of entity typesentityin its events (entity.created,entity.updatedand so on), so an entity's own events and the change set events about it share a subject.Why
Entries were stored and versioned (#2491) but nothing could put them live. Publishing through change sets keeps CHG-05's all-or-nothing rule for mixed sets of schema, entry and entity items (CHG-09), and revert comes for free from
ChangeOperation.Inverse.Choices worth a look:
ResolveEntryAsync,EntryDiffsAsync,PublishedEntriesAsync,PublishableEntry), so the SCH-05 work merges easily.Tests
Unit (Core):
ItemDiff.ForEntry: changed fields in definition order, with a removed field the type no longer has last; formatting-only differences ignored; facts compared whole; create and delete; refusal of non-entry operations and of fields that do not match the operation's versions.Integration, each on SQLite and PostgreSQL:
The full suite ran locally against a
postgres:17container as well as SQLite, after merging the latest v2. No migration, no new package and no new project reference.Checklist
v2