spicebook/CLAUDE.md
Ryan Malloy 78350e02af Update docker-compose and astro config for chat/MCP integration
- Add ANTHROPIC_API_KEY env passthrough in docker-compose.yml
- Add astro telemetry and devToolbar disable settings
- Update CLAUDE.md with deployment notes
2026-02-23 14:25:58 -07:00

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

  • .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