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>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user