Spaces:
Sleeping
Sleeping
File size: 10,112 Bytes
7596726 | 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 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | # solverforge-hospital WIREFRAME
This file is the architectural map for beginners.
If `README.md` tells you how to run the app, this document tells you how the
pieces fit together and in which order to read them.
## Documentation Roles
The docs in this repo are meant to work together rather than compete:
- `README.md`
Quick start, concepts, and user-facing orientation.
- `WIREFRAME.md`
Architecture, execution flow, and file-map walkthrough.
- `docs/api-and-solver-policy.md`
REST routes, lifecycle semantics, payload shape, and solver policy notes.
- `AGENTS.md`
Rules for keeping code, comments, tests, and docs aligned in future changes.
- `Makefile`
The shared developer command surface, including the local Space validation
pipeline.
- `docs/screenshot.png`
Current browser screenshot embedded by the README.
## What This Repo Is Teaching
`solverforge-hospital` is a complete SolverForge example, not just a scoring
snippet.
It shows how to build a planning app where:
- the domain model is small and explicit
- the score rules are readable one file at a time
- the dataset is deterministic and intentionally shaped
- the solver runs as a retained background job
- the browser UI watches the solve through REST and SSE
The planning question is:
"For each hospital shift, which employee should be assigned?"
## SolverForge Concepts In Plain Language
- `Employee`
Input data. The solver reads it, but does not move it.
- `Shift`
The thing the solver is allowed to assign.
- `employee_idx`
The one real decision variable in this app. It points from a shift to one
employee inside `Plan.employees`.
- hard score
Rules that must not be broken, such as missing skills or overlapping shifts.
- soft score
Preferences and quality goals, such as honoring desired days or balancing
workload.
- retained job
A solve that keeps living in memory after it starts, so the UI can poll it,
pause it, resume it, stop it through runtime cancel, or inspect snapshots.
Delete is terminal cleanup before the next fresh Solve, not the Stop action.
## Read Order
If you are new to this repo, read files in this order:
1. `src/domain/employee.rs`
Learn the input facts first.
2. `src/domain/care_hub.rs`
Learn the hospital service-line grouping used by nearby search.
3. `src/domain/mod.rs`
See the `planning_model!` manifest that lists and exports the model modules.
4. `src/domain/plan.rs`
Learn the planning entity, planning variable, nearby meters, and derived
fields.
5. `src/constraints/mod.rs`
See the full score model at a glance.
6. `src/constraints/*.rs`
Read one scheduling rule per file.
7. `src/data/data_seed/entrypoints.rs`
See the public demo-data surface.
8. `src/data/data_seed/large.rs`
See how the published dataset is assembled.
9. `src/solver/service.rs`
See how a domain solve becomes a retained runtime job.
10. `src/api/routes.rs` and `src/api/sse.rs`
See the HTTP contract.
11. `static/app/main.mjs`
See the browser boot sequence.
12. `static/app/shell/` and `static/app/schedule/`
See how stock `solverforge-ui` components are adapted to this hospital demo.
## Runtime Flow
The shortest way to understand the app is to follow one request all the way
through:
1. The browser loads `static/index.html`.
2. `static/app/main.mjs` loads config, the generated UI model, and the `LARGE`
demo dataset.
3. The frontend turns the returned `PlanDto` into schedule rails and side-panel
summaries.
4. When the user clicks Solve, the frontend sends the current plan to
`POST /jobs`.
5. `src/api/routes.rs` converts that HTTP request into a `PlanDto`.
6. `PlanDto::to_domain()` rebuilds the in-memory `Plan`, including derived
helper fields the solver expects.
7. `SolverService` starts a retained solve through `SolverManager<Plan>`.
8. The solver emits lifecycle, phase, telemetry, best-solution, and analysis
events.
9. `src/solver/service.rs` converts those runtime events into the JSON event
shapes expected by the UI.
10. The browser consumes those events over `/jobs/{id}/events` and updates the
visible status, timeline, and analysis panels.
The browser shell also contains a visible REST API guide. That makes
`static/app/shell/api-guide.mjs` part of the documentation surface, not just a
UI helper.
## File Map
```text
.
βββ Cargo.toml
β Rust crate metadata and registry dependency requests.
βββ solver.toml
β Embedded solver policy. This is the runtime source of truth for search.
βββ solverforge.app.toml
β App metadata used by the surrounding SolverForge tooling.
βββ Dockerfile
β Container build for running the app outside the dev checkout.
βββ Makefile
β Local build, validation, and Docker/Space workflow wrapper.
βββ README.md
β Beginner run guide and learning path.
βββ docs/api-and-solver-policy.md
β REST, payload, lifecycle, telemetry, and solver-policy reference.
βββ WIREFRAME.md
β This architectural walkthrough.
βββ AGENTS.md
β Repo-specific contributor and documentation rules.
βββ docs/screenshot.png
β Current browser screenshot used by the README.
βββ src/
β βββ lib.rs
β β Crate root and public module surface.
β βββ main.rs
β β Axum server bootstrap, CORS, static serving, and route composition.
β βββ domain/
β β `planning_model!` manifest plus problem model modules.
β βββ constraints/
β β One scheduling rule per file plus the assembler in `mod.rs`.
β βββ data/
β β Deterministic demo-data generator and published entrypoints.
β βββ solver/
β β Retained-job facade over the SolverForge runtime.
β βββ api/
β DTOs, REST routes, and SSE streaming.
βββ static/
β βββ index.html
β β Browser entrypoint.
β βββ sf-config.json
β β Runtime UI config for the stock frontend shell.
β βββ generated/ui-model.json
β β Generated view metadata used by `solverforge-ui`.
β βββ app/
β βββ main.mjs
β β Browser boot and wiring.
β βββ shell/
β β App shell, state, solver controls, and panels.
β βββ schedule/
β β Hospital-specific grouping, presentation, and rail rendering.
β βββ views/registry.mjs
β Named view registration.
βββ tests/
βββ frontend/
β Browserless frontend tests.
βββ e2e/
β Playwright browser tests for the served app.
βββ support/
Fake DOM support used by the frontend tests.
```
## Why The Model Looks This Way
This app is intentionally narrow.
- There is one planning entity type: `Shift`.
- There is one scalar planning variable: `employee_idx`.
- Nearby search is attached directly to that scalar variable.
- The solver does not juggle multiple variable types, chained assignments, or
list planning.
That makes the example easier to learn because the optimization problem stays
visible:
- facts live in `Plan.employees`
- decisions live in `Plan.shifts[*].employee_idx`
- score rules read those two things and judge the assignment
## Why The Demo Data Is Structured
The demo-data generator is not filler.
It is designed to give beginners a problem that is:
- deterministic
- feasible
- interesting enough that local search still has work to do
- stable enough that tests and comparisons stay meaningful
One important design trick is the hidden witness roster in
`src/data/data_seed/witness.rs`.
That internal roster gives the generator a known feasible staffing pattern.
The published dataset is then shaped around that witness, while the solver only
sees the final public problem. This lets the repo ship a realistic-feeling
demo without random feasibility failures.
## Why The Runtime Uses REST And SSE
The solve is long-lived compared with a normal request/response handler, so the
backend splits the contract into two parts:
- REST for control and snapshots
- SSE for live progress
That separation keeps the frontend simple:
- create a job
- poll or fetch details when needed
- subscribe once to the live event stream
It also mirrors how a real retained SolverForge app behaves in production.
One small but important detail: `GET /jobs/{id}` and `GET /jobs/{id}/status`
return the same summary payload. The second route exists as a stock-compatible
alias for clients that expect the explicit `/status` URL shape.
## Solver Policy
`solver.toml` is embedded by `Plan` and is therefore part of the actual model,
not a side document.
The shipped search policy is deliberately conservative:
- `cheapest_insertion` builds a feasible first assignment
- local search stays in the nearby scalar neighborhood
- `late_acceptance` and `accepted_count` keep the search moving without blowing
up step cost
That narrow configuration is intentional for this demo. It is the balanced
30-second policy that currently performs best on the hospital dataset.
## Frontend Design
The frontend is intentionally thin.
This repo is not trying to teach a custom framework. It is showing how to take
stock `solverforge-ui` pieces and adapt them to one concrete planning problem.
- `shell/` owns app lifecycle, backend wiring, and side panels
- `schedule/` owns the hospital-specific transformation from domain data to
visual rails
- tests in `tests/frontend/` lock browserless presentation behavior down
- tests in `tests/e2e/` verify the served browser app with Playwright
## Validation Surfaces
When you change this repo, think in six separate layers:
1. Domain and constraint logic:
`make test-rust`
2. Slow end-to-end solve quality:
`make test-slow`
3. Frontend module correctness:
`make test-frontend-syntax`
4. Frontend module behavior:
`make test-frontend`
5. Served browser behavior:
`make test-e2e`
6. Local deploy readiness for the Docker-based Space target:
`make ci-local`
If you keep those six layers green, the repo remains teachable and usable.
|