Files
circuit-template/README.md
T
2026-10-15 14:21:55 +02:00

4.1 KiB

Stackship Circuit template

A React 19 + Vite starting point for apps that Circuit builds and Stackship runs. Routing, light/dark theming, a typed API layer and the Stackship components are already wired, so an agent (or you) starts with product work instead of plumbing.

It follows the same contract as Circuit's frontend template — dev server on :5173, mock API at /api, .eventsourced/session.yaml for the live preview — with the Stackship design system on top.

Stack

  • React 19 with the React Compiler enabled
  • Vite 8 dev server, with a mock API served at /api
  • Tailwind v4 — Stackship tokens defined as CSS variables in src/index.css
  • Radix UI (unified radix-ui package) for accessible primitives
  • SWR for data fetching, react-router for routing, lucide-react for icons
  • Poppins + JetBrains Mono bundled through Fontsource — no CDN calls, works air-gapped

Structure

src/
  api/            # typed API layer — one SWR hook per endpoint
    types.ts      #   response types
    client.ts     #   fetch wrapper (all network calls go through here)
    hooks.ts      #   useStats(), useResources(), … consumed by pages
  components/
    ui/           # Stackship primitives: Button, Card, Badge, ServiceIcon, ProgressBar, Skeleton
    gallery/      # component-gallery demos, one primitive per file
    dashboard/    # dashboard sections (StatGrid, ResourcesTable, SentinelCard…)
    home/         # home page sections (Hero, EnvironmentCard, LoopSection, StackGrid)
    Layout.tsx    # header + footer, wraps every route
    Logo.tsx      # Stackship wordmark, light/dark aware
    ThemeProvider.tsx / ThemeToggle.tsx
  pages/          # one file per route, registered in App.tsx
mock/server.mjs   # zero-dependency mock API (started by the dev server)
public/           # favicon and Stackship logos

Conventions (follow these when editing — applies to AI agents too)

  • Colours and fonts come from tokens only. Use Tailwind classes like bg-card, text-muted-foreground, border-border, bg-primary. Never hardcode hex values; both modes read from the variables at the top of src/index.css. The one exception is the always-dark hero surface, which uses bg-night and white text in both themes.
  • Brand utilities: text-gradient (blue→green headline words), bg-brand (gradient CTAs and meters), glass, glow-primary / glow-accent (blurred backdrops on dark sections). Use the gradient sparingly — one highlight per screen reads as deliberate.
  • Resource types get their accent from ServiceIcon (app, database, storage, …). Don't invent new hues for them.
  • Sentinel (the AI/ops assistant) uses the rose sentinel colour and nothing else does.
  • New route = one file in src/pages/ + one line in src/App.tsx (+ nav entry in Layout.tsx).
  • New data = type in src/api/types.ts, route in mock/server.mjs, hook in src/api/hooks.ts. Pages never call fetch directly.
  • Loading with <Skeleton />, errors inline with <ErrorNote /> and a retry — see src/pages/Dashboard.tsx.
  • Pages are compositions. A page owns layout and data fetching, then renders sections from src/components/<page>/. If a page file grows past ~100 lines, extract sections.
  • Copy: sentence case for headings and buttons, no exclamation marks, no emoji. Calm and declarative — "You control where data lives", not "Unleash your data".
  • Radix provides behaviour, Tailwind provides looks. Copy styles from the gallery (src/pages/Components.tsx) rather than inventing new patterns.

Commands

npm run dev       # app on :5173, mock API proxied at /api
npm run build     # type-check + production build
npm run lint      # oxlint

Theming

Light and dark are two sets of CSS variables in src/index.css (:root and .dark). The header toggle offers light, dark and system, and persists to localStorage. To retheme, change the variable values — no component edits needed.

Swapping in a real API

Point server.proxy['/api'] in vite.config.ts at your backend and remove the mockApi() plugin. Endpoint shapes stay in src/api/types.ts.