solverforge-fsr / README.md
blackopsrepl's picture
chore(release): bump fsr app version to 1.0.1
6bc6ef3
---
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
```