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

67 lines
2.9 KiB
Markdown

# 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)
```bash
./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.