I manage a team that builds data and AI products. We use React. We use Next.js. We use the full modern stack because at enterprise scale, the abstractions pay for themselves.
But I wanted to understand what those abstractions actually cost.
Thanks for reading The Data Product Agent! Subscribe for free to receive new posts and support my work.
So I built DashPulse — a real-time personal dashboard with 10 live panels, an AI command bar, and a terminal aesthetic — entirely in vanilla TypeScript. No framework. No component library. No virtual DOM. Just TypeScript, browser APIs, and a question: how much of what we reach for by default do we actually need?
The answer was uncomfortable: We are often over-engineering for problems the browser solved a decade ago.
The Constraint That Clarified Everything
Every morning I open the same six apps. Weather. Stocks. News. ESPN. Crypto. Notes. For a brain that already struggles with linear focus, those six context switches before coffee are a high-tax start to the day. DashPulse was supposed to fix that — one dark screen with everything.
But the interesting part wasn’t the product. It was the decision to build it without React.
I didn’t do this to prove a point. I did it because I wanted to feel the friction. When you manage architectural decisions every week, it helps to have recent scar tissue about what those decisions actually mean in practice. I wrote about this in my last post — the gap between managing products and building them is the gap between opinion and conviction. This was another lap around that track.
The constraint forced clarity. Every time I reached for a pattern I’d normally delegate to a framework — state management, component lifecycle, event propagation — I had to solve it directly. And most of the time, the browser already had an answer. CustomEvent for cross-panel communication. IntersectionObserver for lazy loading. MutationObserver for reactive updates. The Web Platform in 2026 is remarkably capable.
Frameworks prioritize developer velocity and hiring standards. Vanilla prioritizes runtime performance and long-term stability. That’s a valid tradeoff at scale. It’s a questionable one for a side project with one developer.
Architecture Decisions That Survived Contact With Reality
DashPulse uses a panel-based architecture. Each panel extends an abstract base class with two methods: fetchData() and render(). That’s it. The panel registry handles mounting, layout, and lifecycle. Panels are completely independent — you can add or remove one without touching anything else.
10 panels shipped, ranging from a 618-line 3D interactive globe to a simple 161-line localStorage scratchpad. Each panel owns its entire lifecycle: attachToDOM() → startDataCycle() → fetchData() → render().
The pattern that surprised me most: this architecture is framework-agnostic by accident. Self-contained modules with clean interfaces don’t need React’s component model. No prop drilling. No context providers. No re-render waterfalls. Each panel fetches its own data, renders its own DOM, and cleans up after itself.
1500+ lines of TypeScript later, I haven’t hit the wall where I needed a framework.
The Feature I Almost Didn’t Build
Spaces started as a throwaway idea. Originally DashPulse had one layout — all panels, all the time. Then I realized I wanted different views for different contexts. A morning briefing. A market hours view. A weekend mode.
This was my “Aha!” moment as a PM. On a Saturday morning, I found myself annoyed seeing market data when I just wanted the news. My own “user research” told me that a static dashboard is just another form of noise.
Spaces let you save panel configurations on a 12-column CSS grid and switch between them instantly. In retrospect, this is the feature that makes DashPulse a product instead of a demo. It respects how people actually use software throughout a day, not just during a screenshot.
Building With AI — What It Actually Looks Like
I built this with Claude Code as my primary development environment. I’ve written before about the PM-to-builder shift, and this project was another test of that thesis.
I described the panel architecture I wanted. Claude scaffolded the TypeScript interfaces and base class. I reviewed every line, adjusted the patterns, and then Claude implemented individual panels based on the established contract.
The honest breakdown: I directed architecture and made judgment calls. Claude wrote most of the implementation.
The bottleneck was never code generation. It was specification. Knowing exactly what to build, how panels should interact, and what tradeoffs to accept is where the value lies. Every year of running discovery sessions transferred directly to directing an AI pair programmer. The people who will struggle with AI-assisted development aren’t the ones who can’t code; they’re the ones who can’t specify.
The Numbers
15,000+ lines of TypeScript across 89 files
21 Edge Functions for API proxying
75kb gzipped bundle (excluding globe.gl)
0 runtime framework dependencies
1.76s build time
11 days from first commit to production
That last number is the one worth sitting with. A full-stack, multi-API, real-time dashboard — shipped in less than two weeks of evening work.
What This Changed About How I Lead
I went back to my day job with different instincts.
When an engineer proposes adding a state management library, I now ask what problem they’re solving that the browser doesn’t already handle. Not as a challenge — as a genuine question born from having recently built something where the answer was usually “nothing.”
When someone says a feature is “two weeks,” I have a more calibrated sense of whether that’s the work or the process. Building solo with AI strips away all the process overhead and exposes the raw complexity of the work itself.
This isn’t about side projects making you a better manager. It’s about building giving you a reference point that managing alone never provides. Opinion versus conviction. The gap is real, and the only way to close it is to ship something.
Try it: dashpulse.app Source: github.com/ethancstuart/dashboard
Thanks for reading The Data Product Agent! Subscribe for free to receive new posts and support my work.


