Commit Graph

22 Commits

Author SHA1 Message Date
Martin Hohenberg
392acef28e Show spool availability indicator per job on jobs list
- filamentdb.spool_counts(): builds (material, color_name) → roll count
  from cached stock report; counts rolls_in_stock + rolls_in_use (non-graveyard)
- Jobs list: coloured dot before material — green (2+), yellow (1), red (0)
- FILAMENTDB_URL added to .env

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:22:32 +02:00
Martin Hohenberg
bc1769625e Link filament spools card on dashboard to FilamentDB (new tab)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:20:49 +02:00
Martin Hohenberg
b9710faf73 Add 'Compute now' button to job detail File & Geometry card
POST /jobs/{id}/analyse clears the stl_cache entry and re-runs trimesh,
then redirects back to the detail page. Button hidden for .gcode files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:20:01 +02:00
Martin Hohenberg
13422ba29b Remove stale Filament query references left after filament removal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:18:28 +02:00
Martin Hohenberg
6f85cd5d1c Add priority flag to jobs
- Migration 0010: priority BOOLEAN NOT NULL DEFAULT 0 on print_jobs
- Priority jobs sort above normal jobs in the list
- Checkbox in Add Job modal; warning icon in list; badge on detail page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:17:55 +02:00
Martin Hohenberg
e7df987e5b Fix missing Numeric import in print_job model
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:16:17 +02:00
Martin Hohenberg
1259a7294a Remove internal filament management, integrate FilamentDB, add job detail page
Filament removal:
- Deleted app/models/filament.py, routers/filaments.py, templates/filaments.html
- Migration 0009: drops filaments table and filament_id FK from print_jobs
- Removed Filaments from sidebar and all internal references

FilamentDB integration (read-only):
- app/filamentdb.py: GET /reports/stock with 5-min in-memory cache
- available_materials() / available_colors() populate job form dropdowns
- Falls back to static constants if FilamentDB unreachable
- Dashboard filament count now from FilamentDB rolls_in_stock
- FILAMENTDB_URL added to .env.install; httpx added to requirements

Job detail page (/jobs/{id}):
- Two cards: Job info (customer, material, printer, bracket, timing, cost)
  and File & Geometry (bounding box + volume from stl_cache)
- Log timeline with Add Entry modal
- Filename in jobs list links to detail page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:12:47 +02:00
Martin Hohenberg
6868862d77 Replace combined filament dropdown with separate material + color dropdowns
- app/constants.py: MATERIALS and COLORS standard value lists
- Migration 0008: job_material + job_color columns on print_jobs
- Job creation (both /jobs and /brackets/{id}/jobs) stores these independently
  of the filament inventory
- All job tables updated to display job_material · job_color

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:08:29 +02:00
Martin Hohenberg
dc73c9a8c1 Add amount field to job creation — auto-creates bracket when > 1
Amount > 1 with no bracket selected: auto-creates a bracket named
'{customer} – {file} ×{amount}', assigns all jobs to it, and redirects
to the new bracket page. Amount = 1 behaves as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:06:35 +02:00
Martin Hohenberg
4c7acb1c52 Analyse STL/3MF on upload: bounding box + volume, cached in stl_cache
- StlCache model: filename, cube_x/y/z (mm), volume_ccm
- Migration 0007: stl_cache table
- app/stl_analysis.py: trimesh-based analyse() + get_cache_map()
  - Runs immediately after upload in both /jobs and /brackets/{id}/jobs
  - Skips .gcode (no geometry), caches per filename, idempotent
- Library selector in both modals now shows dimensions and volume
- requirements: trimesh==4.5.3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:04:11 +02:00
Martin Hohenberg
ccf6a64787 Add job brackets for grouping multi-part or repeated jobs
- JobBracket model: name, customer, notes
- Migration 0006: job_brackets table + bracket_id FK on print_jobs
- /brackets: list with per-bracket progress bar
- /brackets/{id}: detail with jobs table + Add Job(s) modal (quantity field
  creates N identical jobs in one shot, each with its own UUID and log entry)
