The web app provides an interactive interface for RoverDevKit's mission evaluator, surrogate predictions, parametric sweeps, multi-objective design optimization, and SHAP-style design explanations.
webapp/
├── backend/ FastAPI app over the roverdevkit Python package
└── frontend/ React + Vite + TypeScript single-page app
The backend is a thin FastAPI layer over the Python evaluator and trained surrogate artifacts. The API keeps the browser UI aligned with the same models used by scripts and notebooks.
Common routes:
| Method | Path | Purpose |
|---|---|---|
| GET | /healthz |
Liveness and artifact-presence probe. |
| GET | /version |
Dataset, surrogate, and git version metadata. |
| GET | /scenarios |
List bundled mission scenarios. |
| GET | /scenarios/{name} |
Return one scenario and its nominal soil parameters. |
| GET | /registry |
Return published rover registry entries. |
| POST | /predict |
Surrogate median and 90% interval for one design. |
| POST | /evaluate |
Physics evaluator output for one design. |
| POST | /sweep |
One- or two-dimensional parametric sweep. |
| POST | /optimize |
Start an NSGA-II multi-objective optimization job. |
| GET | /optimize/{job_id}/stream |
Stream optimization progress with server-sent events. |
| GET | /optimize/{job_id}/result |
Fetch a completed optimization result. |
| POST | /shap/explain |
Explain one current design prediction. |
From the repository root, with the roverdevkit conda environment activated:
conda activate roverdevkit
pip install -e ".[webapp]"
uvicorn webapp.backend.main:app --reload --port 8000OpenAPI docs are available at http://localhost:8000/docs.
The frontend is a Vite + React + TypeScript app. Its typed fetch client lives in
src/lib/api.ts, and the dev server proxies backend routes to
http://localhost:8000.
cd webapp/frontend
npm install
npm run dev
npm run build
npm run lintRun both servers together from the repository root:
make webapp-devOpen http://localhost:5173 after the frontend server starts.
- Current Design evaluates the active rover design under the mission inputs (scenario, scientific-payload mass and power, operational duty cycle). Payload is a mission requirement set at the top of the panel, not a design variable.
- Parametric Sweep explores one- and two-variable design sensitivities.
- Optimize Design runs NSGA-II searches and visualizes completed Pareto fronts.
- Explain Design shows SHAP-style feature attributions for the active design and selected target.
The Optimize Design tab always runs NSGA-II live against the corrected physics evaluator. There is no in-app "load reference" affordance because the live job completes in ~30–60 seconds at the default budget and produces evaluator-truth points anyway.
The repo still ships a precomputed reference set under
reports/pareto_fronts/ (one CSV + metadata JSON per canonical scenario,
plus a top-level manifest.json). These are reference artifacts for
documentation figures and notebook fixtures; the evaluator is
deterministic and each file is small (~14 kB), so they are committed
to the repo for reproducibility.
Regenerate them whenever scenario configs change:
make pareto-frontsPass extra arguments through SCRIPT_ARGS:
make pareto-fronts SCRIPT_ARGS="--population-size 80 --generations 80"The default settings (50-point population, 60 generations, analytical Bekker-Wong evaluator) complete all four canonical scenarios in about 4 minutes on a laptop.
A multi-stage webapp/Dockerfile builds the React frontend
with Node 20 LTS, then installs the Python package + the [webapp]
extras on top of python:3.12-slim and bakes in:
- the analytical Bekker-Wong mission evaluator,
- the v9 quantile-XGB surrogate bundles
(
models/surrogate_v9/quantile_bundles.joblib), - the canonical Pareto fronts (
reports/pareto_fronts/), - the built React frontend at
/app/static.
The runtime image runs a single uvicorn process that serves the
FastAPI backend at /healthz, /predict, /evaluate, /sweep,
/optimize, /shap, /registry, /scenarios, and serves the React SPA off
ROVERDEVKIT_STATIC_DIR=/app/static with a history-mode catch-all so
deep links survive a hard refresh.
docker compose -f webapp/docker-compose.yml up --buildOpen http://localhost:8000. First boot takes 2-3 min for the
pip install layer; subsequent rebuilds reuse the wheel cache and
finish in ~30 s for a code-only edit.
# Build context must be the repo root so the Dockerfile can reach
# pyproject.toml, roverdevkit/, data/, models/, reports/, and webapp/.
docker build -f webapp/Dockerfile -t roverdevkit/webapp:dev .
docker run --rm -p 8000:8000 roverdevkit/webapp:devThe image is intentionally hosting-platform agnostic. To stand it up on Hugging Face Spaces, Fly.io, Railway, or a Duke container, walk through this checklist:
-
docker build -f webapp/Dockerfile -t roverdevkit/webapp:dev .succeeds locally; record the resulting image size (~700 MB compressed for the v9 surrogate bundle). -
docker run --rm -p 8000:8000 roverdevkit/webapp:devboots cleanly;curl localhost:8000/healthzreturns{"status":"ok","surrogate_loaded":true,...}. - Set
ROVERDEVKIT_CORS_ORIGINSto the platform's hosted origin (e.g.https://huggingface.co,https://<user>-<space>.hf.space). Defaults tohttp://localhost:5173(Vite dev server) which will block browser calls in prod. - If the platform fronts the container with TLS, leave the
Dockerfile's
--proxy-headers --forwarded-allow-ips=*flags in place so client IP / scheme propagate from the edge. - Confirm the image runs as
roverdevkit(UID 1000) — Fly.io, HF Spaces, and most K8s pod-security policies require non-root. - If the deploy uses a persistent volume to mount alternate
surrogate artefacts, point the volume at
/app/models/surrogate_v9/quantile_bundles.joblib(or override viaROVERDEVKIT_QUANTILE_BUNDLES); seewebapp/backend/config.pyfor the full env-var surface. - (HF Spaces) drop a
Dockerfilesymlink or a one-lineSpaces config: dockerblock at the repo root that points atwebapp/Dockerfile.
.dockerignore at the repo root excludes the LHS training corpora
(data/analytical/), the training-time reports, any superseded
surrogate versions, and Node / Python build caches. Only the runtime
artefacts the backend actually loads — the current surrogate bundle
(models/surrogate_v9/quantile_bundles.joblib) and the Pareto fronts
— are baked into the image.
pytest webapp/backend/tests -q
cd webapp/frontend && npm run lint && npm run buildThe top-level helper runs the same checks:
make webapp-test