Skip to content

Add ADR048: Immutable Form Versioning#248

Open
theseanything wants to merge 4 commits intomainfrom
theseanything/adr-048
Open

Add ADR048: Immutable Form Versioning#248
theseanything wants to merge 4 commits intomainfrom
theseanything/adr-048

Conversation

@theseanything
Copy link
Copy Markdown
Contributor

Outlines an immutable versioning model for published forms. This includes new API endpoints for draft and versioned forms, addressing limitations in the current system and enhancing caching, submission tracking, and user experience during form completion.

Outlines the transition from a mutable document-based system to an immutable versioning model for published forms. This includes new API endpoints for draft and versioned forms, addressing limitations in the current system and enhancing caching, submission tracking, and user experience during form completion.
@theseanything theseanything self-assigned this Mar 24, 2026
| Endpoint | Description |
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `GET /api/v3/forms/:form_id/draft` | Returns the current draft form document JSON (mutable, changes as the form creator edits) |
| `GET /api/v3/forms/:form_id/versions/:form_version` | Returns an immutable, versioned form document. Once created, this content never changes. |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want live form documents to be actually immutable - or immutable from an end user perspective? The main issue we might encounter here is when we make internal changes to form structure such as adding/removing/changing attributes.
It would make it harder to make changes to forms-runner and hard to support users reverting changes if we don't also update the structure of historic form documents when we make breaking changes to the format.

There might be some things we can do to lessen the need for altering existing form documents. Currently when we add attributes to a form, we always back-fill the attribute on form documents. Potentially we can change our approach to this and fall back on default values when an attribute isn't present rather than updating it in the database.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

V good point — I think ultimately we want the semantic content to be immutable.

We could handle changes in schema in a few ways:

  1. Include a schema version in the form document. This makes it explicit to consumers how to interpret the content. It may mean we'd need to support multiple schema versions, but in practice, making sure most changes are backwards-compatible minimises the complexity around this. (Could reserve breaking schema changes for a new API version.)

  2. Weaken the immutability by keeping the semantic content the same but allowing the schema to be updated. i.e. migrate old documents to newer schemas. We wouldn't be able to cache "forever", but schema changes are probably infrequent enough that caching would still be useful.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably lean towards 1. as it gives stronger guarantees for the API, in way that is less likely to break forms-runner.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the ADR with a section on API changes.

- Audit trail. The full history of published form versions is preserved and addressable.

### Negative

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another negative is increased complexity for form processors; making it so that an old version of a form can be submitted after the new version has been made live means that submission processors need to be able to handle both old and new version submissions for a time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, but I think form processors already have this problem today. Unless a form owner can update the form and their processing system at exactly the same time, there's always a window where submissions come in against a version the processor wasn't expecting. The current setup just makes that invisible.

Explicit version numbers actually make it easier to handle. A processor can see which version a submission was made against and branch accordingly (e.g. if version 2, do X, otherwise do Y), rather than having to infer what changed from the shape of the data.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so as part of the changes for this ADR we'll expose the version information to form processors, and inform them of the change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup - added info that submissions would reference the form version. And yup, would be good to inform them.


## Decision

We will introduce an immutable versioning model for published forms, exposed through a new v3 API. The key changes are:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a way we could achieve the same aims and outcomes of this ADR but without needing a new API version; would you be interested in that or would you prefer to have a new API version?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooo! Yes always interested in hearing ideas!

Copy link
Copy Markdown
Contributor

@lfdebrux lfdebrux Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we added the /versions endpoints you're suggesting to the v2 API, and added a version link to the form documents, that would cover the same functionality more or less?

So for a form document that's been made live, regardless of where it's retrieved from, you'd see something like:

{
  form_id: "aB123x",
  name: "Test form",
  ...
  links : {
    version: "https://api.forms.service.gov.uk/api/v2/forms/aB123x/versions/9"
  }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thats a nice idea.

I think my main concern with doing this in v2: we’d end up with a slightly confusing API shape where the old state-based endpoints still exist alongside the new version-based ones.

For example, it becomes unclear what /api/v2/forms/:id/archived is meant to represent

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it still represents the form document as it was when it was archived? We have that so that it's easy for forms-runner to preview the form after its been archived but changes have been made to it. With endpoints for versions we could alternatively do that by sending them to a preview for that version, which I guess what you're proposing currently, but both still seem valid to me?

It doesn't help that I've thought about this so much that it's hard to imagine looking at it for the first time, so I'm unsure about what you mean about it being unclear 😅

When I was thinking about the v2 API I thought about the state endpoints as branches/tags in a git repository, or symbolic links in a filesystem, so that's where I'm coming from.

Added a section on hard submission deadlines to ADR048, outlining the need for strict cutoff times for certain forms. This change clarifies that archiving will no longer serve as a method to prevent future submissions and suggests a new implementation approach for managing submission deadlines.
Added a section detailing how each submission will now store the `form_version` it was made against, helping proccess handle changes to the form.
Added a section detailing schema changes
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.

3 participants