Skip to content

Commit b3f4e27

Browse files
committed
Add ADR for the forms schema refactor
This commit adds an ADR that explains why we have adopted the new forms structure in configurable documents schema and the benefit for us, especially with validating nested blocks. PR: #10972
1 parent eabb594 commit b3f4e27

1 file changed

Lines changed: 91 additions & 0 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# 9. Separate configurable document forms and presenters from attribute schema
2+
3+
## Status
4+
5+
Accepted
6+
7+
## Context
8+
9+
The configurable document schema introduced in [ADR-0006](./0006-config-driven-content-types.md) and evolved in [ADR-0007](./0007-use-rails-validation-for-configurable-documents.md) and [ADR-0008](./0008-drop-json-schema-for-document-configuration.md) defined document properties under `schema.properties` and grouped UI fields via `settings.edit_screens`. This conflated three concerns:
10+
11+
- How publishers see and group fields in the UI (form layout and copy).
12+
- How field values are presented to downstream systems (e.g. Publishing API payload mapping and transformations).
13+
- How attributes and validations are defined and enforced.
14+
15+
This coupling made it hard to:
16+
17+
- Group related fields in the UI without affecting payload mapping.
18+
- Present the same attribute differently to publishers and Publishing API. E.g Duration block in topical events holding data for `start_date` and `end_date` but needed to be presented as individual fields to publishing API.
19+
- Flatten validations while still allowing nested form structures, leading to complex validation logic.
20+
21+
## Decision
22+
23+
We refactored the configurable document type schema to separate concerns:
24+
25+
1. Introduced a top-level `forms` hash describing UI forms and their fields (label, description, block type), replacing `settings.edit_screens`.
26+
2. Replaced `schema.properties` with `schema.attributes`, limited to leaf attributes; we no longer model nested properties at the schema level.
27+
3. Introduced a top-level `presenters` hash to describe how attribute values are mapped or transformed for downstream consumers (e.g. Publishing API), helping to decouple UI layout from payload shape.
28+
4. Flattened validation definitions so `schema.validations` lists validators by attribute name; nested validations inside a property definition are removed.
29+
5. Removed the option to declare attributes as `object` types to enforce the flattened model and prevent reintroduction of nested schema structures.
30+
6. Updated the configurable document type JSON schema to validate the new structure and removed obsolete nested-schema code paths.
31+
32+
## Consequences
33+
34+
- All configurable document type definitions must use `schema.attributes`, `forms`, and `presenters`; `settings.edit_screens` and nested property validations are no longer supported.
35+
- UI layout changes (field grouping, titles, descriptions, block types) can now be made in `forms` without impacting Publishing API payloads, which are defined in `presenters`.
36+
- Validators will run against the flattened `schema.attributes` namespace. Added tests ensure nested data values stored in block content are preserved when present in the payload.
37+
- Future support for genuinely nested attribute schemas or arrays would need a new design rather than reintroducing `object` types.
38+
- It now becomes easier to present the same attribute differently in the UI and Publishing API (or any other consumer in future) by defining separate mappings in `forms` and `presenters`.
39+
40+
## Example
41+
42+
A configurable document type schema following the new structure will be identical to this:
43+
44+
```json
45+
{
46+
"key": "example_document_type",
47+
"title": "Example Document Type",
48+
"description": "An example document type with configurable forms and presenters",
49+
"forms": {
50+
"documents": {
51+
"fields": {
52+
"body": {
53+
"title": "Body",
54+
"description": "The main content area",
55+
"block": "govspeak"
56+
},
57+
"lead_paragraph": {
58+
"title": "Lead Paragraph",
59+
"description": "A short introduction",
60+
"block": "default_string"
61+
}
62+
}
63+
}
64+
},
65+
"schema": {
66+
"attributes": {
67+
"body": {
68+
"type": "string"
69+
},
70+
"lead_paragraph": {
71+
"type": "string"
72+
},
73+
},
74+
"validations": {
75+
"presence": {
76+
"attributes": ["body", "lead_paragraph"]
77+
},
78+
"length": {
79+
"attributes": ["lead_paragraph"],
80+
"maximum": 255
81+
}
82+
}
83+
},
84+
"presenters": {
85+
"publishing_api": {
86+
"body": "govspeak",
87+
"lead_paragraph": "string"
88+
}
89+
}
90+
}
91+
```

0 commit comments

Comments
 (0)