SPB Git

spb/findata

Public
3.5 KB · 52 lines markdown
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.2324### CSP and the post-build step2526Next's App Router emits its React Server Components payload as inline `<script>self.__next_f.push(…)</script>` tags, which `script-src 'self'` blocks. `pnpm build` therefore runs `scripts/externalize-inline-scripts.mjs` after `next build`: it moves those pushes, per page, into `out/_next/static/flight/<hash>.js` and replaces them with one blocking `<script src>`. The exported HTML contains **no inline scripts** (the script fails the build if it ever meets one that is not a `__next_f` push).2728### Smoke test without the backend2930`node scripts/mock-server.mjs [port] [--signed-out] [--mfa]` serves `out/` with the API's exact CSP header plus fixture answers for every `/api/v1` endpoint the console uses — handy for layout checks (375 px / desktop, light / dark) and for verifying hydration under CSP. Not used in production.3132Detail pages use query strings instead of dynamic segments (static export cannot pre-render unknown ids): `/datasets/detail/?id=…`, `/symbols/detail/?symbol=…`.3334## Layout3536```37src/lib/api.ts        fetch wrapper (same-origin cookies, CSRF header, error normalisation) + API types38src/lib/auth.tsx      /auth/me context, redirects to /login/ (401) or the MFA step39src/lib/hooks.ts      useAsync, useDebounced, useQueryParam, useInterval, useLocalStorage40src/lib/format.ts     bytes, thin-space numbers, YYYY-MM-DD HH:mm:ssZ, CSV41src/components/       Shell (sidebar ≥1024px, bottom tabs + drawer on mobile), DataTable (cards <640px), charts, dialogs, toast42src/app/<route>/page.tsx   one client page per route43```4445Routes: `/` overview · `/login/` · `/datasets/` (+`detail/`) · `/symbols/` (+`detail/`) · `/coverage/` · `/bars/` · `/ingestion/` · `/quality/` · `/storage/` · `/keys/` · `/playground/` · `/exports/` · `/fundamentals/` · `/docs/` · `/audit/` · `/settings/`.4647Owner-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.4849## Design5051Brand-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.52
Files · 818844d38cd03bb68ada5c33f70bef54bcf29f10
Menu

Theme