CodamAIDocs
Topicdone

Rolling back to an old state

A rollback creates a new revision with the old content. What comes back (own fields, single references) and what does not (lists, deleted objects).

Variants
simple fieldssingle referenceslists (not)deleted object (not)revision of another object → rejectedSingleton

What this is about

A rollback sets an object back to the state of an older revision. You name the id of the object and the number of the revision, which you know from the history (revisionMeta.ref).

The history is not rewritten in the process. CDMS writes the old state onto the object as a new revision, just like a normal change. All revisions in between stay, and you can undo the rollback itself as well.

Before and after

flowchart LR
    subgraph V["before"]
      A["17 · ADD<br/>price 90.8"] --> B["42 · MOD<br/>price 120.5"] --> C["51 · MOD<br/>price 99.0"]
    end
    subgraph N["after"]
      A2["17 · ADD<br/>price 90.8"] --> B2["42 · MOD<br/>price 120.5"] --> C2["51 · MOD<br/>price 99.0"] --> D2["58 · MOD<br/>price 90.8<br/>rollback to 17"]
    end
    V -- "POST /{id}/rollback/17" --> N
Rolling back an order to revision 17
Request
POST /api/rest/order/7e1…/rollback/17
{ "response": ["orderNr", "price", "_updatedOn"] }
Response
{ "data": { "id": "7e1…", "orderNr": "A-1000", "price": 90.8,
            "_updatedOn": "2026-09-20 14:05:11" },
  "meta": { "error": false, … } }

The response is the same as for reading: the object in its new state with the fields from response. response is required. See Field selection with response.

The flow

POST /order/{id}/rollback/{revision}
  1. 1
    Client→CDMS
    sends POST /order/7e1…/rollback/17 with response
  2. 2
    CDMS
    Is the object visible to the person? It is searched with the same filters as for changing.
    No, or deleted → 404 not-found|<Dto>|<id>. See Why invisible objects return 404.
  3. 3
    CDMS
    Does the person have the rollback role of the model?
    No → 403.
  4. 4
    Hook
    The before hooks for ROLLBACK run, with the object in its current state.
  5. 5
    CDMS→Database
    Does revision 17 belong to this object?
    Revision 0 or lower → 400 invalid-history-revision|<no>. Not a revision of this object → 404 history-revision-not-found|<no>.
  6. 6
    CDMS→Database
    copies the state of revision 17 onto the object: simple fields and single references
    A single reference whose target has since been deleted → 404 history-relation-not-found|<field>|<id>.
  7. 7
    CDMS
    May you read the targets the rollback re-links?
    Only single references that change are checked: the old and the new target, as for linking and unlinking. Target invisible to you → 404 missing-object|<id>|<model>. Read role of the target model missing → 403. Either discards the whole rollback.
  8. 8
    CDMS→File storage
    for file models: brings back the content that belongs to revision 17
  9. 9
    Hook
    The after hooks for ROLLBACK run, with the object in its rolled-back state.
  10. 10
    CDMS→Client
    reads the object back with response and answers
    Result: The request ends successfully, Envers writes the new revision 58. Any error along the way discards the whole change in the database.

Reading back at the end is a normal read. For it you also need the read role of the model and the roles of the references you name in response.

What comes back

Part of the objectDuring a rollback
simple fields (text, number, date, enum …)come back, including null from the old revision
single reference (points to one object)comes back: the object points to the same target as back then again. The target itself is not changed. If the rollback re-links, you must be allowed to read the old and the new target.
lists (1:n, n:m)stay as they are now
idstays
_createdOnstays
_updatedOnstays unchanged, the rollback does not set a new time
_version for file modelsis incremented like on every change
file contentcomes back, see Rollback for files
fields that did not exist yet in the old revisionbecome empty

More about the system fields in System fields that the server sets.

The variants

What a rollback does with which part

When: The object has received other values since revision 17.

Every simple field gets the value from revision 17. Fields you never changed are written too, nothing changes there.

Result: New MOD revision with exactly the state of 17.

When: order.company pointed to company A in revision 17, today to company B.

After the rollback the order points to company A again. The company itself keeps its current state. If company A no longer exists, the whole rollback fails with 404 history-relation-not-found|company|<id>, and nothing is changed. Re-linking is linking: if you may not see company A or company B, you get 404 missing-object; if you lack the read role for companies, 403. You do not need an update role for companies.

Result: You can only bring back targets you may read today. See The four cases.

When: The order had two items in revision 17, today three.

The list stays at three items. A rollback does not create children, does not delete any and does not move any. Every item has its own history, if its model is audited. You can roll them back one by one. A deleted item does not come back this way, though.

When: The object was deleted, the history ends with DEL.

404 not-found|<Dto>|<id>, because the object no longer exists. If you need it again, create it anew, with a new id.

Result: See What remains after a delete.

When: The number belongs to another object or does not exist at all.

404 history-revision-not-found|<no>. CDMS first checks whether the number is in the history of exactly this object. A number 0 or lower results in 400 invalid-history-revision|<no>.

When: POST /{base}/rollback/{revision}, without id in the path

The server finds the one object itself and rolls it back like any other object. If there is no object yet or it has been deleted, the answer is 404 data-not-found.

Result: See Singletons: exactly one object.

Decision table

What happens on POST /{id}/rollback/{revision}?
Object visible?Rollback role?Revision belongs to the object?Reference targets still exist?Re-linked targets readable?Result
no––––404 not-found, also for a deleted object
yesno–––403
yesyesno––404 history-revision-not-found (for a number ≤ 0: 400)
yesyesyesno–404 history-relation-not-found, nothing changed
yesyesyesyesno404 missing-object (invisible) or 403 (read role missing), nothing changed
yesyesyesyesyes200, new state as a new MOD revision

Pitfalls

What comes next

Sources in the code and the knowledge base
  • CDMS/cdms-system-layer – AbstractSystemLayer.historyRollback (assertVisibleForWrite, rollback role, ROLLBACK hooks, assertRestoredReferencesReadable, rollbackFileContent, flush, readObject), AbstractSystemSingletonLayer.historyRollback
  • CDMS/cdms-persistence-database – AuditHistoryReader.historyRollback, findRevision, copyRevisionState (metamodel, without id/version/collections, references resolved again by id), _updatedOn stays; docs/adr/ADR-019
  • CDMS/cdms-rest-api – AbstractRestApi.rollback, AbstractRestSingletonApi.rollback (branch feature/singleton-rollback)
  • CDMS/cdms-generator – ApiProcessor.getRollbackMethod, ApiSingletonProcessor.getRollbackMethod (POST /rollback/{revision})
  • CDMS/cdms-integrationtest – AbstractFileRollbackTest (rollbackAddsARevisionInsteadOfRewritingOne, rollbackWithoutTheRoleIsRefused), AbstractSingletonRollbackTest, AbstractFieldRoleTest (aRollbackCannotRelinkAFilteredRecord, aRollbackAsksForTheReadRoleOfTheTarget, aRollbackLeavesAnUnchangedReferenceAlone); probe: revision of another object 404, revision 0 → 400
Search