Tobias Taulien
← notes

Seven weeks, seven tabs: what happened to my week dashboard

In July I built a dashboard to run my week from. Seven weeks later it has seven tabs and 564 tests, and I closed exactly three weeks with it. An honest follow-up on the stack, the lessons, and what a trip did to the ritual.

buildingclaude-codeproduct-managementproductivity

In July I wrote about building my own dashboard. One screen for the week: calendar, tasks, surf forecast, learning roadmap, and a Sunday ritual that closes the week and writes it into a git-tracked record. I ended that post with a promise to report back after a few closed weeks, with the parts that stuck and the parts I deleted.

This is that post. It's less flattering than I expected.

You can click through a prototype of it here. It's the real frontend with made-up data.

The numbers first

Here's what the app looks like today compared to the day I launched it:

  • Tabs: 1 → 7
  • Code: about 28,000 lines of TypeScript, 108 API endpoints, 564 passing tests
  • Integrations: Google Calendar and Tasks, Open-Meteo, three RSS feeds, the Anthropic API, Google's image models, a stock price feed

And here's how I actually used it:

  • Weeks closed with the Sunday ritual: 3 (CW30, CW31, CW32, back to back)
  • Days I filled in the morning intention: 14, the last one on 10 August
  • Time entries in the work timer I built: 0
  • Surf sessions in the surf log I built: 0
  • Posts in the social pipeline: 45. Published: 2.

Put those two lists next to each other and the story tells itself.

What happened

The first three weeks went exactly as planned. Most mornings I typed one line into the meditation card. Every Sunday I wrote the review, stepped my Chinese lesson counters, and pressed the button. The roadmap moved and the log filled up. It felt great.

Then I started improving it.

First a dark mode. Then a Kanban board for social posts. Then a new theme I designed in Claude Design. Then an image generator for posts, built on Google's Nano Banana models. Then, on 6 August, the big one: I split the single page into tabs and added Learning, Social Media, Health, Work and monthly goals. That's 25 commits in one day. Investments followed the next day, a carousel builder the day after, and one more tab the week after that.

The last intention I typed is from 10 August. So is the last week I closed.

The reason is mundane: I travelled. The ritual didn't survive being away from my desk. Nothing about the app failed and I never decided to stop — a routine with three weeks of momentum just ended when the routine around it did, and it hasn't restarted on its own since.

That's worth separating from a second thing the numbers show, which has nothing to do with the trip: I kept building features I never used. The work timer has never recorded a minute. The surf log has never had a session. Nobody asked for those. They were fun to build, and this time I was both the builder and the user who didn't ask.

What I'd keep

It wasn't all feature creep. Some parts are genuinely good design, and I'd build them again. Whether I use them is a separate question, and that's on me, not on the app.

The learning tracker. Lesson counters against a phased roadmap in one markdown file. No sliders, no guessing. "How's Chinese going?" gets a real number, but only as long as someone keeps the counters up to date. The file hasn't changed since 10 August either.

The surf forecast on the board. Three readings a day per spot, a wave or wind icon, and the week's best swell outlined. It's the only feature that works without any discipline from me, which in hindsight is exactly why it's the one I trust most.

Markdown as the source of truth. Posts, books, projects and the roadmap are plain files I can edit anywhere. The app reads them and never reformats what I wrote. Closed weeks are frozen snapshots, and the whole data folder commits itself to git.

The stack

For the builders:

  • Frontend: React, Vite, TypeScript, TanStack Query. Plain CSS, no Tailwind.
  • Backend: Node and Express, SQLite via better-sqlite3, markdown files, simple-git for automatic backups.
  • Data: Open-Meteo (weather and marine, free, no key), Google Calendar and Tasks via OAuth, RSS.
  • AI: Claude Sonnet for the weekly brief, the close-dialog log lines and tailored CVs. Claude Haiku filters the news. Google's Nano Banana models generate post images.
  • Build: Claude Code, directed by me.

The workflow held up across every feature. Each one got a short PRD with phases and a stop-for-review after every phase. Anything visual got a static HTML mockup that I approved before any real code was written. Anything with an unknown got a spike first. A CLAUDE.md file recorded every decision and why, so each new session started with the full context instead of a blank page.

Five lessons worth more than the app

1. Run the spike before you write the spec. Three times a cheap test overturned a plan. The Fitbit API I'd planned around is being retired in September 2026, and its replacement requires a security assessment no personal app can pass, so health data now comes from a Google Takeout export. SerpAPI returns zero results, not fewer, if the language parameter doesn't match the market. And the stock price provider I picked from its docs returned the wrong security for a bare ticker: $60 for an S&P 500 fund that actually trades at €721. It didn't throw an error. It just quietly gave me a different fund's price.

2. Never show a number you can't justify. That last one became a rule. Every price is now checked against the broker's own figure and rejected if it's more than 6% off. Where a source genuinely can't know something, the app says unknown rather than guessing. A flat with no valuation shows no yearly change at all, because "0%" would claim someone measured it. Silent wrong data is worse than no data.

3. Your validator has blind spots too. One feature rewrites a document for a particular audience, and it’s allowed to add phrasing, so it reports a ledger of everything it added. On its first real run the ledger reported one addition and I found three. The misses were clauses glued onto otherwise identical sentences. Similarity scoring measures what was kept, not what was appended. If you've read my note on evals, this is the same problem again: you have to check the checker against reality.

4. A backup on the same disk isn't a backup. The data folder committed to git from day one, but it had no remote. For weeks, 87 commits of my roadmap, posts and photos existed on exactly one disk. The config option for a remote had been there since the first week. I just never set it.

5. Redesigning mid-build is fine if you write down what you gave up. The money tab started as a transaction ledger and turned into an investments overview halfway through, because day-to-day spending wasn't what I wanted to watch. That cost me savings rate and subscription detection. I wrote that down as a trade, not a win.

What I'm changing

Not another feature.

The app has everything it needs to do its job. What it's missing is a Sunday that survives a week away from home. So the rule for the next month is to close the week even when the week was a mess: from a hotel, late, in five minutes if that's all there is. A ritual that only works from my own desk in a normal week isn't really a ritual.

I'll write a third post if it holds.


The prototype runs entirely in your browser with fictional data. If you've fallen into the same trap with your own tools, I'd like to hear how you got out. Tell me here.