# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Spoolman is a self-hosted web service for managing 3D printer filament spools. It tracks inventory, monitors usage, and integrates with OctoPrint and Klipper/Moonraker. **Tech Stack:** - Backend: Python 3.9-3.12, FastAPI, SQLAlchemy 2.0 (async), Alembic - Frontend: React 19, TypeScript, Vite, Ant Design, Refine framework - Databases: SQLite (default), PostgreSQL, MySQL, CockroachDB ## Common Commands ### Python (PDM) ```bash pdm install # Install all dependencies including dev pdm sync --prod --no-editable # Install production dependencies only pdm run app # Run backend server (uvicorn) pdm run itest # Run integration tests (all databases) pdm run docs # Generate API documentation ``` ### Frontend ```bash cd client npm ci # Install dependencies npm run dev # Development server with hot reload npm run build # Production build npm run tsc # Type check only ``` ### Linting/Formatting ```bash black . # Format Python code ruff check . --fix # Lint and auto-fix Python pre-commit run --all-files # Run all pre-commit hooks ``` ### Integration Tests Tests run in Docker containers against multiple database types: ```bash python tests_integration/run.py sqlite # Single database python tests_integration/run.py sqlite postgres # Multiple databases pdm run itest # All databases ``` Run a single test: ```bash pytest tests_integration/tests/spool/test_add.py::test_add_spool_remaining_weight -v ``` ### Database Migrations 1. Edit models in `spoolman/database/models.py` 2. Run the server to update local SQLite 3. `pdm run alembic revision -m "description" --autogenerate` 4. Review generated migration, format with Black/Ruff ## Architecture ### Backend (`/spoolman/`) - `main.py` - FastAPI app entry, startup/shutdown, SPA mounting - `env.py` - Environment variable parsing and configuration - `ws.py` - WebSocket manager for real-time updates - `api/v1/` - REST endpoints and WebSocket handlers - `router.py` - Main router with WebSocket root endpoint - `spool.py`, `filament.py`, `vendor.py` - CRUD endpoints per resource - `models.py` - Pydantic response models - `database/` - SQLAlchemy models and async database operations - `models.py` - ORM definitions (Vendor, Filament, Spool, Setting, *Field) - `database.py` - Connection setup, backup logic, migrations ### Frontend (`/client/src/`) - `App.tsx` - Routing and Refine framework setup - `pages/` - Page components (spools/, filaments/, vendors/, settings/) - `components/dataProvider.ts` - REST API integration - `components/liveProvider.ts` - WebSocket live updates ### Data Model ``` Vendor (1) ──→ (many) Filament (1) ──→ (many) Spool ``` All entities support custom fields via *Field tables (VendorField, FilamentField, SpoolField). ### API Patterns - REST: Standard CRUD at `/api/v1/{resource}` - WebSocket: Real-time events at `WS /api/v1/` or `WS /api/v1/{resource}` - Query params: `?skip=0&limit=50&sort_by=name&sort_order=asc` ### Key Configuration Environment variables (see `.env.example`): - `SPOOLMAN_DB_TYPE` - Database type (sqlite/mysql/postgres/cockroachdb) - `SPOOLMAN_PORT` - Server port (default: 7912) - `SPOOLMAN_DEBUG_MODE` - Enables permissive CORS - `VITE_APIURL` - Frontend API base URL (e.g., `/api/v1`) ## Code Quality - Line length: 120 characters - Python target: 3.9 - Pre-commit hooks enforce Black formatting and Ruff linting - Backend is fully async using SQLAlchemy AsyncSession ## Gitea Repository - **URL:** http://192.168.0.5:3022/tonym/spoolman2 - **API Token:** 8a04b3cb5dbb54e2d895b707305523c3ad83a945 - **Upstream:** https://github.com/Donkie/Spoolman (remote: `upstream`) This is a fork with UX improvements. Issues are tracked on the Gitea instance above. ## UX Improvement Issues | # | Title | Status | |---|-------|--------| | 1 | Inline Creation Modals | ✅ DONE | | 2 | Smart Density Defaults | ✅ DONE | | 3 | QR Code Sizing Fixes | ✅ DONE | | 4 | Layout Max-Width | ✅ DONE | | 5 | Temperature Ranges | 🔄 NEXT | | 6 | Spool Adjustment History | Open | | 7 | 3dfilamentprofiles Integration | Open | ### Issue #1 Complete - Inline Creation Modals Added ability to create filament/vendor inline without leaving the page: - `client/src/components/vendorCreateModal.tsx` - Quick vendor creation - `client/src/components/filamentCreateModal.tsx` - Quick filament creation with nested vendor modal - Modified spool create to add "Create Filament" in dropdown - Modified filament create to add "Create Manufacturer" in dropdown - Uses `dropdownRender` pattern (same as location select) - Uses `useInvalidate` to refresh lists after creation ### Issue #2 Complete - Smart Density Defaults Auto-fill density based on material type: - `client/src/utils/materialDefaults.ts` - Density lookup table with fuzzy matching - Material field converted to AutoComplete (dropdown suggestions + free text) - Fuzzy matching: "PLA Silk" → PLA (1.24 g/cm³) - New filaments default to 1.75mm diameter and 1.24 g/cm³ (PLA) - Applied to both full create page and FilamentCreateModal - Edit page not affected (preserves user customizations) Material densities in lookup: ``` PLA: 1.24, ABS: 1.04, PETG: 1.27, NYLON: 1.52, TPU: 1.21 PC: 1.3, WOOD: 1.28, CF: 1.3, PC/ABS: 1.19, HIPS: 1.03 PVA: 1.23, ASA: 1.05, PP: 0.9, POM: 1.4, PMMA: 1.18, FPE: 2.16 ``` ### Issue #3 Complete - QR Code Sizing Fixes See upstream issue: https://github.com/Donkie/Spoolman/issues/671 Changes: - Removed fixed 50% max-width constraint (now uses fit-content by default) - Added `qrCodePadding` setting (0-10mm, default 2mm) - Added `qrCodeMaxWidth` setting (0-100%, 0 = auto) - Added UI controls with slider + input number for both settings Files modified: - `client/src/pages/printing/printing.tsx` - Added settings to interface - `client/src/pages/printing/qrCodePrintingDialog.tsx` - CSS and UI controls ### Issue #4 Complete - Layout Max-Width Changes: - Added 1400px max-width container in `SpoolmanLayout` - Added 800px max-width for forms via CSS override in `overrides.css` - Content is centered on wide screens ### Issue #5 Next - Temperature Ranges Plan: - Convert single temp values to min/max ranges for better label printing - Add new database columns: `settings_extruder_temp_min/max`, `settings_bed_temp_min/max` - Create Alembic migration to handle data migration - Update API models and endpoints - Update frontend forms to use range inputs - Update label template to show ranges like "190-210°C"