b3c3e2a3b2
- 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>
2.9 KiB
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=1by default) so heavy, CPU-bound CAD work doesn't block the event loop. Status/stage are written to SQLite as the job progresses, so pollingGET /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.pyactive-area detection: the kernel ships as cadquery'sOCP, not pythonoccOCC.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.