- Add ANTHROPIC_API_KEY env passthrough in docker-compose.yml - Add astro telemetry and devToolbar disable settings - Update CLAUDE.md with deployment notes
3.8 KiB
3.8 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
# Local site: https://spicebook.l.warehack.ing (via caddy-docker-proxy)
# API docs: https://spicebook.l.warehack.ing/docs
# 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
Local vs Production domains
| Environment | Domain | .env setting |
|---|---|---|
| Local dev | spicebook.l.warehack.ing |
SPICEBOOK_DOMAIN=spicebook.l.warehack.ing |
| Production | spicebook.warehack.ing |
SPICEBOOK_DOMAIN=spicebook.warehack.ing |
The .env on the dev machine should use spicebook.l.warehack.ing — the .l. subdomain resolves locally. Using the production domain (spicebook.warehack.ing) will route requests to the remote production server, not the local containers.
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