The Problem
Storybook was running manually via bun run storybook on the host machine. This created several friction points: developers had to remember to start it separately from make up, it was not accessible through the Caddy reverse proxy (no HTTPS, no consistent URL), the Storybook MCP server needed Storybook running to function, and there was no discoverable link in the admin UI -- you had to know the port number.
What I Built
I added Storybook as a dev-only Docker service that starts automatically alongside the rest of the stack, accessible via a proper HTTPS subdomain.
Docker service. The storybook service reuses the existing frontend dev image (Dockerfile.dev) with a command override to run bun run storybook. It shares the same node_modules and source as the frontend, so no separate Dockerfile was needed. Hot reload works -- editing a .stories.svelte file updates Storybook immediately.
Caddy subdomain route. I added a https://storybook.localhost site block to Caddyfile.dev. Storybook serves at root, so no path stripping was needed. Caddy's local_certs auto-issues a certificate for the subdomain, and *.localhost resolves to 127.0.0.1 in all modern browsers per RFC 6761.
Admin sidebar CTA. I added a Storybook external link in the admin sidebar, following the exact same pattern as the existing PocketBase link. It only renders when import.meta.env.DEV is true, so it never appears in production builds. Collapsed sidebar shows a tooltip, matching the existing behaviour.
MCP verification. Confirmed the .mcp.json Storybook MCP server URL (http://localhost:6006/mcp) works with the Docker setup since it uses the host-mapped port, not the Caddy URL.
Key Decisions
- Dev-only service -- lives in
docker-compose.override.ymlandCaddyfile.dev, zero changes to production configs. - Subdomain approach (
storybook.localhost) rather than path-prefix -- Storybook serves at root, avoiding path-prefix configuration issues. - Reuse existing image with command override -- avoids maintaining a separate Dockerfile for Storybook.
- MCP uses host port (
localhost:6006), not Caddy URL -- simpler and avoids proxy complications.
What is Next
With Storybook running automatically in Docker and accessible via HTTPS, the next step was to achieve full component coverage -- writing stories for the remaining 107 components that had none.