pluginsdk/docs/adr/0003-keyed-page-provisioning-and-render-response-data.md

59 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Provisioned pages use stable keys and render results carry safe response data
Provisioned pages were identified only by slug. Slugs are customer-facing
content and can change when an administrator renames a page, changes its
hierarchy, or mounts a plugin below a customer-specific route. A later plugin
load could therefore fail to find its page, recreate it, or attach children
and menu items to a stale location.
Decision: a page declaration may carry a plugin-scoped `Key`. `ParentKey`
references another declaration from the same plugin, while menu items use the
pair `PagePlugin` and `PageKey` so they can target a provisioned page across
plugin boundaries. The existing `ParentSlug` field remains an explicit legacy
input, but keyed references are the stable identity for new declarations.
`MountPath` is create-only. The host applies it while creating the page but
does not relocate an existing customer page during later reconciliation.
`MergeMissingBlockContent` enables a shallow default merge for matching
plugin-owned block assignments: only absent top-level keys are added, and
present values such as an empty string, zero, false, or null are preserved.
The render ABI exposes both `DerivedSlug` and `MountPath` on page and block
contexts. `DerivedSlug` is computed from the resolved hierarchy. `MountPath`
is the effective, normalized value after host inheritance, rather than the raw
stored declaration. Guests consume these values and do not reimplement host
routing rules.
Powered blocks and template documents may also request an HTTP status and a
shared `DocumentMetadata` value. Metadata is deliberately limited to title,
description, canonical URL, image URL, and robots directives. The host
validates status codes and metadata, escapes values, and accumulates status
before writing headers. Only 200599 is accepted; the highest status class
wins, with the first result retained within a class. For metadata, the first
non-empty value for each field wins in deterministic render order, after which
page/document defaults fill gaps. Arbitrary meta/link maps were rejected
because they would create a second unvalidated head-injection path; advanced
trusted templates already have the explicit `HeadExtra` surface.
Appending fields to the v1 protobuf messages was chosen over renumbering or a
Go-only helper because `abi/proto/v1` is the language-neutral contract. Slug
fallbacks remain data in that contract; the SDK does not silently synthesize
keys from mutable slugs.
Consequences:
- Plugin updates can find the same provisioned page after customer route
changes without taking ownership of the customer's chosen slug.
- Parent and menu references survive page moves and renames.
- Changing a declaration's mount path does not unexpectedly move a live page.
- Plugins can add newly introduced block defaults without overwriting customer
configuration.
- Native and WASM render code receive the same host-resolved routing values.
- Wiki-like powered blocks can return correct not-found status and structured
metadata without rendering or injecting the document envelope themselves.
Keywords: PageConfig.Key, ParentKey, ParentSlug, MountPath,
MergeMissingBlockContent, MenuItemConfig.PagePlugin, PageKey, DerivedSlug,
PageSeed, RenderContext, PoweredBlockWithOptions, DocumentMetadata,
TemplateDocument, stable identity, page provisioning