Files
step-parse/PHASE1.md
T
Jason Stedwell b3c3e2a3b2 Phase 1: FastAPI backend with async job model
- backend/app: FastAPI API wrapping the CAD skill modules
  - upload -> job -> poll -> model / BOM / artifacts -> geometry query
  - SQLite via SQLModel (Model, Job, BomRow, QueryLog)
  - ThreadPoolExecutor worker, serialized, with live stage updates
- docker-compose.yml: dev server (mounts source, --reload) on :8000
- api-test.sh: end-to-end live validation script
- requirements.txt: add fastapi, uvicorn, python-multipart, sqlmodel
- external_diagram.py: port active-area detection OCC.Core -> OCP
- .gitignore, PHASE1.md

Validated live: MR16 round-trip passes (28 BOM rows, 12 artifacts,
bounding-box query, xlsx download; active-area detection working).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:38:26 -05:00

2.9 KiB

Phase 1 — FastAPI wrapper + job model

Wrap the Phase 0 CAD modules in a web API with async job processing and a SQLite model library. No frontend yet (Phase 2) — validated with curl.

Architecture

backend/app/
  config.py        paths (SKILL_SRC, DATA_DIR, DB) — all env-overridable
  db.py            SQLite engine + init (SQLModel)
  models.py        tables: Model, Job, BomRow, QueryLog
  skill_bridge.py  puts skill.src on sys.path so `modules.*` import works
  processing.py    pipeline orchestration over the CAD modules
  worker.py        ThreadPoolExecutor — runs jobs, persists stage/status/results
  main.py          FastAPI routes
  • Backend is Python/FastAPI, not Jason's usual Node/Express — the CAD core is Python-native (decided in the roadmap).
  • ORM is SQLModel, not Prisma — Prisma is JS-first; SQLModel is the FastAPI-native SQLAlchemy/Pydantic ORM. DB stays SQLite, single file under the data volume.
  • Jobs run in a thread pool (MAX_WORKERS=1 by default) so heavy, CPU-bound CAD work doesn't block the event loop. Status/stage are written to SQLite as the job progresses, so polling GET /api/jobs/{id} shows live stages (loading → bom → thumbnails → diagram → collect → done).

Endpoints

Method Path Purpose
GET /api/health liveness
POST /api/upload multipart STEP upload (+ thumbnails/bom/diagram/translate/diagram_mode form flags) → creates model + job
GET /api/jobs/{id} status, stage, error, artifacts
GET /api/models list models
GET /api/models/{id} model metadata + BOM rows + artifacts
GET /api/models/{id}/artifacts/{name} download a generated file
POST /api/models/{id}/query run a geometry query ({"query": "..."})

Interactive docs at /docs.

Run (dev)

./build.sh                 # only when requirements.txt changed
docker compose up          # http://localhost:8000  (source mounted, --reload)
./api-test.sh              # end-to-end: upload → poll → detail → download → query

docker-compose.yml mounts backend/ and skill.src/ into the image, so code edits hot-reload without a rebuild. Data (uploads, artifacts, SQLite) lives in the step_parser_data volume (mounted at /data).

Also in this phase

  • OCC → OCP port in external_diagram.py active-area detection: the kernel ships as cadquery's OCP, not pythonocc OCC.Core. Now the screen-aperture dimension can actually be detected instead of no-opping with a warning.

Deferred to later phases

  • Frontend (Phase 2).
  • Model loads are repeated per query (no in-memory cache) — fine for MVP; add an LRU of loaded kernels if query latency matters.
  • Auth — none yet; LAN-only. Add before it leaves the network (Phase 4).
  • Swap Background- thread pool for a real queue (RQ/Celery) only if concurrency demands it.