1# FinData OS — web console23Private operator console for the FinData OS lakehouse. Next.js 15 (App Router) + TypeScript + Tailwind CSS v4, built as a **static export** and served by the Python API — no Node process in production.45## Develop67```bash8cd apps/web9pnpm install10pnpm dev # http://localhost:3000 — /api/* is proxied to http://127.0.0.1:8600 (next.config.ts rewrites, dev only)11pnpm typecheck # tsc --noEmit12```1314Start the API locally (`uv run uvicorn findata_api.main:app --port 8600`) before using the dev server; the console authenticates with the API's cookie session and sends `X-CSRF-Token` on every non-GET request.1516## Build & serve1718```bash19pnpm build # → apps/web/out/ (index.html + one directory per route, trailing slashes)20```2122`services/api/src/findata_api/main.py` mounts `apps/web/out` (or `FINDATA_WEB_DIST`) with `StaticFiles(html=True)`, so `/datasets/` serves `out/datasets/index.html`, and the console is same-origin with `/api/v1`. The CSP is `default-src 'self'` (inline styles allowed, inline scripts not); the bundle contains no inline scripts, external fonts or CDNs.2324Detail pages use query strings instead of dynamic segments (static export cannot pre-render unknown ids): `/datasets/detail/?id=…`, `/symbols/detail/?symbol=…`.2526## Layout2728```29src/lib/api.ts fetch wrapper (same-origin cookies, CSRF header, error normalisation) + API types30src/lib/auth.tsx /auth/me context, redirects to /login/ (401) or the MFA step31src/lib/hooks.ts useAsync, useDebounced, useQueryParam, useInterval, useLocalStorage32src/lib/format.ts bytes, thin-space numbers, YYYY-MM-DD HH:mm:ssZ, CSV33src/components/ Shell (sidebar ≥1024px, bottom tabs + drawer on mobile), DataTable (cards <640px), charts, dialogs, toast34src/app/<route>/page.tsx one client page per route35```3637Routes: `/` overview · `/login/` · `/datasets/` (+`detail/`) · `/symbols/` (+`detail/`) · `/coverage/` · `/bars/` · `/ingestion/` · `/quality/` · `/storage/` · `/keys/` · `/playground/` · `/exports/` · `/fundamentals/` · `/docs/` · `/audit/` · `/settings/`.3839Owner-only pages (ingestion, storage, keys, audit, environment settings) are hidden from the navigation for other roles and show a notice if opened directly; the API enforces the `admin` scope regardless.4041## Design4243Brand-neutral palette validated with the `dataviz` skill (categorical blue/orange/aqua, sequential blue ramp for the coverage heatmap, fixed status colours with icon + label), light and dark via `prefers-color-scheme`, system font stack. Charts: `recharts` (one axis per chart, 2 px lines, ≤24 px bars, hover tooltips) and plain SVG for the heatmap.44