Skip to content

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 in solutions/ontological/lib/services/dashboard/server.ts (about L1869). It calls runRoadmapProgress from lib/model/entities/roadmap/ops/progress.ts and returns { roadmaps: RoadmapProgress[] }. Each RoadmapProgress is { id, path, sections }, each section is { section, milestones }, and each milestone is { id, title, state, state_group, task_total, task_state_counts }. id is validated by SAFE_ROADMAP_ID_RE and an unknown id is a 404.
  • Sections come from top-level ## headings that carry milestone wikilinks, found by scanTopLevelMilestoneLinks in lib/model/entities/roadmap/sections.ts. The corpus has three roadmaps (docs/planning/roadmaps/RM-0RYV.md, RM-DO9Z.md, RM-E2L0.md). RM-E2L0.md has a ## Pre-release section and ## v0.4.0 to ## v0.8.0.
  • Unresolved milestone links and non-task entries in a milestone’s tasks are omitted from the response. roadmap check reports those as findings, so the page does not.
  • State group is the prefix of state before /, or unknown. So task_state_counts keys are groups such as planning, open, in-progress, closed.
  • The typed client already has it: getRoadmapProgress(id?, project?) in packages/ts/dashboard-client/src/index.ts, with generated types in types.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.vue with its test and story. It shows each section’s milestones with a segmented bar over task_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 become milestoneBar in app/utils/roadmapProgress.ts, so the maths is written once more only because the SPA keeps it inside a .vue file with no export; copy it into the pure helper and test it there. Not reused: the SPA template, its <style> block and its --muted and --line variables. 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 in desktop/src-nuxt/app/plugins/register.ts (about L151).

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.

  1. Add app/utils/roadmapProgress.ts with pure functions: milestoneBar(m: MilestoneProgress): { total, done, active, rest, donePct, activePct } and sectionRollup(section) summing the milestones. Zero tasks gives zeros, never NaN.
  2. Add a useRoadmapProgress(project) composable in the style of useEntityDetail (composables/useEntities.ts): project from the route or the focus, no ambient project, NO_PROJECT_MESSAGE when none.
  3. Add app/pages/model/roadmap.vue and a RoadmapProgressBar.vue component. Use only --d-* tokens for the bar segments.
  4. Register the nav entry in app/plugins/register.ts.
  5. Add a story and a fixture shaped like the real response.
AreaNote
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.tsNav entry
  • AC-1: /model/roadmap lists each roadmap’s sections in response order, with each section’s milestones, read from getRoadmapProgress and 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: milestoneBar is correct for: no tasks, all closed, none closed, a mix with in-progress, and a task_state_counts that lacks closed; percentages never exceed 100.
  • AC-4: sectionRollup equals 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.
  • CI is the typecheck. vue-tsc is never run locally, and neither is nuxi 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/roadmap and compare one milestone’s counts with sdlc roadmap progress. Every /api/* request over HTTP needs the platform token; give the browser the token in Settings first.
  • Any change to the progress API or the roadmap schema.
  • Editing roadmaps or milestones from the page.
  • The roadmap findings that roadmap check reports.
  • A gantt or date view; milestones carry no required dates.
  • none

← Back to Tasks