3.2 KiB
3.2 KiB
SpiceBook
Notebook interface for SPICE circuit simulation.
- Frontend: Astro 5 SSR + React 19 islands (
frontend/) - Backend: FastAPI + ngspice (
backend/) - Production: https://spicebook.warehack.ing
- Repo: git.supported.systems:warehack.ing/spicebook.git
Development
# Local dev (Docker)
make dev
# Frontend: http://localhost:4321
# Backend: http://localhost:8099
# Local dev (no Docker)
cd backend && uv run uvicorn spicebook.main:app --host 0.0.0.0 --port 8099 --reload
cd frontend && npm run dev -- --host 0.0.0.0 --port 4322
Deployment to Production
Production runs on warehack.ing (149.28.126.25) behind caddy-docker-proxy.
# 1. Push changes
git push origin main
# 2. SSH to production server
ssh -A warehack-ing@warehack.ing
# 3. Pull and rebuild
cd ~/spicebook
git pull origin main
make prod
# 4. Verify
docker compose -f docker-compose.yml -f docker-compose.prod.yml logs --tail=20
Production environment notes
.envon the production server is NOT tracked in git — edit it directly on the server when adding new env varsBACKEND_INTERNAL_URL=http://backend:8000must be set for SSR server-side fetches (frontend talks to backend over Docker network)notebooks/user/must be world-writable (chmod 777) because the backend runs as non-root userspicebookbut the bind mount is owned bywarehack-ing- The
@resvg/resvg-jsnative binary requiresnode:20-slim(Debian glibc) — Alpine won't work - OG image font comes from
@fontsource/interinnode_modules, not a separate font file
Caddy routing
Caddy routes /api/*, /health, /docs, /openapi.json to the backend (port 8000). Everything else goes to the frontend (port 4321). No Caddy config changes needed for new frontend routes — they're caught by the frontend's SSR handler.
Architecture
SSR Data Flow
Notebook pages fetch metadata server-side via server-api.ts:
fetchNotebookMeta(id)callsBACKEND_INTERNAL_URL/api/notebooks/{id}with a 5s timeout- Title, engine, and tags populate SEO meta tags at render time
- If the backend is unreachable, pages degrade to generic metadata
OG Image Pipeline
/og/[id].png and /og/default.png are SSR API routes that:
- Fetch notebook metadata from the backend (same internal URL)
- Render JSX layout with Satori (SVG)
- Rasterize to PNG with @resvg/resvg-js (native Rust NAPI binding)
- Return with cache headers (1h client / 24h CDN for notebooks, 24h/7d for default)
Key Environment Variables
| Variable | Where | Purpose |
|---|---|---|
PUBLIC_API_URL |
Build-time (Vite) | Client-side API base URL. Empty string = same origin (prod) |
BACKEND_INTERNAL_URL |
Runtime (process.env) | SSR server-to-server API URL over Docker network |
SPICEBOOK_DOMAIN |
Docker labels | Caddy reverse proxy domain |
CORS_EXTRA_ORIGINS |
Backend | Additional CORS origins for embed framing |
Build & Test
cd frontend
npx astro check # TypeScript type checking
npm run build # Full SSR build
Style Guide
- Date-based versioning (YYYY.MM.DD)
- Dark theme: slate-950 background, slate-200 text
- Icons: astro-icon with lucide set (server-rendered SVGs, zero JS)
- React components use
client:loadfor interactive islands