T-HV1N-roadmap-page
State: planning/draft · Impact: medium · Complexity: medium
SDF has no page for the roadmap. Add one that shows each release as a section, the milestones in it, and a progress bar per milestone built from its tasks’ states. It is a read-only view over the API that already exists.
- The read API exists, so no new API task is needed.
GET /api/roadmap/progress(optional?id=, plus the usual?project=) is insolutions/ontological/lib/services/dashboard/server.ts(about L1869). It callsrunRoadmapProgressfromlib/model/entities/roadmap/ops/progress.tsand returns{ roadmaps: RoadmapProgress[] }. EachRoadmapProgressis{ id, path, sections }, each section is{ section, milestones }, and each milestone is{ id, title, state, state_group, task_total, task_state_counts }.idis validated bySAFE_ROADMAP_ID_REand an unknown id is a 404. - Sections come from top-level
##headings that carry milestone wikilinks, found byscanTopLevelMilestoneLinksinlib/model/entities/roadmap/sections.ts. The corpus has three roadmaps (docs/planning/roadmaps/RM-0RYV.md,RM-DO9Z.md,RM-E2L0.md).RM-E2L0.mdhas a## Pre-releasesection and## v0.4.0to## v0.8.0. - Unresolved milestone links and non-task entries in a milestone’s
tasksare omitted from the response.roadmap checkreports those as findings, so the page does not. - State group is the prefix of
statebefore/, orunknown. Sotask_state_countskeys are groups such asplanning,open,in-progress,closed. - The typed client already has it:
getRoadmapProgress(id?, project?)inpackages/ts/dashboard-client/src/index.ts, with generated types intypes.ts. - No page in the desktop app uses it. The precedent is the legacy dashboard SPA, whose source is
packages/ts/dashboard-spa/src/:composables/useRoadmapProgress.ts(one fetch, no id),views/RoadmapProgressView.vuewith its test and story. It shows each section’s milestones with a segmented bar overtask_state_counts(group order closed, in-progress, open, planning, unknown) and a percentage tally. - Reuse: the progress maths. The SPA’s
pct(zero total gives 0) and its group order becomemilestoneBarinapp/utils/roadmapProgress.ts, so the maths is written once more only because the SPA keeps it inside a.vuefile with no export; copy it into the pure helper and test it there. Not reused: the SPA template, its<style>block and its--mutedand--linevariables. The desktop app is a different framework layer with the--d-*token set, and its rows link to milestone pages. - Pages live in
solutions/ontological/desktop/src-nuxt/app/pages/model/. The Model nav entries, including “Milestones” to/model/milestones, are registered indesktop/src-nuxt/app/plugins/register.ts(about L151).
Proposed
Section titled “Proposed”A page at /model/roadmap (nav entry beside Milestones). For each roadmap, its sections in
document order; for each section, its milestones. A milestone row shows id, title, state, a
progress bar and “closed of total” tasks, and links to /model/milestones/<id> with the project
carried. A milestone with no tasks shows “no tasks listed” and no bar. When there is more than one
roadmap, each is a collapsible block headed by its id; ?id= is not needed.
Progress is closed tasks over total tasks, from task_state_counts.closed. In-progress tasks are
shown as a second segment so the bar separates done, in progress and the rest.
Approach
Section titled “Approach”- Add
app/utils/roadmapProgress.tswith pure functions:milestoneBar(m: MilestoneProgress): { total, done, active, rest, donePct, activePct }andsectionRollup(section)summing the milestones. Zero tasks gives zeros, never NaN. - Add a
useRoadmapProgress(project)composable in the style ofuseEntityDetail(composables/useEntities.ts): project from the route or the focus, no ambient project,NO_PROJECT_MESSAGEwhen none. - Add
app/pages/model/roadmap.vueand aRoadmapProgressBar.vuecomponent. Use only--d-*tokens for the bar segments. - Register the nav entry in
app/plugins/register.ts. - Add a story and a fixture shaped like the real response.
| Area | Note |
|---|---|
solutions/ontological/desktop/src-nuxt/app/pages/model/ | New roadmap.vue |
solutions/ontological/desktop/src-nuxt/app/utils/ | New pure progress helper and its test |
solutions/ontological/desktop/src-nuxt/app/composables/ | New read composable |
solutions/ontological/desktop/src-nuxt/app/components/ | Progress bar component and story |
solutions/ontological/desktop/src-nuxt/app/plugins/register.ts | Nav entry |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
/model/roadmaplists each roadmap’s sections in response order, with each section’s milestones, read fromgetRoadmapProgressand nothing else. - AC-2: Each milestone row shows its progress bar and “closed of total”, and links to
/model/milestones/<id>carrying?project=when the page has one. - AC-3:
milestoneBaris correct for: no tasks, all closed, none closed, a mix with in-progress, and atask_state_countsthat lacksclosed; percentages never exceed 100. - AC-4:
sectionRollupequals the sum of its milestones’ counts, tested. - AC-5: With no project the page shows the no-project message and sends no request.
- AC-6: The bar and layout use only
--d-*design tokens. - AC-7: The nav shows a Roadmap entry that routes to the page.
Verification
Section titled “Verification”- CI is the typecheck.
vue-tscis never run locally, and neither isnuxi typecheck. cd solutions/ontological/desktop/src-nuxt && bun run test(vitest)cd solutions/ontological/desktop/src-nuxt && bun run generate- Run against
sdf-serve, the headless server from open PR #2546, open/model/roadmapand compare one milestone’s counts withsdlc roadmap progress. Every/api/*request over HTTP needs the platform token; give the browser the token in Settings first.
Out of scope
Section titled “Out of scope”- Any change to the progress API or the roadmap schema.
- Editing roadmaps or milestones from the page.
- The roadmap findings that
roadmap checkreports. - A gantt or date view; milestones carry no required dates.
Dependencies
Section titled “Dependencies”- none