-
Notifications
You must be signed in to change notification settings - Fork 1
Add draft ADR for Composite block type #646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
edavey
wants to merge
1
commit into
main
Choose a base branch
from
adr-to-add-composite-blocks
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
119 changes: 119 additions & 0 deletions
119
docs/architecture/decisions/0013-add-composite-block-type.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| # 13: Add composite block type | ||
|
|
||
| Date: 2026-05-07 | ||
|
|
||
| Status: Draft | ||
|
|
||
| ## Context | ||
|
|
||
| ### Driver | ||
|
|
||
| Editors need to control composed content (text interspersed with dynamic data | ||
| from multiple content blocks) without developer involvement. Currently, when | ||
| rendering requires data from multiple blocks (e.g. the pension one-off arrears | ||
| paragraph which combines pension rates with a contact link), the composition | ||
| would be hardcoded in developer-maintained "formats". (See [Tools PR 156][pension-pr]) | ||
|
|
||
|
|
||
| ### Rationale | ||
|
|
||
| 1. **Editors control the copy** - text changes should not require developer | ||
| involvement. See [Content Block Editor][content-block-editor]. | ||
| 2. **Links and data are dynamic** - if a URL or rate changes, updating the | ||
| constituent block propagates automatically | ||
| 3. **Auditable** - clear visibility of what references what, via the existing | ||
| dependency tracking infrastructure | ||
| 4. **No nesting** - composite blocks cannot reference other composite blocks. | ||
| This constraint: | ||
| - Keeps the dependency graph to a single level of indirection | ||
| - Ensures the "impact of change" UI remains clear to editors | ||
| - Makes cache invalidation tractable | ||
| - Avoids circular reference challenges | ||
|
|
||
|
|
||
| ## Decision | ||
|
|
||
| Add a new block type, `composite`, which allows editors to author blocks that | ||
| combine free-form Govspeak text with embedded references to other content | ||
| blocks. | ||
|
|
||
| ### Illustrative example | ||
|
|
||
| A composite block `pension-one-off-arrears` laid out in `Edition#details`: | ||
|
|
||
| ```ruby | ||
| { | ||
| body: <<~GOVSPEAK | ||
| If you defer your | ||
| {{embed:content_block_contact:pension-office/contact_links/new_state_pension#new_state_pension_link}} | ||
| for 52 weeks, you'll get a one-off arrears payment of | ||
| {{embed:content_block_pension:new_state_pension#one_off_arrears_52_wks}}. | ||
|
|
||
| If you defer your | ||
| {{embed:content_block_contact:pension-office/contact_links/new_state_pension#new_state_pension_link}} | ||
| for 27 weeks, you'll get a one-off arrears payment of | ||
| {{embed:content_block_pension:new_state_pension#one_off_arrears_27_wks}}. | ||
| GOVSPEAK | ||
| } | ||
| ``` | ||
|
|
||
| Embedded via: `{{embed:content_block_composite:pension-one-off-arrears}}` | ||
|
|
||
| ## Consequences | ||
|
|
||
| ### Two-level dependency tracking | ||
| When an editor changes a constituent block, the "impact of change" view (currently | ||
| [`HostEditionsTableComponent`][host-editions-table]) must show: | ||
|
|
||
| 1. Documents directly embedding the changed block | ||
| 2. Composite blocks referencing the changed block | ||
| 3. Documents embedding those composite blocks | ||
|
|
||
| The existing Publishing API [dependency resolution and link expansion][link-expansion] | ||
| mechanisms will need to support this two-level walk. | ||
|
|
||
| ### Auto-update on publish | ||
| When a constituent block is published, composite blocks referencing it update | ||
| automatically. No editor action is required on the composite itself. | ||
|
|
||
| ### Schema and validation | ||
| A new `composite` schema definition is needed (see [existing schema definitions][schema-definitions]). | ||
| Validation must enforce the no-nesting constraint (reject embed codes referencing | ||
| other composite blocks). | ||
|
|
||
| ### Authoring UI | ||
| A version of the authoring widget ([Content Block Editor][content-block-editor] ) | ||
| will be used within the Content Block Manager to let editors compose blocks. | ||
|
|
||
|
|
||
| ### Out of scope | ||
|
|
||
| ### Authoring UI design | ||
| The visual editor for composing blocks (including the block picker, live preview, | ||
| and how the authoring widget from ADR 0012 is adapted for use within the Content | ||
| Block Manager itself) is an implementation concern to be designed separately. | ||
|
|
||
| ### Detailed rendering pipeline specification | ||
| The exact sequence of embed code resolution, Govspeak processing, and HTML wrapping | ||
| within the rendering API. This includes questions about how format specifiers | ||
| interact with Govspeak context (e.g. `#new_state_pension_link` rendering a local | ||
| `<a>` tag vs the default absolute URL). | ||
|
|
||
| ### Caching strategy for composite rendered output | ||
| Composite blocks depend on multiple constituent blocks, making cache invalidation | ||
| more complex than for simple blocks. The approach to caching (keyed by constituent | ||
| edition versions, TTL-based, or uncached) will be determined as part of the implementation. | ||
|
|
||
| ## References | ||
|
|
||
| - [Content Block Editor][content-block-editor] - an authoring widget to allow editors | ||
| to discover and embed content blocks | ||
| - [Publishing API: link expansion][link-expansion] - how links between | ||
| content items are stored, expanded, and resolved | ||
| - [Pension one-off arrears PR][pension-pr] - the PR which motivated the composite blocks concept | ||
|
|
||
| [content-block-editor]: https://github.com/alphagov/content-block-editor | ||
| [link-expansion]: https://github.com/alphagov/publishing-api/blob/main/docs/link-expansion.md | ||
| [pension-pr]: https://github.com/alphagov/govuk_content_block_tools/pull/156 | ||
| [host-editions-table]: https://github.com/alphagov/content-block-manager/blob/main/app/public/components/shared/host_editions_table_component.rb | ||
| [schema-definitions]: https://github.com/alphagov/content-block-manager/tree/main/app/models/schema/definitions | ||
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's to stop people creating a "composite" block without any reference to a content block, effectively creating a "snippet" content block by the back door?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing?! I guess we get the generic block for free...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wonder whether we genericise the name of this and just call it a "generic" block? Might need input from IA in this case...