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

make space-build
make space-run

Full local readiness check:

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

make run-release

Then open http://localhost:7860.

To inspect the command surface:

make help

Development

# 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:

make test

Full local Space validation:

make ci-local