docs(10.1): create phase plans for the runtime admin extension point

Four plans: framework Go contracts and routes, framework SPA hosts,
Albums proof in fonoteka.go, and unit tests with the phase gate.
Adds ADMIN-07 to REQUIREMENTS.md and fills the Phase 10.1 roadmap goal,
success criteria and plan list.
This commit is contained in:
Jakub Zych
2026-09-28 22:25:50 +02:00
parent 04c587a5a3
commit ccdc014078
6 changed files with 1241 additions and 7 deletions

View File

@@ -462,13 +462,33 @@ Plans:
### Phase 10.1: Runtime admin extension point (INSERTED)
**Goal:** [Urgent work - to be planned]
**Requirements**: TBD
**Goal:** A plugin extends the compiled admin SPA without a Node rebuild. Controllers declare their own JS/CSS, served same-origin from the plugin's embedded files; `type: widget` fields mount plugin custom elements whose actions the SPA posts; `type: partial` form fields and a list `headerPartial` render server-side through `html/template` and reach the page without any raw-HTML sink; and controllers register named toolbar actions. The framework contract is proven on a nameless fixture plugin, and the application proof is three Albums surfaces: a statistics strip above the list, a Discogs lookup widget on the form, and a Discogs sync toolbar action, both Discogs actions as stubs that Phase 14 replaces.
**Requirements**: ADMIN-07
**Depends on:** Phase 10
**Plans:** 0 plans
**Repos:** summercms.go, fonoteka.go
**Success Criteria** (what must be TRUE):
1. A controller's declared JS/CSS is served from its plugin's embedded files under `{backend.uri}/assets/{vendor}/{plugin}/…` through an exact allowlist, loads only when that controller's list or form opens, and runs under CSP `script-src 'self'`; undeclared files and traversal attempts never leave the plugin tree.
2. A `type: widget` field mounts the plugin's custom element; its event makes the SPA POST the declared action with the admin cookie and CSRF header, and only the field's declared `fill` keys are patched onto the unsaved form.
3. A `config_list.yaml` `headerPartial` and a `type: partial` form field render server-side with `html/template` from a controller-supplied view model and reach the DOM only as an allowlisted node tree.
4. A controller registers named toolbar actions listed in `toolbar.buttons`; a click POSTs the action and toasts while `create` and `delete` keep their behaviour; unknown YAML keys, missing templates, unregistered actions and unknown permissions fail boot.
5. The Albums list shows a statistics strip scoped to the admin's collection, the Albums form shows a "Load from Discogs" widget whose stub fills Release year and Format, and a "Sync with Discogs" toolbar action toasts from its stub.
**Plans:** 4 plans
Plans:
- [ ] TBD (run $gsd-plan-phase 10.1 to break down)
**Wave 1**
- [ ] 10.1-01-PLAN.md — Framework Go: pact capability interfaces, cabana widget/partial/toolbar/asset boot rules, cabana-owned action, partial and asset routes, sanitizer, OpenAPI (summercms.go)
**Wave 2** *(blocked on Wave 1 completion)*
- [ ] 10.1-02-PLAN.md — Framework SPA: plugin asset loader, WidgetField, PartialHost and PartialField, list-header slot, custom toolbar buttons, rebuilt dist (summercms.go/admin)
**Wave 3** *(blocked on Wave 2 completion)*
- [ ] 10.1-03-PLAN.md — Application: Albums stats strip, Discogs lookup widget stub, discogsSync toolbar stub, plugin assets and copy (fonoteka.go)
**Wave 4** *(blocked on Wave 3 completion)*
- [ ] 10.1-04-PLAN.md — Unit tests last: Go and Vitest coverage, Albums acceptance, check-phase10.1.sh gate, security review and validation evidence (both repos)
### Phase 11: Jobs, realtime and search infrastructure