/ 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.*