/ KB_Dashboard_PRD_v1.md
KB_Dashboard_PRD_v1.md
1 # KB-Dashboard — Product Requirements Document v1 2 3 > **Status:** living. Updated as phases ship and requirements clarify. 4 > **Date:** 2026-04-25. 5 > **Author:** Xavier Brinon. 6 > **Scope:** project-level. Single source of truth for requirements that all 7 > phase plans should be measurable against. 8 9 --- 10 11 ## 1. Vision 12 13 KB-Dashboard is a personal new-tab dashboard surfacing project status from 14 `~/Projects/*` — LOC, commit velocity, `rad` issue counts, last-activity dates. 15 Offline-first locally; a filtered public build deploys later to 16 `dashboard.brinon.eu` as the start of a personal online presence under 17 `brinon.eu`. Personal-scale only — not multi-user, not a SaaS. The goal is to 18 replace the default browser new-tab page with a glance-able portfolio status 19 that is *honest* (data-driven, no editorial inflation) and to ship a public 20 artifact that doubles as the start of a personal online identity. 21 22 The dashboard exists because manual portfolio updates rot — the data is already 23 in `git`, `rad`, and the filesystem; KB-Dashboard surfaces it. 24 25 --- 26 27 ## 2. Users & jobs-to-be-done 28 29 ### 2.1 Primary persona — Xavier (sole maintainer, daily user) 30 31 Single human. Owns the data, the dashboard, and the deployment. Daily-use 32 audience is exactly one person on one dev machine. 33 34 **Jobs:** 35 36 | # | When… | I want… | So that… | 37 |----|----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------| 38 | J1 | I open a new browser tab | to see the current state of every project I'm working on | I can decide what to work on next without context-switching to multiple tools | 39 | J2 | A project goes stale | to be reminded passively (a desaturated card, a clock glyph) | I can decide whether to revive it, archive it, or accept the staleness | 40 | J3 | I commit to a project | the dashboard to reflect that within ~30 minutes (next scheduled scan) without manual action | my snapshot is always trustworthy | 41 | J4 | I want to record context that isn't in git ("blocked because X", "waiting on Y") | a place to write notes that survive regenerations | I don't lose the why behind a status | 42 | J5 | I want to publish a curated subset of my work | to opt in projects field-by-field with confidence nothing private leaks | I get a portfolio artifact without a confidentiality breach | 43 44 ### 2.2 Secondary persona — portfolio visitor 45 46 Whoever lands on `dashboard.brinon.eu` via CV link, blog post, social, or 47 search. Read-only relationship to the dashboard. No interactive affordances 48 beyond navigation. 49 50 **Jobs:** 51 52 | # | When… | I want… | So that… | 53 |----|------------------------------------------|-------------------------------------------------------------------------------|-------------------------------------------------------------------------| 54 | V1 | I land on the dashboard from a CV / link | to see at-a-glance evidence of recent technical activity | I can form an opinion about Xavier's current work without reading prose | 55 | V2 | I click into a project | enough detail to evaluate it (tech stack, activity recency, kind of artifact) | I can decide whether to investigate further or move on | 56 | V3 | I'm comparing developer portfolios | something honest and dated, not curated marketing | I can trust what I'm seeing | 57 58 The visitor persona explicitly does **not** include: comment authoring, account 59 creation, write-side actions of any kind, or analytics-driven feedback loops. 60 61 --- 62 63 ## 3. Success metrics 64 65 Quantitative targets. Forward-looking; reviewed at the end of each phase. 66 67 ### 3.1 Performance 68 69 | Metric | Target | How measured | 70 |------------------------------------------------------------|----------------------------------------|------------------------------------------------------------| 71 | Dashboard First Contentful Paint (local) | < 500ms | Browser DevTools, cold load | 72 | Dashboard Time to Interactive (local) | < 1s | Browser DevTools | 73 | Public build initial page weight | < 500 KB gzipped (excluding web fonts) | `ls -lh dist/public/index.html.gz` + asset audit | 74 | Public build CSS budget | < 50 KB gzipped | Bundle audit | 75 | Public build JS required for first paint | 0 bytes | SSG output is HTML+CSS only; JS is progressive enhancement | 76 | Scanner full-pass duration (50 projects) | < 60s sequential | `time bun run scan` | 77 | Deploy ritual end-to-end (`bun run deploy` → Dokploy live) | < 2 min | Wall clock | 78 79 ### 3.2 Adoption — does it actually get used 80 81 | Metric | Target | How measured | 82 |-----------------------------------------------|-------------------------------------|--------------------------------------------------| 83 | New-tab opens hitting the dashboard | ≥ 5/day at steady state (post-MVP) | Browser default-page setting + self-observation | 84 | Proportion of project statuses I keep current | ≥ 90% accurate at any random sample | Random spot-checks against my real working state | 85 | Days a project status stays incorrect | ≤ 3 days, ≤ 1×/month | Self-observation | 86 | Public build refresh cadence at steady state | ≥ 1×/week | `git log` of the deploy registry | 87 88 ### 3.3 Trustworthiness 89 90 | Metric | Target | How measured | 91 |---------------------------------------------|-----------------------------------------------------------------------------------|--------------------------------------------------| 92 | Private strings leaked into public build | 0, ever | `bun run guard:public` + post-deploy spot-checks | 93 | Active-project snapshot freshness | 100% of `active` projects have a snapshot < 24h old (when scanner is functioning) | Manual query against `project_snapshots` | 94 | Source SHA discoverability on public deploy | 100% of public pages embed the build SHA in `<meta>` and footer | View source spot-check | 95 96 ### 3.4 Reliability 97 98 | Metric | Target | How measured | 99 |-------------------------------------------------|--------------------------------------------------------------|---------------------------------------------| 100 | Scanner per-project failure rate | < 5% across all projects in `$PROJECTS_ROOT` | `scan_errors` row count over scan-run count | 101 | Migrations replay cleanly from empty `pb_data/` | 100% — every commit's `pb_migrations/` reproduces the schema | Manual verification each phase close | 102 | Public deploy with visibly-broken styling | 0 shipped to production | Visual spot-check post-deploy | 103 104 --- 105 106 ## 4. Non-functional requirements 107 108 ### 4.1 Privacy 109 110 - **MUST** bind PocketBase to `127.0.0.1` exclusively. Never network-exposed. 111 - **MUST** redact via allowlist-by-field. Default state of any field is private; 112 visibility is opt-in via `public-shape.ts`. 113 - **MUST** fail the deploy on any private-string match in `dist/public/` (grep 114 guard). 115 - **MUST NOT** include telemetry, analytics, or third-party scripts in either 116 the local or public build. 117 - **MUST NOT** make external network calls from the public deploy at runtime. 118 The public build is purely static HTML + CSS. 119 - **MUST NOT** commit `pb_data/` or any file under it to git. 120 121 ### 4.2 Performance budgets 122 123 - Dashboard SSR has zero network round-trips beyond the local PocketBase REST 124 read. 125 - Public build pages are SSG: rendered HTML with no JS required for first paint. 126 Any JS shipped is progressive enhancement. 127 - CSS is < 50 KB gzipped. 128 - Web fonts load asynchronously (FOUT acceptable; FOIT is not). 129 - No image assets are loaded eagerly above the fold beyond ≤ 100 KB total. 130 131 ### 4.3 Reliability guarantees 132 133 - Local PocketBase data survives every reasonable failure mode (laptop reboot, 134 app crash, accidental Ctrl-C). 135 - Schema migrations in `pb_migrations/` are the source of truth — deleting 136 `pb_data/` and re-running PocketBase reproduces the schema identically. 137 - Scanner failures are isolated per-project (one bad git repo cannot poison 138 the run). 139 - Source SHA is always discoverable from the deployed page (footer + `<meta>` 140 tag). 141 142 ### 4.4 Deployability 143 144 - Single command (`bun run deploy`) takes the system from "code committed + scan 145 run + grep guard passed" to "live on `dashboard.brinon.eu`". 146 - Local development requires no internet connection beyond initial `bun 147 install` + first PocketBase binary fetch. 148 - Zero manual configuration steps after `bun install` + `bun run pb` first-run 149 admin setup. 150 - Manual deploys only. No auto-deploys from scheduled jobs, commit hooks, or 151 scanner runs. 152 153 ### 4.5 Accessibility 154 155 - Public build conforms to WCAG 2.1 AA contrast ratios at minimum. 156 - All interactive elements (filter buttons, project links) are keyboard- 157 navigable. 158 - Semantic HTML throughout: real `<article>`, `<section>`, `<time>` elements 159 rather than `<div>` soup. 160 - Dark-mode default; reduced-motion preference respected (no parallax / 161 auto-playing transitions). 162 163 ### 4.6 Maintainability 164 165 - Every long-lived authoring convention (commit format, schema policy, 166 artifact-emission rules) is codified in a referenceable doc before its third 167 use, per [`templates/plan_convention.md`](templates/plan_convention.md). 168 - The data model is structurally append-only where possible 169 (`project_snapshots`) — history is preserved by structure, not by retention 170 policy. 171 172 --- 173 174 ## 5. Phase roadmap 175 176 **This roadmap is directional, not committed.** Each phase's actual scope is 177 determined by its own plan ([`plan_phase_N.org`](plan_phase_1.org)) with 178 grilling and discussion before lock-in. 179 180 ### 5.1 Phase 1 — Tracer-bullet vertical slice 181 182 **Status:** planned, not executed. See [`plan_phase_1.org`](plan_phase_1.org). 183 184 Scaffold + schema + scanner v1 (git only) + dashboard renders one card. 185 Manual project insertion. No auto-discovery, no public build, no deploy. 186 187 ### 5.2 Phase 2 — Useful local dashboard (likely next) 188 189 Scanner v2 (`tokei` for LOC, `rad` for issue counts). Multi-project — either 190 auto-discovery from `$PROJECTS_ROOT` or a batch-import script. Manual refresh 191 button in the UI. launchd timer setup. First visual-polish pass applying the 192 [`grilling-session.org` §Q9b](grilling-session.org) tokens. 193 194 Open question for the Phase 2 plan: `tokei` first or `rad` first? The PRD's 195 position: `rad` first, because issue counts are higher portfolio-value and 196 Xavier's project workflow already uses `rad`. `tokei` is visual sugar. 197 198 ### 5.3 Phase 3 — Public build 199 200 Public mapper (`public-shape.ts`) + snapshot test. Grep guard (`bun run 201 guard:public`). Dockerfile + first deploy to `dashboard.brinon.eu`. Public list 202 filter enforcement. Status filter (stuck/archived hidden). 203 204 This phase is a strong candidate to be KB-Dashboard's first **COMPLEX-tier** 205 task per [`CLAUDE.md`](CLAUDE.md) §Project Definition of Done — the Risk Surface 206 dimension goes from "internal" to "user-facing" the moment the deploy is live, 207 and a build-time leak is a visible breach. 208 209 ### 5.4 Phase 4+ (uncertain order) 210 211 - **Time-tracker integration** — `timewarrior` adapter; defer until the tracker 212 itself is part of Xavier's daily workflow. 213 - **Annotations write-back** — round-trippable markdown notes; needs the clean 214 separation between manual and derived fields (already structural via the 215 two-collection model). 216 - **Sparklines / velocity charts** — inline SVG, monochrome; requires 217 multi-snapshot history (already captured from Phase 1 onward). 218 - **Auth on PocketBase** — only if a feature needs to write from outside 219 `127.0.0.1` (e.g., phone CRUD). Not before. 220 - **Realtime UI updates** — PB subscriptions; live-update during scan runs. 221 - **Project screenshots / OG images** — PB file storage for per-project imagery 222 on the public build. 223 224 ### 5.5 Eventual 225 226 - **Staging environment** at `dashboard-staging.brinon.eu` — when visual changes 227 are nontrivial enough to want a preview. 228 - **Carry-forward Open Items** from Pi-YackShaving (`O2`, `O3`, `O4`) fire 229 naturally as KB-Dashboard's phases hit the relevant capability classes. 230 231 --- 232 233 ## 6. Permanent out-of-scope 234 235 These are committed exclusions. Reopening them requires a new PRD version. 236 237 | What | Why out | 238 |-------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 239 | Multi-user / login other than the local PB superuser | KB-Dashboard is personal-scale. A login system is an attack surface, an auth-flow design problem, and a perpetual maintenance cost — none of which earn their keep for one user. | 240 | Multi-tenant SaaS / hosting for other people's projects | Same reasoning, plus the architectural commitment to local-only source of truth makes this a fundamental rewrite. | 241 | Hosted PocketBase / network-exposed source of truth | The privacy posture (default-private, allowlist-by-field) depends on the DB being unreachable from the network. | 242 | Mobile-first / native apps | Desktop-primary; mobile-acceptable. No native apps, no React Native, no PWA install flow. | 243 | Real-time collaboration | There is no second user. | 244 | Comments / public-side interaction on `dashboard.brinon.eu` | The public build is read-only forever. Comments require auth, moderation, anti-spam, and a write path on the VPS — all violate constraints elsewhere. | 245 | Editorial blog content on the dashboard | Blog/CV pages live elsewhere on `brinon.eu`. The dashboard is data, not prose. | 246 | Generic project tracker for arbitrary use cases | The data model is shaped by Xavier's actual workflow (Radicle, git, the project folder convention). Not designed to onboard other people. | 247 | AI-generated content on the public build | Descriptions are hand-authored. No auto-summaries, no LLM-written blurbs. | 248 | Analytics / telemetry on the public build | Privacy is a feature; visitor surveillance is not. | 249 | Funded / monetised features | This is a personal portfolio artifact, not a product. | 250 251 --- 252 253 ## 7. Cross-references 254 255 - [`README.md`](README.md) — entry-point orientation 256 - [`kb-dashboard.org`](kb-dashboard.org) — project governance (what / who / success — qualitative) 257 - [`grilling-session.org`](grilling-session.org) — architectural decisions (Q1–Q9) 258 - [`ideas.org`](ideas.org) — original brainstorm 259 - [`plan_phase_1.org`](plan_phase_1.org) — current phase plan 260 - [`UBIQUITOUS_LANGUAGE.md`](UBIQUITOUS_LANGUAGE.md) — canonical terminology 261 - [`CLAUDE.md`](CLAUDE.md) — framework master rules 262 - [`templates/plan_convention.md`](templates/plan_convention.md) — phase plan authoring convention 263 - [`skills/orchestrator.md`](skills/orchestrator.md) — complexity scoring rubric 264 265 --- 266 267 ## 8. Versioning policy 268 269 This document is **`v1`**. Successor versions follow these rules: 270 271 - A new PRD version (`KB_Dashboard_PRD_v2.md`) ships when one of: 272 1. A permanent out-of-scope item from §6 is reopened. 273 2. A success metric in §3 is materially revised (target shift > 25%, or metric 274 removed/added). 275 3. The user persona model in §2 changes (e.g., a new persona is introduced). 276 - A new version is a *new file*, not an in-place edit. The prior version is 277 preserved verbatim for historical traceability, matching Pi-YackShaving's 278 `YackShavingSkill_PRD_v1.md` / `_v2.md` / `_v3.md` pattern. 279 - Phase plans cite the PRD version they target. A phase started under v1 remains 280 accountable to v1 even if v2 ships mid-phase. 281 282 Minor in-place edits (typo fixes, metric measurement-method clarifications, 283 additional cross-reference links) are made directly to the current version 284 without a new version number. 285 286 --- 287 288 ## 9. Appendix — open requirement questions 289 290 Surfaced for future PRD-version review. Not yet bound. 291 292 - **A1 — Quantitative "I check it 5×/day" target:** is self-observation 293 sufficient, or should the dashboard log its own load times to a local file for 294 honest measurement? (Logging itself is mild surveillance; trade-off 295 unresolved.) 296 - **A2 — Public build accessibility floor:** is WCAG 2.1 AA the right target, or 297 should it be AAA where contrast is concerned? (AAA on dark mode is hard; defer 298 until visual identity is stable.) 299 - **A3 — Time-tracker honesty trade-off:** if `timewarrior` data shows zero 300 hours on a public project, does that get rounded up, omitted, or shown 301 honestly? Honesty bias suggests "shown" but visitor-job V3 ("something honest 302 and dated") needs a concrete rule. 303 - **A4 — Update cadence promise:** should the public build advertise its 304 freshness ("updated daily" vs nothing)? Stating a cadence creates an 305 obligation; not stating one means visitors can't gauge data age beyond the 306 per-card timestamps. Resolution: per-card `last_commit_at` is sufficient; no 307 global "updated daily" promise. 308 309 --- 310 311 *This PRD is the authoritative requirements source for KB-Dashboard. When in 312 doubt about scope or priority, defer to it before deferring to phase plans.*