osctrl frontend
June 11, 2026 ยท View on GitHub
React + TypeScript + Vite SPA for the osctrl admin UI.
Talks exclusively to osctrl-api (port 8081 by default). Served as static files โ no Node.js server in production.
Important
The frontend is the primary operator UI going forward. The legacy server-rendered osctrl-admin HTML interface is being kept for transition purposes and will be deprecated.
๐ค What is the frontend?
The osctrl frontend is the modern operator UI for managing environments,
nodes, queries, carves, tags, users, and settings through osctrl-api.
๐ Why it exists
The frontend is where new operator-facing UX improvements are landing. It
replaces the legacy server-rendered osctrl-admin experience with a React SPA
that talks directly to the API layer.
๐ Directory
frontend/
โโโ src/
โ โโโ main.tsx React 19 entry point
โ โโโ router.tsx TanStack Router instance
โ โโโ routes/ Page components (TanStack Router)
โ โโโ components/ Reusable UI components (primitives, atoms, data, chrome, forms, feedback)
โ โโโ features/ Feature modules (one folder per page: nodes, queries, carves, ...)
โ โโโ api/ Typed API client + generated types
โ โโโ lib/ Utilities, custom hooks, time formatting
โ โโโ styles/ Tailwind base + design token CSS
โโโ tests/
โโโ e2e/ Playwright end-to-end tests
๐งฐ npm scripts
| Script | Description |
|---|---|
npm run dev | Start Vite dev server on port 5173, proxying /api to :8081 |
npm run build | Type-check then produce dist/ |
npm run preview | Preview the production build locally |
npm run check | Run tsc --noEmit (type-check only) |
npm run lint | Alias for check (linting config added in a later track) |
npm test | Run Vitest once |
npm run test:watch | Run Vitest in watch mode |
npm run test:e2e | Run Playwright e2e tests |
๐ Development
๐ป Local frontend workflow
# Terminal 1 โ osctrl API (Go)
make api-dev # starts osctrl-api on :8081
# Terminal 2 โ React SPA
cd frontend
npm run dev # starts Vite on :5173, proxies /api/* to :8081
Open http://localhost:5173 in the browser. Vite's dev proxy forwards all /api/* requests to the running Go API, so auth cookies work as same-origin.
๐ณ Docker dev stack
The repository's docker-compose-dev.yml exposes the frontend through
osctrl-nginx at:
https://localhost:8444for the frontend SPAhttps://localhost:8443for the legacyosctrl-adminHTML interface
In that setup, osctrl-frontend stays internal-only on the Docker network and
osctrl-nginx performs TLS termination before proxying requests to it.
๐ Production build
make frontend # runs npm ci + npm run build in frontend/
Output: frontend/dist/. Deploy options:
- nginx โ serve
dist/as the document root, reverse-proxy/api/*toosctrl-api. Seedeploy/nginx/frontend.conf.example. - Static hosting + CDN โ upload
dist/to S3/Cloudfront/etc. Configure CORS on the API. - Docker โ build the multi-stage image at
deploy/docker/dockerfiles/Dockerfile-osctrl-frontend(node:22-alpineโnginx:alpine). Single image, no separate Go binary.
โ๏ธ Tech stack
- React 19 + TypeScript 5 (strict)
- Vite 7
- TanStack Router (typed routing)
- TanStack Query 5 (server state)
- TanStack Table 8 (headless table)
- Tailwind CSS v4 via
@tailwindcss/vite - Radix UI primitives (ร la carte)
- react-hook-form 7 + zod 3
- Vitest + @testing-library/react + jsdom
- Playwright (e2e)