Streamlit inspiration: https://demo-uber-nyc-pickups.streamlit.app/
One-time setup:
just install
Run both backend + frontend in parallel:
just dev
Or run them individually (in separate terminals):
just dev-backend # FastAPI on http://localhost:8000
just dev-frontend # SvelteKit on http://localhost:5173
The SvelteKit app is configured as a SPA (@sveltejs/adapter-static with fallback: 'index.html'). FastAPI serves the built assets at / and exposes the API under /api/*, so there's no Vite proxy in production mode:
just build # outputs frontend/build/
just run # FastAPI in production mode on http://localhost:8000
The static mount in backend/app/main.py resolves frontend/build/ relative to the source tree and is skipped (with a warning) if the build is missing — so just dev keeps working without a build.
The frontend imports request/response types from frontend/src/lib/client/ — generated from FastAPI's OpenAPI schema by @hey-api/openapi-ts. Run this whenever you change a Pydantic model in backend/app/models.py or a route signature in backend/app/api/routes/:
just gen-client
Under the hood this dumps app.main.app.openapi() to frontend/openapi.json (gitignored), then runs npm run generate-client to emit types.gen.ts + index.ts. The generated client is committed to the repo, so npm install alone is enough on a fresh clone.
For a model to appear in the generated types, the route must expose it to OpenAPI — either via response_model=... on the decorator or a typed return annotation. Import the resulting type with import type { HistogramBin } from '$lib/client'.