spicebook/CLAUDE.md

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

  • .env on the production server is NOT tracked in git — edit it directly on the server when adding new env vars
  • BACKEND_INTERNAL_URL=http://backend:8000 must 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 user spicebook but the bind mount is owned by warehack-ing
  • The @resvg/resvg-js native binary requires node:20-slim (Debian glibc) — Alpine won't work
  • OG image font comes from @fontsource/inter in node_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) calls BACKEND_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:

  1. Fetch notebook metadata from the backend (same internal URL)
  2. Render JSX layout with Satori (SVG)
  3. Rasterize to PNG with @resvg/resvg-js (native Rust NAPI binding)
  4. 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:load for interactive islands