I wanted a single page that showed everything Claude and I had built together since late 2024. Not a portfolio; the main site handles that. More of a tracker: repos, issues, deployments, shipped projects, and a timeline of activity across the tools we use every day. The result is dashboard.jamescarty.co.uk.
Starting static
The first version was deliberately simple. A single HTML page with vanilla JavaScript and CSS; no frameworks, no build step. The data came from a static data.json file that I generated locally using Claude Code with MCP connections to GitHub, Linear, and Vercel. Claude Code would pull repo data, issue counts, and deployment history via MCP, assemble it into a JSON file, and I'd commit it to the repo. Vercel would auto-deploy.
This worked well enough as an MVP, but it meant the data was only as fresh as my last commit. Every time I wanted the dashboard to reflect recent work, I had to regenerate the file and push it. That added commit noise to the repo and the data was stale the moment it was generated.
Going dynamic
The upgrade was a Vercel serverless function at /api/data that fetches all three APIs in parallel at request time. The front-end calls this endpoint instead of reading a static file.
The function uses Promise.all to fetch GitHub, Linear, and Vercel in parallel. GitHub provides repo counts, languages, commit history, and recent activity. Linear provides issue counts, project progress, and closed issues per month. Vercel provides production deployment counts. The function assembles everything into the same JSON schema the front-end already expects, so the switch from static to dynamic required no front-end changes.
Caching was the main design decision. The Vercel CDN caches the response for 15 minutes using CDN-Cache-Control headers. The browser cache is 60 seconds. This means the data is reasonably fresh without hammering the upstream APIs on every page load. No database, no Vercel KV; just HTTP cache headers.
What's on the page
The dashboard shows: stats cards (total repos, issues closed, live sites, languages), a stacked bar timeline of monthly activity (commits in mint, issues closed in purple), Linear project progress cards, a shipped milestones section, the full tech stack with highlighted technologies, a collapsible repo grid, and a recent activity feed.
Some fields are curated rather than derived from APIs: the tech stack, highlighted technologies, and shipped milestones are hardcoded in the serverless function because they need editorial judgement rather than raw counts. Everything else is live.
The design process
Like the blog reskin, this started with mockups. I went through four rounds of design iteration with Claude before writing any code. The layout, colour coding, and information hierarchy were all settled in mockups first. The dashboard uses the same Paradigm Shift design tokens as the portfolio and blog: mint accents, Raleway headings, Source Sans Pro body text, and a dark mode toggle in the back-bar.
The idea for the dashboard was actually Claude's suggestion (yes, I know it's an LLM) when I asked what to build next and it seemed only right to oblige.
Static-first, then automate
Starting with static data was the right call. It let me build and iterate on the front-end without worrying about API rate limits, authentication tokens, or caching strategies. Once the layout and data schema were stable, adding the dynamic endpoint was a contained change: one new file in the api/ directory, environment variables for the three API tokens, and updated cache headers. The static data.json still exists as a silent fallback if the API ever fails.
The dashboard is live at dashboard.jamescarty.co.uk.
Comments 0
Log in or register to comment.