--- name: dev-serve description: | Boots the TTRPG Initiative Tracker dev stack (Node backend + CRA frontend) for hands-on human testing, then opens a headed browser window the user can see and click. Use when user says "let me test", "open it for me", "give me a browser", "run it locally", "boot the app", or wants to manually use the app. Handles STORAGE mode selection (ws vs firebase), port collision cleanup, background process management, and headed agent_browser launch in one shot. --- # dev-serve Run the full app stack for human testing, then open a headed browser window the user can see and drive. ## Prerequisites - Repo root has `server/`, `shared/`, `src/` (npm workspaces). - Node 18+. - Ports 4001 (backend) and 3999 (frontend) free, or let this skill kill stale procs. ## Defaults - Backend: `DB_PATH=/tmp/tracker-dev.sqlite PORT=4001` - Frontend: `REACT_APP_STORAGE=ws` (self-hosted backend) unless user asks for firebase. Override: user says "firebase mode" → `REACT_APP_STORAGE=firebase` + requires `.env.local` with `REACT_APP_FIREBASE_*`. - Frontend port: `3999`. Backend: `4001`. ## Steps ### 1. Kill stale procs (idempotent) ```bash pkill -f "node server/index.js" 2>/dev/null pkill -f "react-scripts start" 2>/dev/null sleep 2 ``` Do not error if pkill finds nothing. ### 2. Boot backend (background, log to /tmp) ```bash rm -f /tmp/tracker-dev.sqlite* DB_PATH=/tmp/tracker-dev.sqlite PORT=4001 nohup node server/index.js > /tmp/tracker-backend.log 2>&1 & sleep 2 curl -s http://127.0.0.1:4001/health # must return {"ok":true} ``` If health fails, tail `/tmp/tracker-backend.log`, diagnose, fix. Do not proceed. ### 3. Boot frontend (background, log to /tmp) ```bash REACT_APP_STORAGE=ws \ REACT_APP_BACKEND_URL=http://127.0.0.1:4001 \ REACT_APP_BACKEND_WS=ws://127.0.0.1:4001/ws \ BROWSER=none PORT=3999 nohup npm start > /tmp/tracker-frontend.log 2>&1 & ``` Wait ~10s, then confirm compile: ```bash grep -E "Compiled successfully|Failed to compile" /tmp/tracker-frontend.log | tail -1 ``` `BROWSER=none` stops CRA from stealing focus; we open our own headed window. ### 4. Open headed browser window for user Use `agent_browser` tool, fresh session (headed flag is launch-scoped): ```json { "agent_browser": { "args": ["open", "http://127.0.0.1:3999", "--headed"], "sessionMode": "fresh", "timeoutMs": 20000 } } ``` Then snapshot to confirm UI rendered (look for "TTRPG Initiative Tracker" heading + "Create Campaign" button, NOT "Loading campaigns..." after 2-3s). ### 5. Tell user the URL ``` App: http://127.0.0.1:3999 (browser window open) Backend: http://127.0.0.1:4001 Logs: /tmp/tracker-frontend.log, /tmp/tracker-backend.log ``` User can also navigate to that URL in their own browser if they closed the agent_browser window. ## Troubleshooting | Symptom | Cause | Fix | |---------|-------|-----| | "Loading campaigns..." stuck | WS subscribe silent fail | Check `/tmp/tracker-backend.log` for WS connection; check ws.js `ensureWs` uses `.onopen/.onmessage` not `.on('open')` | | "Configuration Error" screen | firebase mode without `.env.local`, OR init not gated on STORAGE_MODE | Confirm `STORAGE=ws`; confirm `initializeStorage()` gates firebase | | Port 4001/3999 EADDRINUSE | stale proc | Rerun step 1 | | Campaign created but not visible | WS broadcast not wired, or path prefix not normalized | Check ws.js `norm()` strips `artifacts/.../public/data/` | | Headed window not on screen | remote/VM/headless env | `--headed` only guarantees browser context, not OS visibility; tell user env limitation | ## Teardown When user done testing, kill both: ```bash pkill -f "node server/index.js" pkill -f "react-scripts start" ``` Or leave running if user continuing dev. Ask which. ## Storage mode notes - `ws` (default here): self-hosted backend. Cross-device via backend WS. No Firebase creds needed. - `firebase`: original upstream. Needs `.env.local`. Behavior identical per characterization tests. - `memory`: in-process, tests only. Resets on reload. Switching modes mid-session: kill procs, re-export `REACT_APP_STORAGE`, reboot.