Spaces:
Paused
solverforge-fsr WIREFRAME
This file is the architectural map for the field-service routing example.
README.md explains how to run and use the app. This document explains how the
pieces fit together and where each responsibility lives.
Documentation Roles
README.mdQuick start, dependency shape, API list, and user-facing orientation.WIREFRAME.mdArchitecture, execution flow, and file-map walkthrough.AGENTS.mdRepo-specific contribution, validation, and documentation rules.MakefileLocal development, validation, and Space/Docker command surface.DockerfileHugging Face Docker Space image definition.
What This Repo Is Teaching
This repo is a complete solverforge-fsr list-variable SolverForge app for
field-service routing in Bergamo.
It shows how to combine:
- a
FieldServicePlansolution with a list planning variable - route-level hard and soft score rules
- precomputed travel-leg facts and
solverforge-mapsroad-network geometry - retained jobs with snapshots, analysis, cancel, pause, resume, and SSE
- a browser map workspace built on stock
solverforge-uiassets
SolverForge Concepts In Plain Language
LocationInput place data. Depots and customer sites are indexed so routes can refer to them cheaply.ServiceVisitInput job data. The solver places visit indexes into technician routes.TravelLegInput travel data. Each leg records duration, distance, and whether the road graph can connect the two locations.TechnicianRoutePlanning entity. Each technician owns one orderedvisitslist.FieldServicePlanPlanning solution. It holds facts, route entities, and the current score.- hard score Missing visits, duplicate visits, invalid visit indexes, unreachable legs, missing skills or parts, late visits, and route overtime.
- soft score Travel cost, workload balance, territory fit, and priority slack.
- retained job A solve that lives in memory so the UI can stream events, fetch snapshots, pause/resume, cancel, analyze, and delete terminal jobs.
Runtime Flow
- The browser loads
static/index.html. static/app.jsloadsstatic/sf-config.jsonandstatic/generated/ui-model.json.- The app fetches
/demo-data/STANDARD. - The backend returns a
FieldServicePlanwith seed travel legs. - The browser renders route cards, tables, timeline, map shell, and the visible REST API guide.
- When the user clicks Solve, the browser posts the current plan to
POST /jobs. src/api/routes.rsdeserializes thePlanDto; domain deserialization andFieldServicePlan::normalize()restore transient service-visit indexes and route shadow fields before routing preparation.prepare_routing()loads or fetches the Bergamo road network, computes the full travel matrix, and replaces seed legs with road-network legs.SolverServicestarts a retained solve throughSolverManager<FieldServicePlan>.- Solver events are converted by
src/solver/event_payload.rsinto UI-facing JSON. - The browser consumes
/jobs/{id}/eventsand fetches snapshots, analysis, and route geometry for exact snapshot revisions. src/api/route_geometry.rsbuilds map segments, preserving non-routed statuses so one unreachable leg does not hide the rest of a route.
File Map
.
βββ Cargo.toml
β Rust 1.95 crate metadata for the app package and registry dependency
β requests.
βββ solver.toml
β Embedded search policy for list construction and local search.
βββ solverforge.app.toml
β App metadata, demo IDs, model facts/entities, registry dependency sources,
β and the `solverforge 0.19.3` runtime target.
βββ Makefile
β Local build, validation, and Space/Docker commands.
βββ Dockerfile
β Multi-stage Rust 1.95 Docker image for Hugging Face Spaces.
βββ README.md
β Run guide, dependency shape, API list, and learning path.
βββ AGENTS.md
β Repo-specific rules for future edits.
βββ WIREFRAME.md
β This architectural walkthrough.
βββ docs/screenshot.png
β Current browser screenshot used by the README.
βββ src/
β βββ domain/
β β `planning_model!` manifest, facts, route entity, shadows, and solution.
β βββ constraints/
β β Mostly stock SolverForge streams plus the custom duplicate-assignment
β β counter in `assigned_visits.rs`.
β βββ data/
β β Deterministic Bergamo seeds, demo entrypoints, and OSM matrix loading.
β βββ solver/
β β Retained-job service and runtime event payload formatting.
β βββ api/
β Axum routes, DTOs, route geometry, and SSE endpoint.
βββ static/
βββ index.html
βββ sf-config.json
βββ generated/ui-model.json
βββ app*.js
Browser controller, map rendering, route state, layout, and tables.
Domain And Route Metrics
src/domain/field_service_plan.rs owns the public solution shape. It keeps the
SolverForge model explicit: facts are read-only inputs, while
TechnicianRoute.visits is the one mutable list variable. Its custom
deserializer and normalize() method rebuild skipped transient visit indexes
and route shadow values after JSON round trips, direct deserialization, and
seed travel-matrix replacement.
Route-specific scoring math lives in src/domain/route_metrics.rs. That module
walks a route from depot to visits to depot, advances a service clock, and
records reusable counters as TechnicianRoute shadow values. The constraint
files then use stock SolverForge ConstraintFactory streams over those shadow
fields. The assignment module uses stock streams for missing visits and invalid
route visit indexes; duplicate assignments use a small custom
IncrementalConstraint so /jobs/{id}/analysis reports matches only for visit
indexes assigned more than once while scoring each extra valid assignment.
src/api/route_geometry.rs is separate because map drawing has a different
job from scoring. Scoring consumes matrix facts already on the plan; geometry
loads the road graph to draw visible polylines for a retained snapshot.
Demo Data
src/data/data_seed.rs exposes one demo ID:
STANDARD
The generator is deterministic. It builds two depots, 24 customer locations, 48 visits, six technicians, and seed self-leg travel facts. Full road-network travel facts are prepared when a job is created.
API And Retained Runtime
The REST API handles discovery, job control, snapshots, and route geometry:
/healthand/infoexpose liveness and app metadata./demo-dataand/demo-data/{id}expose the deterministic demo catalog./jobscreates a retained solver job./jobs/{id}and/jobs/{id}/statusexpose summary state./jobs/{id}/snapshotreturns an exact or latest snapshot./jobs/{id}/analysisruns constraint analysis for a snapshot./jobs/{id}/routesreturns route geometry for a snapshot./jobs/{id}/pause,/jobs/{id}/resume, and/jobs/{id}/cancelcontrol a live job.DELETE /jobs/{id}removes a terminal retained job./jobs/{id}/eventsstreams typed lifecycle events.
Frontend Layout
static/app.js is the controller. It owns current plan state, retained job
state, route focus, event handlers, and analysis modal wiring.
Supporting modules split the UI by responsibility:
static/app-dataset.jsDemo catalog and plan loading.static/app-layout.jsPage shell and stock SolverForge UI component composition.static/app-route-state.jsSnapshot identity and route geometry cache coordination.static/app-render*.jsSummary cards, route cards, maps, timeline, tables, and API guide.static/app-utils.jsPlan cloning, labels, formatting, and color helpers.
Validation Surfaces
Use the Makefile as the repo-local workflow:
make fmt-checkmake clippymake build-releasemake testmake test-e2emake space-buildmake ci-localmake pre-release
make ci-local includes the Docker image build used by the Hugging Face Space.
The Playwright command uses the publication bundle's root Node dev dependency;
runtime UI assets are served from the declared solverforge-ui Cargo crate.