Oops I Broke It
WIPSolo developer — architecture, capture core, and replay UI
The problem
Bug reports arrive as a screenshot and the words "it broke". The console output, the failed request, and the exact sequence of clicks that caused it are all gone by the time a developer looks, so the first hour of every bug is spent trying to reproduce it.
What I built
- Architected a pnpm monorepo around a framework-agnostic recorder core, deliberately splitting the capture package from its consumers so the same core drives the extension, a test playground, and any future SDK.
- Built the capture core on rrweb, adding console interception (including uncaught throws and unhandled promise rejections via global handlers) and fetch/XHR network capture with timing and status codes.
- Wrote a Hono + Drizzle + Postgres API with a storage abstraction that switches between filesystem and S3-compatible blob storage by environment variable, verified against both MinIO and the real thing.
- Split metadata from payload by design — queryable rows in Postgres, the gzipped rrweb event stream in blob storage — because that boundary is the expensive one to undo later.
- Built the replay UI on rrweb's low-level Replayer with a custom scrubber after the official player wrapper silently failed to construct its iframe.
- Shipped an MV3 extension that runs the recorder as a MAIN-world content script so it sees the real page's console and DOM, with an isolated-world relay bridging the popup and handling uploads so its own traffic is not captured.
- Treated redaction as a day-one concern rather than a later feature: rrweb input masking plus Authorization-header stripping in network capture.
- Added an MCP server so an AI coding agent can pull a recording's console and network data directly into its context while debugging.
Outcome
- End-to-end working: a real website is recorded through the extension, uploaded, and replays in the dashboard with the DOM reconstructed and console and network tabs alongside.
- Solved the ad-blocker problem that kills plain-web recorders — running inside the extension sidesteps page-level content blocking entirely.
- Deploy-ready: Dockerfiles for API and dashboard both build and run, storage and CORS are environment-driven.
- Architected for the SaaS turn — multi-tenant auth, share links, and presigned uploads are the remaining gap, not a rewrite.
Tech stack
- Capture
- rrwebTypeScriptZodMV3 extensionVite
- Backend
- HonoDrizzle ORMPostgreSQLS3 / R2 / MinIO
- Frontend & tooling
- Next.jsReactNextAuthpnpm workspacesDockerMCP SDK