Files
mimic-big/frontend
knacky 649194b174
Some checks failed
ci / backend (lint + typecheck + unit tests) (push) Failing after 1s
ci / frontend (lint + typecheck + build + unit tests) (push) Failing after 0s
chore(frontend): add multi-stage Dockerfile + nginx SPA config
Production image for the frontend dist.

Stage 1 (build): node:22-alpine, `npm ci --ignore-scripts` from the
committed lockfile, `npm run build`. Output lands in /app/dist.

Stage 2 (runtime): docker.io/nginxinc/nginx-unprivileged:alpine.
- Upstream-maintained variant that runs as the nginx user (uid 101)
  out of the box. /var/cache/nginx and /var/run/nginx are pre-owned,
  no chown gymnastics needed in our layer. Vanilla nginx:alpine fails
  at startup as non-root because client_temp mkdir is denied.
- Listens on 8080 (non-privileged port, matches the unprivileged
  variant convention).
- nginx.conf serves /usr/share/nginx/html with SPA `try_files`
  fallback for client-side routing, long-cache headers on
  /assets/ (Vite hashed bundles), a plaintext /healthz endpoint
  for Caddy / Prometheus blackbox, and server_tokens off.

.dockerignore excludes node_modules, dist, .vite, coverage,
playwright-report, .env*, .git, editor dirs. Keeps .env.example.

Smoke local validated with `podman build -t mimic-frontend:smoke .`
and `podman run -p 127.0.0.1:18080:8080`:
  /healthz -> 200 "ok"
  /        -> 200 index.html (508 B)
  /spa/x   -> 200 (SPA fallback)
  /assets  -> Cache-Control: max-age=31536000, public, immutable
2026-05-22 19:59:09 +02:00
..

Mimic frontend

React + TypeScript SPA for the Mimic BAS platform. Lives behind the existing RT reverse proxy (Caddy + TLS + IP allowlist) — see D-007.

Stack

  • React 19, TypeScript strict
  • Vite 8 (dev/build)
  • Tailwind 4 (semantic tokens in src/styles/theme.css)
  • TanStack Query 5 for server state
  • react-router-dom v7 for routing
  • Recharts for the report visualisations
  • Vitest + Testing Library for unit tests
  • Playwright for E2E (covered in sprint 1+)

Scripts

npm install
npm run dev          # vite dev server on :5173
npm run build        # tsc -b && vite build
npm run typecheck    # tsc -b --noEmit
npm run lint         # eslint . (strict TS + react-hooks + prettier)
npm run format       # prettier --write .
npm test             # vitest run
npm run e2e          # playwright test (needs npm run e2e:install once)

Layout

src/
├── components/
│   ├── brand/        # Wordmark (provisional, awaits PR3 charter)
│   ├── shell/        # AppShell, Sidebar, StatusRail
│   └── ui/           # Panel, Pill, Button — instrument-grade primitives
├── mocks/            # sprint 0 fixtures (no backend yet)
├── router/           # RootLayout helper
├── screens/          # one folder per top-level route
├── session/          # mock auth context (D-003 v1 hook-in point)
├── styles/           # theme.css (tokens), fonts.css, globals.css
└── types/            # cross-cutting type aliases

Design system status (provisional)

The token layer in src/styles/theme.css is structured to receive the RT graphic charter (PR3) without touching component code. Component CSS reads exclusively from semantic tokens (--accent-rt, --status-detected, …); swapping the underlying primitive palette is the only change required when PR3 lands.

Auth status (sprint 0)

The session context reads/writes a mock user in sessionStorage. No real auth yet. v1 will wire local username/password + bcrypt (D-003); v2 maps Keycloak OIDC claims onto the same role enum.

Fonts

IBM Plex (Sans / Sans Condensed / Mono), self-hosted under public/fonts/. Files are not yet vendored — see public/fonts/README.md. Until then the UI falls back to ui-sans-serif / ui-monospace.