- PrintJob: job_uuid (UUID4), customer, logs relationship - JobLog model + migration 0004 (also includes job_logs table) - POST /jobs: upload STL or select from library, auto-logs 'Job created' - GET /jobs?q=: search by customer or filename across all statuses - app/stl.py: STL_UPLOAD_DIR helper (from env, default /data/stl) - docker-compose: named volume stl_files mounted at /data/stl - .env.install: added STL_UPLOAD_DIR and TZ=Europe/Berlin - CLAUDE.md: full project context for future sessions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3.7 KiB
3.7 KiB
POPS — Claude Code context
What this project is
Web-based production management system for a 3D print farm. FastAPI backend, Jinja2 server-rendered UI, MySQL 8 (external server), Docker deployment.
Running locally
docker compose up --build # starts on http://localhost:8720
Alembic migrations run automatically at startup (stamps if tables exist, upgrades if not).
Environment
Copy .env.install → .env and fill in values.
Key variables:
| Variable | Purpose |
|---|---|
MYSQL_* |
External MySQL 8 connection |
STL_UPLOAD_DIR |
Where STL/3MF/gcode files are stored (default /data/stl) |
TZ |
Timezone for all timestamps (e.g. Europe/Berlin) |
The docker-compose.yml mounts a named volume stl_files at /data/stl.
Database
- External MySQL 8 server — user needs
ALL PRIVILEGESon the database (Alembic requires DDL). create_db.sql— run once as root to create the DB and user.db.sql— raw schema reference (not used for migrations, kept for reference).- Migrations live in
alembic/versions/, numbered0001_…,0002_…etc.
To add a migration:
docker compose run --rm app alembic revision --autogenerate -m "describe change"
# then review and commit the generated file
Project structure
app/
main.py — FastAPI app, lifespan (DB check + auto-migration)
db.py — SQLAlchemy engine, SessionLocal, get_db, run_migrations
stl.py — STL file directory helpers (get_stl_dir, list_stl_files)
models/ — SQLAlchemy 2.x declarative models (one file per table)
routers/
ui.py — All HTML routes (GET + form POST → redirect)
printers.py — JSON API: /api/printers
printer_types.py
filaments.py
print_jobs.py
todos.py
pricing.py
templates/ — Jinja2 templates extending base.html
alembic/
env.py — reads MYSQL_* env vars at runtime
versions/ — numbered migration files
Conventions
- API routes live under
/api/*(JSON, for programmatic access). - UI routes live at root (
/,/printers,/jobs, …) inapp/routers/ui.py. - Form POSTs redirect with HTTP 303 — no JavaScript needed for basic operations.
- All models have a
to_dict()method fromBasefor JSON serialization in API routes. - Timestamps use the container's
TZenv var — keep it consistent with MySQL server timezone. job_uuid(UUID4) is generated in Python on job creation, not by MySQL.- Job creation always writes a "Job created" entry to
job_logs. - Printer log and job log both use
ondelete="CASCADE"— deleting a printer/job cleans up logs.
Models at a glance
| Model | Table | Notes |
|---|---|---|
PrinterType |
printer_types |
name + bed X/Y/Z mm |
Printer |
printers |
FK → printer_type; lifecycle dates; logs |
PrinterLog |
printer_logs |
timestamped text per printer |
Filament |
filaments |
material enum + color + weight + price |
PrintJob |
print_jobs |
UUID, customer, STL filename, FK → printer + filament |
JobLog |
job_logs |
timestamped text per job (auto-entry on creation) |
Todo |
todos |
optional FK → printer |
PricingConfig |
pricing_config |
electricity rate, markup %, etc. |
UI pages
| URL | Description |
|---|---|
/ |
Dashboard — stats cards + printer overview + recent jobs |
/printers |
Printer list + Add Printer modal |
/printers/{id} |
Printer detail — lifecycle info + log |
/printer-types |
Manage printer types (name + bed volume) |
/jobs |
Job list with search (customer / filename) + Add Job modal |
/filaments |
Filament inventory with progress bars |
/todos |
To-do list |
/pricing |
Pricing config cards |