Spaces:
Running
Running
| title: SolverForge Field Service Routing | |
| emoji: 🧰 | |
| colorFrom: indigo | |
| colorTo: blue | |
| sdk: docker | |
| app_port: 7860 | |
| pinned: false | |
| license: apache-2.0 | |
| short_description: SolverForge field-service routing example | |
| # SolverForge FSR | |
| `solverforge-fsr` is a SolverForge field-service routing example with retained | |
| jobs, route geometry, technician schedules, and a browser map workspace. | |
| It answers one concrete question: | |
| "Given technicians, service visits, skills, parts, shifts, territories, and | |
| road-network travel, which technician should serve each visit and in what | |
| order?" | |
| ## Hugging Face Space Deployment | |
| This repo is Docker-Space ready. Hugging Face reads the README front matter, | |
| builds `Dockerfile`, and expects the app to bind `PORT=7860`. | |
| Local Space-equivalent commands: | |
| ```sh | |
| make space-build | |
| make space-run | |
| ``` | |
| Full local readiness check: | |
| ```sh | |
| make ci-local | |
| ``` | |
| The Space image is self-contained: it builds against published crates.io | |
| packages, copies `static/`, `solver.toml`, and `solverforge.app.toml`, and runs | |
| the release binary `solverforge_fsr`. | |
| ## Versioning | |
| The app package version is `1.0.1`; the release binary is `solverforge_fsr`. | |
| - CLI version used to scaffold this project: `2.0.3` | |
| - SolverForge runtime target for this scaffold: `solverforge 0.11.1` | |
| - SolverForge UI target for this scaffold: `solverforge-ui 0.6.5` | |
| - SolverForge maps target for this scaffold: `solverforge-maps 2.1.4` | |
| - Runtime dependency currently wired into `Cargo.toml`: `crates.io: solverforge 0.11.1` | |
| - Frontend UI dependency currently wired into `Cargo.toml`: `crates.io: solverforge-ui 0.6.5` | |
| - Maps dependency currently wired into `Cargo.toml`: `crates.io: solverforge-maps 2.1.4` | |
| This project was scaffolded by `solverforge-cli`, and it currently targets `SolverForge crate target 0.11.1` through the configured crate dependency targets. | |
| `solverforge-core` is a direct dependency because the 0.11 custom | |
| incremental-constraint API exposes `ConstraintRef`, while the top-level facade | |
| does not re-export that type. | |
| ## What SolverForge Is Doing Here | |
| - `ServiceVisit` is a problem fact: a customer job the solver must place in a | |
| technician route. | |
| - `TechnicianRoute` is the planning entity: each technician owns one mutable | |
| route. | |
| - `TechnicianRoute.visits` is the list planning variable. | |
| - `FieldServicePlan` is the planning solution. | |
| - Constraints score assignment coverage, route reachability, shift capacity, | |
| required skills, required parts, time windows, priority slack, territory | |
| affinity, travel time, and workload balance. | |
| - `solver.toml` selects the construction and local-search policy. | |
| The app ships one standard Bergamo field-service dataset and prepares full | |
| routing data when a job is created so snapshots can expose per-segment geometry. | |
| ## Quick Start | |
| ```sh | |
| make run-release | |
| ``` | |
| Then open `http://localhost:7860`. | |
| To inspect the command surface: | |
| ```sh | |
| make help | |
| ``` | |
| ## Development | |
| ```sh | |
| # Add a new constraint | |
| solverforge generate constraint my_rule --unary --hard | |
| # Add a domain entity | |
| solverforge generate entity worker --planning-variable shift_idx | |
| # Add a problem fact | |
| solverforge generate fact location | |
| # Remove a resource | |
| solverforge destroy constraint my_rule | |
| ``` | |
| ## Project Structure | |
| | Directory | Purpose | | |
| |-----------|--------| | |
| | `src/domain/` | Planning entities, facts, and solution struct | | |
| | `src/constraints/` | Constraint definitions (scored by the solver) | | |
| | `src/solver/` | Solver service and configuration | | |
| | `src/api/` | HTTP routes and DTOs | | |
| | `src/data/` | Data loading and generation | | |
| | `static/` | Browser UI, SolverForge UI config, and generated UI model | | |
| | `Dockerfile` | Multi-stage Rust 1.95 Alpine build for the Hugging Face Docker Space | | |
| | `Makefile` | Local development, validation, and Space image commands | | |
| | `solverforge.app.toml` | Scaffolded app/domain contract | | |
| | `solver.toml` | Solver configuration (termination, phases) | | |
| ## REST API | |
| - `GET /health` | |
| - `GET /info` | |
| - `GET /demo-data` | |
| - `GET /demo-data/{id}` | |
| - `POST /jobs` | |
| - `GET /jobs/{id}` | |
| - `GET /jobs/{id}/status` | |
| - `GET /jobs/{id}/snapshot` | |
| - `GET /jobs/{id}/analysis` | |
| - `GET /jobs/{id}/routes` | |
| - `POST /jobs/{id}/pause` | |
| - `POST /jobs/{id}/resume` | |
| - `POST /jobs/{id}/cancel` | |
| - `DELETE /jobs/{id}` | |
| - `GET /jobs/{id}/events` | |
| Route geometry is returned by `/jobs/{id}/routes` with segment-level geometry | |
| status. Unreachable road-network legs are reported as non-routed segments, so | |
| one infeasible leg does not hide the rest of the snapshot geometry. | |
| ## Validation | |
| Standard validation: | |
| ```sh | |
| make test | |
| ``` | |
| Full local Space validation: | |
| ```sh | |
| make ci-local | |
| ``` | |