# Vue dashboard over Tailscale: API base and proxy

When restarting or troubleshooting the FinanceManager Vue dashboard for remote/Tailscale use, verify the browser-visible API base, not only localhost health checks.

## Symptom

The page loads via a Tailscale URL, but the UI reports:

- `Backend nicht erreichbar`
- `Runtime-DB nicht verfügbar`

Meanwhile server-side checks may still show:

- `http://127.0.0.1:8000/api/runtime/status` works
- `http://127.0.0.1:5173/api/runtime/status` works

## Root cause

If `VITE_API_BASE_URL` is absent, the frontend client can fall back to `http://127.0.0.1:8000`. In a browser opened on the user's laptop/phone, `127.0.0.1` points to the user's device, not the FinanceManager host. The UI then cannot reach FastAPI even though the backend is healthy on the server.

For Tailscale access, set `VITE_API_BASE_URL` to the browser-visible **FastAPI backend origin** used by the client code. In the current FinanceManager Vue client, `API_BASE_URL` is concatenated directly with API paths, so the practical value is the Tailscale host/IP on port `8000`, not the Vite dev-server port:

```bash
VITE_API_BASE_URL=http://<tailscale-host-or-ip>:8000
```

Example:

```bash
VITE_API_BASE_URL=http://100.85.29.67:8000 \
  __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=100.85.29.67,agent.tailbd371b.ts.net \
  npm run dev -- --host 0.0.0.0 --port 5173
```

Older/proxy-style instructions that use `VITE_API_BASE_URL=http://<tailscale-host>:5173` are only correct if the frontend client intentionally calls the Vite proxy origin. Before reporting success, inspect the served `src/api/client.ts` and confirm `import.meta.env.VITE_API_BASE_URL` contains the browser-visible backend origin. The durable lesson: the page loading over Tailscale does not prove the browser can reach FastAPI; the delivered Vite env must point away from `127.0.0.1`.

## Restart checklist

Do not report "Backend/Frontend neu gestartet" from process-start output alone. For this user's iPhone/Tailscale workflow, restart is only complete after stale listeners are killed, new listeners are observed on the expected bind addresses, and `/api/runtime/status` succeeds through the browser-visible Tailscale/Vite origin.

1. Stop existing dashboard processes and stale listeners on ports `8000` and `5173`. Use port-based cleanup so stale Vite/uvicorn children cannot keep serving an old client:

```bash
for port in 8000 5173; do
  pids=$(fuser -n tcp "$port" 2>/dev/null || true)
  [ -n "$pids" ] && kill $pids 2>/dev/null || true
done
sleep 1
for port in 8000 5173; do
  pids=$(fuser -n tcp "$port" 2>/dev/null || true)
  [ -n "$pids" ] && kill -9 $pids 2>/dev/null || true
done
```

2. Confirm both ports are free before starting new processes:

```bash
ss -ltnp '( sport = :8000 or sport = :5173 )' || true
```

3. Start FastAPI bound to localhost only:

```bash
cd /home/agent/.hermes/repos/FinanceManager
source ~/jarvis_runtime/finance-system/venv/bin/activate
PYTHONPATH=src uvicorn jarvis_finance.api.main:app --host 127.0.0.1 --port 8000
```

3. Resolve Tailscale DNS/IP:

```bash
tailscale status --json | python -c 'import json,sys; d=json.load(sys.stdin); print(d.get("Self",{}).get("DNSName","").rstrip("."))'
tailscale ip -4 | head -n1
```

5. Before starting Vite, verify the actual Vite binary, not only that `node_modules/` exists. A partially restored `node_modules` directory can make the restart script pass its directory check while `npm run dev` still fails with `sh: 1: vite: not found`. Treat this as a dependency repair step, not a dashboard code bug:

```bash
cd /home/agent/.hermes/repos/FinanceManager/frontend
if [ ! -x node_modules/.bin/vite ]; then
  npm install
fi
```

6. Start Vite with a browser-visible backend API base. If `node_modules/.bin/vite` already exists, do **not** include `npm install` in the normal start command; install is a separate maintenance step, not part of every restart.

```bash
cd /home/agent/.hermes/repos/FinanceManager/frontend
VITE_API_BASE_URL=http://<tailscale-host-or-ip>:8000 \
  __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=<tailscale-host-or-ip> \
  npm run dev -- --host 0.0.0.0 --port 5173
```

For the current Tailscale IP style, this is the practical form:

```bash
cd /home/agent/.hermes/repos/FinanceManager/frontend
VITE_API_BASE_URL=http://100.85.29.67:8000 \
  __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=100.85.29.67,agent.tailbd371b.ts.net \
  npm run dev -- --host 0.0.0.0 --port 5173
```

6. Verify listeners and note that background-process parent PIDs can differ from the final child listener PIDs; trust `ss`, not the initial process-start line:

```bash
ss -ltnp '( sport = :8000 or sport = :5173 )'
```

Expected shape:

- `127.0.0.1:8000` handled by `uvicorn`
- `0.0.0.0:5173` handled by `node`

7. Verify all of these, not just localhost. Prefer `/api/health` for current FastAPI liveness and use a real dashboard API/route for runtime data availability; if the repo still exposes `/api/runtime/status`, check it too, but do not assume that endpoint exists in every branch:

```bash
curl -fsS http://127.0.0.1:8000/api/health
curl -fsS http://<tailscale-host-or-ip>:8000/api/health
curl -fsS -o /dev/null -w '%{http_code}\n' http://<tailscale-host-or-ip>:5173/
curl -fsS -o /dev/null -w '%{http_code}\n' http://<tailscale-host-or-ip>:5173/planning/budget/expenses/actual
curl -fsS http://<tailscale-host-or-ip>:5173/src/api/client.ts | grep -E "VITE_API_BASE_URL|100\.85\.29\.67:8000|127\.0\.0\.1"
```

Expected: backend health returns `200`, frontend routes return `200`, and the served Vite client contains `VITE_API_BASE_URL: "http://<tailscale-host-or-ip>:8000"`.

8. Verify the delivered dev client contains the browser-visible API base, because the page can load while still calling `127.0.0.1` from the phone:

```bash
curl -fsS http://<tailscale-host>:5173/src/api/client.ts \
  | grep -E "VITE_API_BASE_URL|127\.0\.0\.1|localhost|http://[^']*:5173" \
  | head -20
```

Expected: `import.meta.env` includes `VITE_API_BASE_URL: "http://<tailscale-host-or-ip>:8000"`. A fallback constant such as `DEFAULT_API_BASE_URL = "http://127.0.0.1:8000"` is acceptable only if `VITE_API_BASE_URL` is actually set in the served client.

9. Browser-sanity the Tailscale URL and inspect the console. The Command Center must say:

- `FastAPI verbunden: ja`
- `Runtime-DB verfügbar: ja`
- `Externe Provider beim Rendern: nein`

10. If the user still sees the old error after the fix, ask for a hard refresh/private tab before changing backend code.

## Durable implementation note

The repo's `scripts/start_vue_dashboard.sh` should set `VITE_API_BASE_URL` automatically from Tailscale DNS/IP when available, using the browser-visible FastAPI backend origin (normally `http://<tailscale-host-or-ip>:8000` for the current Vue client), and export `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` for the Tailscale host. Keep the UI fallback instructions aligned with this command so users do not copy a localhost-only frontend start recipe.