Repository navigation
Users cannot reach eleven dashboard features whose backend is already built #680
Description
The capability matrix merged in #678 (merge e8dcc75e, file openspec/parity/capabilities.json on development, read at 961fc8bc) found eleven capabilities whose backend is written and routed, but which no page in the app lets a user reach. Each row below is marked built.state: "building" or "built" with a reachedOn that says nothing reaches it, or reaches only half of it.
How the matrix traced this: from the route, to the store action that wraps it, to a component that calls the store action. A route-to-caller grep is not enough. For seven of the eleven, src/services/api.js or a store module wraps the route, so a grep for the URL or the wrapper finds a hit in src/ and would credit the capability as reachable. The other four (edit lock, personal hide layer, version rollback, translations) have no wrapper anywhere in src/ at all.
Evidence links point at 961fc8bc.
- Edit lock (row
build-edit-lock). RoutesPOST|PUT|DELETE|GET /api/dashboards/{uuid}/lockand/lock/force-release(appinfo/routes.php:159-174). Service:lib/Service/DashboardLockService.php:116(acquireLock). No wrapper insrc/services/api.js, no store action.reachedOn: "nothing: /api/dashboards/{uuid}/lock has no caller anywhere in src/". - Personal hide layer (row
build-personal-hide). RoutesGET|PUT|DELETE /api/dashboards/{dashboardId}/personal-layer(appinfo/routes.php:255-262). Service:lib/Service/PersonalLayerService.php:15. No wrapper, no store action.reachedOn: "nothing: /api/dashboards/{dashboardId}/personal-layer has no caller in src/". - Version rollback (row
build-rollback). RoutesGET|POST /api/dashboards/{uuid}/versions,GET .../versions/{versionNumber},POST .../versions/{versionNumber}/restore(appinfo/routes.php:288-297). Service:lib/Service/DashboardVersionService.php:433(restoreVersion). No wrapper, no store action.reachedOn: "nothing: /api/dashboards/{uuid}/versions and its restore route have no caller in src/". - Dashboard tree (row
dash-tree). RouteGET /api/dashboards/tree(appinfo/routes.php:127), wrapped bygetDashboardTree()insrc/services/api.js:386, called by store actionloadDashboardTree()insrc/stores/dashboard.js:1106. Service:lib/Service/DashboardTreeService.php:105.reachedOn: "nothing: the store action loadDashboardTree has no caller outside src/stores/". - Dashboard translations (row
dash-languages). Routes under/api/dashboards/{uuid}/translationsandGET /api/dashboards/{uuid}/resolved(appinfo/routes.php:79-101). Service:lib/Service/DashboardTranslationService.php:93. No wrapper, no store action.reachedOn: "nothing: /api/dashboards/{uuid}/translations and /resolved have no caller in src/". - Metadata fields (row
dash-metadata). Routes/api/admin/metadata-fieldsandGET|PUT /api/dashboards/{uuid}/metadata(appinfo/routes.php:486-503), wrapped insrc/services/api.js:873-899, store actionsfetchMetadataFields()andupdateDashboardMetadata()insrc/stores/dashboard.js:1310and:1384. Service:lib/Service/MetadataService.php:71.reachedOn: "nothing: the store actions fetchMetadataFields and updateDashboardMetadata have no component caller". - Tile-click report (row
tile-clicks). Clicks are recorded from the Workspace page (src/components/TileWidget.vue:94), but the report is never shown:src/services/api.js:305getAnalyticsTopTiles()andgetTileAnalyticsCsvExport()(src/services/api.js:378) have no caller outsideapi.js. Routes/api/admin/analytics/tiles/topand/tiles/export(appinfo/routes.php:523-524).reachedOn: "clicks are recorded from the Workspace page; nothing shows them: getAnalyticsTopTiles and the tile CSV export have no caller in src/". - Kiosk playlists (row
s-kiosk). Routes/api/kiosk/playlistsand the publicGET /kiosk/{token}(appinfo/routes.php:206-215). Service:lib/Service/KioskService.php:263(renderPlaylist, returns an array the controller sends as JSON). Store:src/stores/kioskPlaylists.js:19useKioskPlaylistStore, imported by nothing.reachedOn: "nothing: /kiosk/{token} returns JSON that no page renders, and useKioskPlaylistStore has no caller, so no screen creates a playlist". Already tracked in detail in dashboard-kiosk-mode: 23 spec scenarios are unsatisfiable — the kiosk frontend was removed in 1fd075c5, backend still routed #93; listed here so the eleven stay together. - Publish and schedule (row
s-schedule). RoutesPOST /api/dashboards/{uuid}/publish,/unpublish,/schedule(appinfo/routes.php:72-76), wrapped insrc/services/api.js:220-249, store actionspublishDashboard()andscheduleDashboard()insrc/stores/dashboard.js:518and:558. Service:lib/Service/DashboardService.php:2069(schedule).reachedOn: "nothing: the store actions publishDashboard and scheduleDashboard have no component caller". - Acknowledgement authoring (row
e-ack-ask). The read-and-confirm prompt renders on the Workspace page (src/components/WidgetWrapper.vue:155), and the backend accepts the flag (lib/Service/PlacementUpdater.php:139), but no form insrc/sendsrequiresAcknowledgement. Everysrc/reference to it reads the flag; none writes it.reachedOn: "the prompt renders on the Workspace page, but no form sets requiresAcknowledgement; only PUT /api/widgets/{placementId} does". - Reactions (row
e-react). Routes under/api/dashboards/{uuid}/reactions(appinfo/routes.php:230-247), wrapped bygetDashboardReactions()insrc/services/api.js:1129, store actionsaddReaction()andfetchReactionsSummary()insrc/stores/dashboard.js:1256and:1229. Service:lib/Service/ReactionService.php:91.reachedOn: "nothing: the store actions addReaction and fetchReactionsSummary have no component caller".
Why it matters: each of these is maintained, tested and routed code that no user can use, and a tool that credits a capability because its URL appears somewhere in src/ will keep counting all eleven as shipped.
Source: #678, rows build-edit-lock, build-personal-hide, build-rollback, dash-tree, dash-languages, dash-metadata, tile-clicks, s-kiosk, s-schedule, e-ack-ask, e-react.
Activity
github-actions commentedon Sep 25, 2026
Thank you for opening this issue! It has been assigned to @rubenvdlinde for review.
What happens next:
Triage labels:
triage:accept-feature— accepted as a new featuretriage:accept-bugfix— accepted as a bug fixtriage:needs-info— more information neededtriage:wontfix— will not be addressedtriage:duplicate— duplicate of another issue