File size: 6,705 Bytes
4f50b67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
---
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 screenshot](docs/screenshot.png)

`solverforge-fsr` is a SolverForge field-service routing app with retained
jobs, technician schedules, road-network geometry, 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?"

## Quick Start

```sh
make run-release
```

Then open `http://localhost:7860`.

To inspect the supported command surface:

```sh
make help
```

## Documentation Map

- `README.md`
  Quick start, model concepts, validation, REST API, and solver policy.
- `WIREFRAME.md`
  As-built architecture and runtime/data flow across backend, routing, and UI.
- `AGENTS.md`
  Codex-facing maintenance, validation, and documentation rules.
- `Makefile`
  Supported local commands for development, validation, Docker, and Space work.
- `Dockerfile`
  Docker Space image build using Rust 1.95 and the declared crates.io line.

## Current Dependency Shape

- Package: `solverforge-fsr`; version is declared in `Cargo.toml`
- Release binary: `solverforge_fsr`
- Rust: `1.95`
- SolverForge runtime: `solverforge` `0.19.3`
- SolverForge core helpers: `solverforge-core` `0.19.3`
- Browser UI assets: `solverforge-ui` `0.6.5`
- Routing engine: `solverforge-maps` `2.1.4`
- Scaffold metadata: `solverforge-cli` `2.2.2` in `solverforge.app.toml`

The app serves registry-backed Rust dependencies, local static browser modules,
and Axum API routes from one process.

## Model Concepts

- `Location` is a problem fact: a depot or customer coordinate.
- `ServiceVisit` is a problem fact: a customer job the solver must place in a
  route.
- `TravelLeg` is a problem fact: precomputed duration, distance, and
  reachability between two locations.
- `TechnicianRoute` is the planning entity: one route owned by one technician.
- `TechnicianRoute.visits` is the list planning variable: the ordered visit
  sequence SolverForge changes.
- `FieldServicePlan` is the planning solution with the current `HardSoftScore`.

The app ships one deterministic `STANDARD` Bergamo dataset with two depots, six
technicians, 24 customer locations, and 48 service visits.

## Constraints

Hard constraints:

- Every service visit is assigned exactly once, and route visit indexes are valid.
- Every route leg is reachable.
- The assigned technician has the required skills.
- The assigned technician carries the required parts.
- Visits fit their time windows.
- Routes fit technician shift capacity.

Soft constraints:

- Total travel time is minimized.
- Workload is balanced across technicians.
- Territory affinity is preferred.
- Deadline slack is rewarded more strongly for higher-priority visits.

## REST API

- `GET /health`
- `GET /info`
- `GET /demo-data`
- `GET /demo-data/{id}`
- `POST /jobs`
- `GET /jobs/{id}`
- `DELETE /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`
- `GET /jobs/{id}/events`

`snapshot_revision={n}` is optional for snapshots, analysis, and route
geometry. Route geometry reports unreachable, snap-failed, and no-path legs as
segment statuses so one failed road leg does not hide the rest of the route.

## Solver Policy

`solver.toml` is embedded by `FieldServicePlan` and is the runtime source of
truth.

- `list_round_robin` creates the first visit distribution.
- Local search combines list change, list swap, sublist change, sublist swap,
  and reverse moves over `TechnicianRoute.visits`.
- `hill_climbing` with `first_best_score_improving` keeps this tutorial easy to
  reason about.
- Solving stops after 60 seconds.

Road-network routing is prepared from the deterministic Bergamo coordinates and
stored as `TravelLeg` facts before solving.

## Validation

Standard validation:

```sh
make test
```

Full local validation:

```sh
make ci-local
```

`make test` runs Rust tests, JavaScript syntax checks, and Playwright browser
tests. `make ci-local` adds formatting, clippy, release build, and Docker image
build.

## Hugging Face Space Deployment

This repo is Docker-Space ready. The Space 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
```

## Read The Code In This Order

1. `src/domain/mod.rs`
   The `planning_model!` manifest and public domain exports.
2. `src/domain/field_service_plan.rs`
   The solution type, fact collections, route entities, transient index
   normalization, route shadow refresh, and score.
3. `src/domain/location.rs`, `src/domain/service_visit.rs`, and
   `src/domain/travel_leg.rs`
   The problem facts the solver reads.
4. `src/domain/technician_route.rs` and `src/domain/route_metrics.rs`
   The planning entity, list variable SolverForge mutates, and route shadow
   measurements used by stock constraints.
5. `src/data/data_seed.rs` and `src/data/bergamo_*.rs`
   Demo ID, Bergamo data assembly, static fact catalogs, routing preparation,
   and cache policy.
6. `src/constraints/mod.rs`
   The score model assembled from SolverForge constraints.
7. `src/constraints/*.rs`
   One business scoring rule per file. Most rules use stock `ConstraintFactory`
   streams; duplicate visit assignment uses a custom incremental counter so
   retained score analysis counts only real duplicate groups.
8. `src/solver/service.rs`
   Retained-job orchestration over `SolverManager<FieldServicePlan>`.
9. `src/api/routes.rs`, `src/api/dto.rs`, `src/api/route_geometry.rs`, and
   `src/api/sse.rs`
   HTTP routes, transport DTOs, route geometry, and live-event streaming.
10. `static/app.js` and `static/app-*.js`
    Browser lifecycle, dataset loading, route rendering, maps, tables, and API
    guide.

## Project Shape

- `src/domain/`
  Planning model, domain types, route entities, and route shadow measurements.
- `src/constraints/`
  SolverForge scoring rules, one business rule per file; most use stock streams.
- `src/data/`
  Deterministic Bergamo demo data and road-network preparation.
- `src/solver/`
  Retained-job facade and runtime event payload formatting.
- `src/api/`
  Axum routes, DTOs, route geometry, and SSE endpoint.
- `static/`
  Browser workspace built on stock `solverforge-ui` assets.
- `tests/e2e/`
  Playwright browser tests for the served app.