docs(34-05): complete admin Plugins screen plan
This commit is contained in:
@@ -1735,7 +1735,7 @@ Plans:
|
||||
4. The admin Plugins screen lists installed plugins with versions and available updates, and its Marketplace tab searches the registry and shows the install command with a copy button.
|
||||
5. The new code has unit tests, delivered in the phase's last plan.
|
||||
|
||||
**Plans:** 3/6 plans executed
|
||||
**Plans:** 4/6 plans executed
|
||||
|
||||
Plans:
|
||||
**Wave 1**
|
||||
@@ -1746,7 +1746,7 @@ Plans:
|
||||
- [x] 34-04-PLAN.md — `summer plugin:install` (module, --source, git URL) and `summer plugin:update`, `plugins.registry_url`, go.work overrides (wave 2)
|
||||
|
||||
**Wave 3** *(blocked on Wave 2 completion)*
|
||||
- [ ] 34-05-PLAN.md — admin Plugins screen: cabana endpoints, backend.view_plugins, Installed + Marketplace tabs with copy, openapi and dist (wave 3)
|
||||
- [x] 34-05-PLAN.md — admin Plugins screen: cabana endpoints, backend.view_plugins, Installed + Marketplace tabs with copy, openapi and dist (wave 3)
|
||||
|
||||
**Wave 4** *(blocked on Wave 3 completion)*
|
||||
- [ ] 34-02-PLAN.md — plugin.yaml and TestPluginManifest in every public sm-*-plugin repo, framework minimum v0.6.0, app pointer bumps after Jakub's push (wave 4)
|
||||
@@ -1809,7 +1809,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
|
||||
| 31. Chat polish against WavePath clients | 0/TBD | Not started | - |
|
||||
| 32. SEO foundation | 6/6 | In Progress| |
|
||||
| 33. SEO output, audit and content | 0/14 | Planned | - |
|
||||
| 34. Plugin marketplace | 3/6 | In Progress| |
|
||||
| 34. Plugin marketplace | 4/6 | In Progress| |
|
||||
|
||||
## Backlog
|
||||
|
||||
|
||||
253
.planning/phases/34-plugin-marketplace/34-05-SUMMARY.md
Normal file
253
.planning/phases/34-plugin-marketplace/34-05-SUMMARY.md
Normal file
@@ -0,0 +1,253 @@
|
||||
---
|
||||
phase: 34-plugin-marketplace
|
||||
plan: 05
|
||||
subsystem: admin
|
||||
tags: [cabana, boardwalk, kiosk, reka-ui, plugins-screen, registry-cache, openapi]
|
||||
|
||||
requires:
|
||||
- phase: 34-plugin-marketplace (34-01)
|
||||
provides: "party.Info, party.Installed, party.Describe; kiosk version rules (BaseVersion, CompareVersions, NewestCompatible, Satisfies) and registry wire types"
|
||||
- phase: 34-plugin-marketplace (34-04)
|
||||
provides: "kiosk.Client (List, Versions), kiosk.NewClient, kiosk.RegistryURL, kiosk.ErrNotFound, plugins.registry_url"
|
||||
provides:
|
||||
- "cabana.PermissionViewPlugins (backend.view_plugins), declared by the admin's own screens with no role grant"
|
||||
- "GET /plugins (cabana.PluginsOverview, cabana.InstalledPlugin, cabana.RegistryState) and GET /plugins/marketplace (cabana.MarketplaceResponse, cabana.MarketplacePlugin, cabana.MarketplaceMeta), swag operations AdminPluginsInstalled and AdminPluginsMarketplace"
|
||||
- "cabana.SettingsEntry.Path (JSON path, omitempty): Settings → System → Plugins links the SPA route /system/plugins"
|
||||
- "Server-side registry cache: 4 s per call, at most 4 concurrent version lookups, searches 5 min, releases 15 min, failures 1 min"
|
||||
- "SPA: /system/plugins route, PluginsView (Installed and Marketplace tabs), settingsPath honours entry.path, settingsEntryForPath for the shell"
|
||||
- "Rebuilt modules/boardwalk/dist"
|
||||
affects: [34-06 tests and release ledger, every app's admin (new Settings → System entry for superusers)]
|
||||
|
||||
actuals:
|
||||
tokens: 29000
|
||||
tasks: 3
|
||||
commits: 3
|
||||
plan_head_before: 0418900122a1cba8952ec40a8f8294fc615eb6a8
|
||||
plan_head_after: 678eac4637c26f4d57dfdaa8348fbd41e26f6616
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "A settings entry of the admin's own can open an SPA route (SettingsEntry.Path) instead of an admin controller; plugin entries are unchanged"
|
||||
- "Registry calls from cabana run on context.WithoutCancel(request) plus a timeout, so a closed tab never caches a failure, and fetchguard.WithTransport-style context values still reach the client"
|
||||
- "Degraded 200 answers: a registry failure is a status in the payload (registry.status unavailable), never a non-200"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- modules/cabana/plugins.go
|
||||
- modules/cabana/plugins_smoke_test.go
|
||||
- admin/src/views/PluginsView.vue
|
||||
- admin/tests/views/PluginsView.test.ts
|
||||
modified:
|
||||
- modules/cabana/http.go
|
||||
- modules/cabana/navigation.go
|
||||
- modules/cabana/backend_screens.go
|
||||
- modules/cabana/admin_openapi.go
|
||||
- modules/cabana/security_coverage_test.go
|
||||
- modules/cabana/token_routes_test.go
|
||||
- modules/cabana/openapi_conformance_test.go
|
||||
- modules/cabana/README.md
|
||||
- modules/phrasebook/backend/lang/en/lang.yaml
|
||||
- modules/phrasebook/backend/lang/pl/lang.yaml
|
||||
- admin/openapi/admin.json
|
||||
- admin/src/api/schema.d.ts
|
||||
- admin/src/api/types.ts
|
||||
- admin/src/app/router.ts
|
||||
- admin/src/app/pageTitle.ts
|
||||
- admin/src/state/useSettings.ts
|
||||
- admin/src/components/shell/AppShell.vue
|
||||
- admin/src/components/shell/Breadcrumbs.vue
|
||||
- admin/src/components/shell/PluginRail.vue
|
||||
- admin/tests/fixtures/lang.json
|
||||
- modules/boardwalk/dist
|
||||
- docs/backend/users-and-permissions.md
|
||||
- docs/backend/admin-spa.md
|
||||
- docs/plugins/marketplace.md
|
||||
|
||||
key-decisions:
|
||||
- "The Plugins settings entry is added by Registry.Metadata only when the registry declares backend.view_plugins (the admin's own screens are compiled), no plugin already uses the settings code plugins, and the principal is allowed; a plugin's own plugins setting therefore never breaks"
|
||||
- "The registry catalog is built once by cabana.Activate (service.catalog); a service assembled without Activate (tests) gets a fresh uncached catalog per call, because service is copied by value in existing tests and cannot hold a sync.Once"
|
||||
- "Update rule is plugin:update's: NewestCompatible(versions, framework) above BaseVersion(installed); latestFramework names the minimum of the newest release when it is newer than both the compatible latest and the installed base"
|
||||
- "A 404 for one plugin's versions is an answer (listed false, cached 15 min), not a registry failure"
|
||||
- "Marketplace entries whose ID does not match the plugin ID shape are dropped, and only https icon URLs are passed through, since the ID ends up in a shell command the administrator copies"
|
||||
- "Marketplace categories (for the filter) come from the cached unfiltered registry list and are sent in meta.categories"
|
||||
- "Registry JSON fields in the admin API use lower camel case (updateAvailable, latestFramework, iconUrl, installCommand), as the plan asked"
|
||||
|
||||
patterns-established:
|
||||
- "Admin screens of the framework that are not admin controllers: SPA route plus SettingsEntry.Path, shell helpers settingsEntryForPath"
|
||||
|
||||
requirements-completed: [SC-4, D-06, D-07, D-17, D-18, D-19]
|
||||
|
||||
coverage:
|
||||
- id: D1
|
||||
description: "GET /plugins lists installed plugins from party.Installed (party.Activated IDs for older builds) for superusers and holders of backend.view_plugins; 401/403 otherwise; Settings → System → Plugins entry with path only for allowed principals"
|
||||
requirement: D-19
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "modules/cabana/plugins_smoke_test.go#TestPluginsScreenSmoke/installed"
|
||||
status: pass
|
||||
- kind: unit
|
||||
ref: "modules/cabana/security_coverage_test.go#TestPhase09PermissionMatrix (denied plugins-installed, plugins-marketplace)"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D2
|
||||
description: "Update availability computed in Go with plugin:update's rule; describe versions compare by base tag; unlisted and local plugins get no badge"
|
||||
requirement: D-07
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "modules/cabana/plugins_smoke_test.go#TestPluginsScreenSmoke/updates,describe_base,unlisted"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D3
|
||||
description: "Registry down, slow or disabled never breaks the Installed tab; disabled sends no request; cache windows hold"
|
||||
requirement: D-18
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "modules/cabana/plugins_smoke_test.go#TestPluginsScreenSmoke/unavailable,disabled,cache"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D4
|
||||
description: "Marketplace search through cabana forwards q and category, validates them like the registry (400 invalid_query), marks installed and incompatible plugins and returns the install command"
|
||||
requirement: SC-4
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "modules/cabana/plugins_smoke_test.go#TestPluginsScreenSmoke/marketplace"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D5
|
||||
description: "OpenAPI and SPA types regenerated; contract, token-class and conformance inventories include both routes"
|
||||
requirement: D-17
|
||||
verification:
|
||||
- kind: other
|
||||
ref: "scripts/check-admin-openapi.sh --check"
|
||||
status: pass
|
||||
- kind: unit
|
||||
ref: "modules/cabana#TestPhase09ContractInventory, TestTokenRouteGates, TestPhase10ConformanceInventory"
|
||||
status: pass
|
||||
- kind: integration
|
||||
ref: "modules/cabana/openapi_conformance_test.go#TestPhase10OpenAPIConformance/GET_/plugins, GET_/plugins/marketplace (Postgres)"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D6
|
||||
description: "PluginsView: Installed rows, update badges with copyable update command, Marketplace tab (debounced search, category select, cards with markers and copyable install command, no install button), hidden tab and badges when disabled, unavailable notice, clipboard fallback"
|
||||
requirement: SC-4
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "admin/tests/views/PluginsView.test.ts (9 tests)"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D7
|
||||
description: "Embedded admin rebuilt and committed; dist gate passes"
|
||||
verification:
|
||||
- kind: other
|
||||
ref: "scripts/check-admin-dist.sh; go test ./modules/boardwalk"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D8
|
||||
description: "Visual layout of the Plugins screen (table, badges, marketplace cards) in light and dark themes, and a real search against the deployed registry"
|
||||
verification: []
|
||||
human_judgment: true
|
||||
rationale: "Styling and the live summercms.io registry answer are not covered by jsdom tests; needs a look in a browser on a built app"
|
||||
|
||||
duration: 28min
|
||||
completed: 2026-10-29
|
||||
status: complete
|
||||
---
|
||||
|
||||
# Phase 34 Plan 05: Admin Plugins screen Summary
|
||||
|
||||
**Settings → System → Plugins (backend.view_plugins) lists the installed plugins with versions and sources, marks updates computed server-side with plugin:update's rule, and searches the registry through cabana with copyable `summer plugin:install` / `summer plugin:update` commands, cached and degrading to a notice when the registry is down or disabled.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** about 28 min of execution (started 2026-10-29T17:54:17Z, completed 2026-10-29T18:21:42Z)
|
||||
- **Tasks:** 3
|
||||
- **Files modified:** 33 (4 created, plus the rebuilt dist)
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- `cabana.PermissionViewPlugins` (`backend.view_plugins`) on the System tab of the permission editor, granted to no role; superusers pass.
|
||||
- `GET /plugins` and `GET /plugins/marketplace` in the backend group, swag-annotated, in every route inventory (permission matrix, contract, token classes, Postgres conformance).
|
||||
- `cabana.SettingsEntry.Path`: the Plugins entry opens `/system/plugins`; the SPA's settings index, settings panel, rail highlight, breadcrumbs and page title handle it.
|
||||
- Registry catalog in cabana: lazy `kiosk.Client` from `plugins.registry_url`, 4 s per call on a detached context, at most 4 version lookups at once, TTL cache with failure caching, 404 treated as "not listed".
|
||||
- PluginsView with reka-ui Tabs: Installed (name or ID, description, version, source, update badge, command copy) and Marketplace (debounced search, category select, cards with Installed / Needs framework markers and the install command). No install button anywhere, all server text rendered as text.
|
||||
- `modules/boardwalk/dist` rebuilt in its own commit; `scripts/check-admin-dist.sh` passes.
|
||||
|
||||
## Task Commits
|
||||
|
||||
1. **Task 1: read-only Plugins screen with installed plugins (tracer)**: `c4b1ac4` (feat)
|
||||
2. **Task 2: plugin updates and marketplace search**: `7e8a193` (feat)
|
||||
3. **Task 3: rebuild the embedded admin**: `678eac4` (build)
|
||||
|
||||
**Plan metadata:** the docs commit containing this SUMMARY.
|
||||
|
||||
## Tracer feedback gate
|
||||
|
||||
Task 1's `<verify>` was re-run end to end after its commit (TestPluginsScreenSmoke/installed, the Phase 09 inventories, `check-admin-openapi.sh --check`, the PluginsView spec, typecheck, `go vet ./...`, `go test -short ./...`, and the full Docker cabana suite). All passed before Task 2 expanded the slice.
|
||||
|
||||
## Decisions Made
|
||||
|
||||
See `key-decisions` in the frontmatter.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 3 - Blocking] Two more route inventories**
|
||||
- **Found during:** Task 1
|
||||
- **Issue:** `TestTokenRouteGates` (token_routes_test.go) and `TestPhase10ConformanceInventory` / `TestPhase10OpenAPIConformance` (openapi_conformance_test.go) also list every admin route and failed on GET /plugins.
|
||||
- **Fix:** Both routes classified `allows_protect` (they check `cabana.Allows`, so a scoped token passes when its scope covers the code); conformance cases for both routes. The conformance admin gets `backend.view_plugins` in its own permissions and the conformance app sets `plugins.registry_url: ""`, so the Postgres test never calls a real registry.
|
||||
- **Commits:** c4b1ac4, 7e8a193
|
||||
|
||||
**2. [Rule 2 - Missing critical] Shell integration of a path-based settings entry**
|
||||
- **Found during:** Task 1
|
||||
- **Issue:** The settings panel, rail highlight, breadcrumbs and page title only knew singleton forms and controller links; on `/system/plugins` the admin would lose its Settings context.
|
||||
- **Fix:** `settingsEntryForPath` in useSettings.ts, used by AppShell.vue, PluginRail.vue; Breadcrumbs.vue and pageTitle.ts name the screen.
|
||||
- **Files modified:** admin/src/state/useSettings.ts, admin/src/components/shell/{AppShell,Breadcrumbs,PluginRail}.vue, admin/src/app/pageTitle.ts
|
||||
- **Commit:** c4b1ac4
|
||||
|
||||
**3. [Rule 2 - Missing critical] Command and icon hardening**
|
||||
- **Found during:** Task 2
|
||||
- **Issue:** Registry IDs are third-party text that ends up in a command an administrator pastes into a shell.
|
||||
- **Fix:** Marketplace entries (and update lookups) only for IDs matching `^[a-z][a-z0-9]*\.[a-z][a-z0-9]*$`; only absolute https icon URLs are passed through, rendered with `referrerpolicy="no-referrer"`.
|
||||
- **Commit:** 7e8a193
|
||||
|
||||
**4. [Rule 3 - Blocking] sync.Once in service breaks go vet**
|
||||
- **Found during:** Task 2
|
||||
- **Issue:** Existing tests copy `service` by value (copylocks).
|
||||
- **Fix:** `cabana.Activate` builds the catalog (`service.catalog`); without it a fresh uncached catalog is used per call.
|
||||
- **Commit:** 7e8a193
|
||||
|
||||
**5. [Plan adjustment] Names and files beyond the plan's lists**
|
||||
- Extra exported names: `cabana.MarketplaceResponse`, `cabana.MarketplaceMeta` (the marketplace answer with registry state, total and categories, following the `FieldTypesResponse` pattern), `cabana.AdminPluginsMarketplace` is as planned.
|
||||
- Extra files: `admin/src/api/types.ts` (type aliases), `admin/tests/fixtures/lang.json` (hand-kept Polish fixture), the shell files above, token_routes_test.go and openapi_conformance_test.go.
|
||||
- No `view_plugins_comment` permission-editor comment: the acceptance criterion expects exactly one `view_plugins` line per lang file, so the comment line used by the other two admin permissions was left out.
|
||||
|
||||
**6. [Process] TDD order**
|
||||
- Task 2's Go behavior subtests were written first and failed to compile on the missing `MarketplaceResponse`, `pluginsMarketplace` and `pluginCatalog` (RED), then the implementation made all eight pass. The SPA specs for Task 2 were written after the view and passed on the first run. One commit per task, as the Execution units table requires.
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 6 (2 Rule 2, 2 Rule 3, 1 plan adjustment, 1 process note). **Impact:** no contract change outside the plan; existing settings entries and plugins are untouched (`path` is omitted from their JSON).
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
- One `go test -short ./...` run failed in `internal/build` on a missing Go build-cache file (`open ~/.cache/go-build/...: no such file or directory`), most likely another session trimming the shared cache; the immediate rerun passed with no change.
|
||||
- `gofmt -l modules/cabana` lists pre-existing test files (account_tokens_test.go, field_trigger_smoke_test.go, token_postgres_smoke_test.go, token_routes_test.go, token_scopes_test.go); the new code is gofmt-clean. Left untouched (scope boundary).
|
||||
- `npm --prefix admin run test:browser` passes (2 files); it has no view coverage, so it does not exercise the new screen.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None. Grant `backend.view_plugins` to a role or administrator to give non-superusers the screen.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- 34-06 can add unit coverage on top of TestPluginsScreenSmoke and PluginsView.test.ts.
|
||||
- Open for human review (coverage D8): the screen's look in both themes and a live search against the deployed summercms.io registry.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- Files exist: modules/cabana/plugins.go, modules/cabana/plugins_smoke_test.go, admin/src/views/PluginsView.vue, admin/tests/views/PluginsView.test.ts.
|
||||
- Commits c4b1ac4, 7e8a193, 678eac4 are in history; `git rev-list --count 0418900..HEAD` = 3 before this docs commit; `git show --stat 678eac4` lists only modules/boardwalk/dist paths.
|
||||
- `go vet ./...`, `go test -short ./...`, `go test ./modules/cabana` (Docker), `go test ./modules/boardwalk`, `summer docs:build --check`, `go test ./cmd/summer -run 'TestDocsTree|TestCommandsDocumented'`, `npm --prefix admin run test` (1614 tests), `typecheck`, `test:browser`, `scripts/check-admin-openapi.sh --check` and `scripts/check-admin-dist.sh` pass.
|
||||
- Acceptance greps of Tasks 1-3 re-run: permission constant, both routes, swag router, `/system/plugins`, `entry.path`, two `view_plugins` lines, `kiosk.NewestCompatible`/`kiosk.BaseVersion`, `navigator.clipboard`, no `summercms.io` in admin/src.
|
||||
Reference in New Issue
Block a user