- /jobs Add Job modal: optional bracket selector
- Sidebar: Brackets nav item added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:03:01 +02:00
Martin Hohenberg
977e0deb24 Make printer optional on job creation — assigned when job starts
Migration 0005 makes print_jobs.printer_id nullable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:57:07 +02:00
Martin Hohenberg
fe594e8675 Add job creation with UUID, STL upload/library, search, job log, TZ, and CLAUDE.md
- 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>
2026-06-18 21:55:49 +02:00
Martin Hohenberg
c78f8c91cd Add printer lifecycle fields and printer log
- Printer: bought_at, last_maintenance_at, decommissioned_at (all Date, nullable)
- PrinterLog: per-printer timestamped text entries (CASCADE delete)
- Migration 0003: adds columns + printer_logs table
- /printers/{id}: detail page showing lifecycle info + scrollable log
- POST /printers/{id}/log: add a log entry via modal form
- Printer names in list are now links to the detail page
- Add Printer modal includes optional purchase date

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:47:48 +02:00
Martin Hohenberg
750edbbcec Add printer types with bed volume + add-printer UI
- PrinterType model: name, bed_x_mm/y/z, linked to Printer via type_id
- Migration 0002: creates printer_types, adds type_id to printers, drops model
- /printer-types page: table + Add Type modal form
- /printers page: Add Printer modal with type dropdown (disabled if no types)
- API: GET/POST/DELETE /api/printer-types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:46:26 +02:00
Martin Hohenberg
ea1e383cfc Fix logging and surface unhandled exceptions
- basicConfig so the pops logger actually emits output
- Global exception handler logs full traceback + returns detail in 500

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:38:40 +02:00
Martin Hohenberg
541bb88847 Catch migration exceptions so app doesn't crash-loop on startup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:37:02 +02:00
Martin Hohenberg
ee0b1b39e9 Add Jinja2 web UI with Bootstrap 5 dark theme
- app/templates/: base layout with sidebar nav + 6 pages
  (dashboard, printers, jobs, filaments, todos, pricing)
- app/routers/ui.py: HTML routes querying the DB live
- API routes moved to /api/* prefix
- requirements: jinja2, python-multipart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:26:23 +02:00
Martin Hohenberg
ef8285e583 Auto-stamp or migrate on startup
On boot, run_migrations() checks the Alembic revision:
- no revision + tables exist  → stamp head (db.sql was run manually)
- no revision + no tables     → upgrade head (fresh install)
- revision present            → upgrade head (no-op if already current)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:21:51 +02:00
Martin Hohenberg
d092c19b41 Scaffold SQLAlchemy models, routers, and Alembic migrations
- app/models/: Printer, Filament, PrintJob, Todo, PricingConfig with full
  SQLAlchemy 2.x mapped columns and relationships
- app/routers/: list + get-by-id endpoints for all five resources
- app/db.py: SQLAlchemy engine + SessionLocal + get_db dependency
- alembic/: env.py reads MYSQL_* env vars; 0001_initial_schema mirrors db.sql
- alembic.ini: script_location configured, URL injected at runtime

Since db.sql already created the tables, stamp the DB before running future
migrations:  alembic stamp head

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:19:59 +02:00
Martin Hohenberg
03eebc4f9b Expose DB connection error in /health response for debugging
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 21:10:38 +02:00
Martin Hohenberg
f66af4c732 Add FastAPI hello-world structure with Docker and DB health check
- app/main.py: root endpoint + /health that reports DB connectivity
- app/db.py: pymysql connection check from MYSQL_* env vars, logged at startup
- Dockerfile: python:3.12-slim, port 8720
- docker-compose.yml: mysql:8.2 with healthcheck, app waits for DB ready
- requirements.txt: fastapi, uvicorn, pymysql

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 19:21:55 +02:00