/ ideas.org
ideas.org
1 #+title: KB-Dashboard — Ideas & Initial Scope 2 #+author: Xavier Brinon 3 #+date: [2026-04-24 Fri] 4 #+startup: indent 5 #+options: toc:3 num:t ^:{} 6 7 * Concept 8 9 A personal web dashboard listing all the projects I'm working on — their current 10 status, stats, progress, delivery speed, lines of code, and so on. Intended as 11 the default page when I open a new tab in Firefox or Chrome. 12 13 *Offline-first*: builds and runs locally, displays via =file://= URL or a tiny 14 localhost server. Later, a filtered public variant deploys online at 15 =dashboard.brinon.eu= as the beginning of a personal online presence. 16 17 * Use case 18 19 - *Private new-tab page*: every new browser tab opens to the dashboard, giving 20 me an at-a-glance view of what I'm working on and where each project stands. 21 - *Public portfolio snapshot* (later): a filtered, allowlisted version serves at 22 a =brinon.eu=-related URL alongside eventual blog / CV pages. 23 - Personal-scale only. Not multi-user, not a SaaS, not shared. 24 25 * Data sources 26 27 Minimum first-cut: 28 29 - *Subdirectories of the parent folder* (=../= from this repo's parent) — each 30 folder that looks like a project gets surfaced. 31 - *Git history* of each project (commits, diff stats, LOC, velocity derived from 32 commit frequency). 33 - *=rad= issue state* per project (open / solved / closed counts; maybe 34 breakdown by label). 35 - *Time tracker* (tool TBD — candidates include =timewarrior=, Toggl, a CSV I 36 maintain, or something else). 37 38 Potentially extensible: 39 40 - GitHub / GitLab remote metadata (stars, issues, PRs) for projects with 41 remotes. 42 - CI / CD status. 43 - Linear / Jira if I end up using either. 44 - Published artifacts (HTML / PDF / images) grouped by project. 45 46 * Features 47 48 ** MVP — read-only 49 50 - Discover projects in =../= (something marks a folder as "a project" — =.git= 51 presence? A manifest file? An allowlist config?). 52 - Compute stats per project (LOC, commit velocity, last-commit date, open issue 53 count). 54 - Render a dashboard grid / list with each project card showing its key numbers. 55 - Refresh mechanism (cron, timer, or manual "regenerate" button). 56 57 ** Polish 58 59 - Typography and visual hierarchy — the dashboard has to be pleasant to look at 60 dozens of times a day. 61 - Project status categories / colour coding (active / idle / done / stuck). 62 - Responsive layout (desktop primary; tablet / phone as secondary). 63 - Dark mode default — it's a new-tab page, bright is unfriendly. 64 65 ** Write-back (later, optional) 66 67 - Per-project annotation: free-form notes, "why is this stuck?", next-action 68 prose. 69 - Annotations live in markdown files the dashboard can round-trip: 70 auto-refreshed data cells (dates, LOC, counts) regenerate each run; 71 user-authored text cells (my notes) are preserved verbatim across 72 regenerations. 73 - Requires clean separation between generated and user-authored content. 74 75 ** Public variant 76 77 - A filtered build that only exposes projects explicitly marked public. 78 - *Default-private*: projects must opt in (allowlist), not opt out (blocklist). 79 - Per-project opt-in mechanism (candidate: a =.dashboard.public.yaml= marker 80 file in each project, or a central allowlist config). 81 - Redaction of sensitive columns even within public projects (e.g., LOC OK; 82 client name / hourly rate not). 83 84 * Deployment & hosting 85 86 ** Domain 87 88 - Primary: =brinon.eu= (candidate). 89 - *Subdomain architecture*: each subdomain is a separate app / repo / deploy. 90 Subpaths are workflows within an app. 91 - Dashboard at =dashboard.brinon.eu=; apex =brinon.eu= reserved for a future 92 minimal landing page. Rationale: keeps apex decoupled from dashboard identity, 93 so either can evolve without the other breaking. 94 95 ** Infrastructure 96 97 - Self-hosted VPS already running *Dokploy* (open-source Heroku-alternative; 98 Docker + Traefik + automatic Let's Encrypt + built-in CI/CD). 99 - Dokploy handles SSL, routing, cert rotation, auto-deploy on git push. 100 101 ** Deployment pattern 102 103 - *Generator runs locally* — on my dev machine where =../= project folders 104 actually exist. 105 - Generator outputs two builds: =dist/private/= (full) and =dist/public/= 106 (filtered). 107 - =dist/public/= is committed and pushed to the repo that Dokploy watches. 108 - Dokploy builds a tiny nginx-serves-dist container and deploys. 109 - *The VPS never sees private data* — it's a dumb CDN for pre-built static HTML. 110 111 ** Refresh cadence 112 113 - Local machine runs a scheduled regen (cron / launchd / systemd-user-timer) — 114 say every 30 minutes or on git-commit hook — then pushes committed 115 =dist/public/= changes. 116 - Manual "refresh now" option for on-demand regen. 117 118 * Architecture notes 119 120 ** Local-first build 121 122 All data access happens on my dev machine. The VPS is a static file server. This 123 decouples "where data lives" from "where it's served" and keeps private data out 124 of any network-exposed environment. 125 126 ** Single-source-of-truth generator 127 128 One Node / Bun / Python / Go binary (stack TBD) reads all data sources, produces 129 an intermediate model, and renders to static HTML with a flag gating 130 public-vs-private scope. 131 132 ** No server-side state 133 134 Static HTML only. No database, no runtime data fetching, no API calls from the 135 browser. Simplifies security, caching, and failure modes. All "freshness" comes 136 from the next regen. 137 138 * Privacy & safety 139 140 Publishing something tied to my name (near a future CV / resume) raises stakes 141 meaningfully: 142 143 - *Data leakage risk*: any private repo or client project accidentally surfaced 144 is a confidentiality breach. 145 - *Correctness risk*: wrong numbers on a resume-adjacent page misrepresent me 146 professionally. 147 - *Reputation coupling*: whatever the dashboard says about velocity / progress 148 becomes part of my online brand. 149 150 Mitigations: 151 152 - *Default-private*: projects must explicitly opt in to the =--public= build. 153 - *Diff-visible publish*: the committed =dist/public/= directory is readable — a 154 pre-publish audit can grep it for project names, file paths, client 155 identifiers, or any string that shouldn't be there. 156 - *Staging environment* (later): a staging Dokploy app at 157 =dashboard-staging.brinon.eu= that I can preview before promoting to 158 production. 159 160 * Open questions 161 162 - *Stack choice*: Bun + TypeScript? Python? Go? Plain HTML with a build-time 163 generator? Each has tradeoffs — TS gives shared types between generator and 164 (future) client JS; Python has the richest stats ecosystem; Go produces tiny 165 static binaries; plain HTML is simplest but least expressive. 166 - *Project discovery marker*: how does the generator decide a folder in =../= is 167 a project to show? =.git= presence? An explicit manifest file? An allowlist 168 config? The answer affects day-one UX. 169 - *Time-tracker integration*: which tracker, and does the dashboard read its 170 data live or from a periodic export? This is the least-defined data source. 171 - *Visual identity*: the dashboard as first public artifact under my name sets 172 tone for whatever follows. Minimalist / data-dense / colourful? Worth settling 173 before the polish phase. 174 - *Update strategy for public deploy*: auto-deploy every commit, or explicit 175 "publish" button? Staging environment as gate before production? 176 - *"What is a project" boundary*: is a project one folder, or can a folder 177 contain multiple projects (e.g., monorepos)? Does the dashboard treat 178 sub-folders as children, or flatten? 179 180 * Suggested sequence 181 182 1. Decide stack. 183 2. Scaffold project with minimal build pipeline (generator reads =../=, outputs 184 a placeholder HTML). 185 3. First real data source: git stats for one project. 186 4. Expand to all projects; add =rad= issue counts. 187 5. Read-only MVP — usable as a new-tab page locally. 188 6. Visual polish. 189 7. Additional data sources (time tracker, remote metadata). 190 8. Optional: write-back feature for annotations. 191 9. Privacy filter implementation + =--public= build target. 192 10. First deploy to =dashboard.brinon.eu= via Dokploy.