The Dockerfile was copying raw web/ source files but never building the
frontend. Since .gitignore excludes web/dist/, the Docker image had no
built frontend — only the Vite dev entry point (web/index.html) which
references /src/main.tsx and only works with the Vite dev server. This
caused a blank page when accessing the dashboard.
Fix: Add a Node.js build stage that runs npm ci && npm run build, then
copy only web/dist/ into the final image. Also add web/node_modules and
web/dist to .dockerignore to keep the build context clean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>