Apply an optimisation solution
Apply one saved optimiser alternative to a service occurrence so the selected table assignments become live and remain traceable to the run that produced them.
In this article
Use this guide when a successful optimiser run already exists for a service occurrence and the operator wants to make one generated table arrangement live. The action consumes the saved run response; it does not create a new run or call the optimiser again.
In the Harbor Demo Group > Harbor Soho demo, the related product surface is the reservation occurrence detail screen. The current visible UI can review and preload Proposed arrangements, but the direct apply action is an authenticated app API/hook, so the preload capture should be labelled as related context rather than proof that the direct apply endpoint ran.
Before you start
- The operator can access the target organisation and location, for example Harbor Demo Group > Harbor Soho.
- Automatic reservations are enabled for the location through `reservation-automatic:use`.
- The operator has either `reservation:manage` or `optimization:manage`, plus the required automatic-reservation permission.
- A service occurrence exists for the same app context, such as `BOOKING_SOLUTIONS_OCCURRENCE_ID` for the Soho lunch service.
- A `service_occurrence_optimization_run` exists for that occurrence, has `status == "succeeded"`, and contains an `alternatives` array.
- The selected alternative is known as `solution_index`; use `expected_occurrence_version` when conflict protection is needed.
Instructions
- 1.
Open the occurrence context
Start from the service occurrence whose table assignments should change. In the GB demo, this is Harbor Soho and the occurrence behind `BOOKING_SOLUTIONS_OCCURRENCE_ID`; the related screen is `/:orgId/:locationId/reservations/:occurrenceId`.
- 2.
Review the proposed arrangements
Use the latest successful run or the related Settings (`Configuraciones`) > Proposed arrangements (`Disposiciones propuestas`) screen to compare generated alternatives, metrics and assignments before choosing one.
- 3.
Choose the solution index
Record the selected alternative as `solution_index`. The index is zero-based, so the first alternative is `0`. Include `expected_occurrence_version` when the client has the occurrence version and wants to avoid applying an outdated arrangement.
- 4.
Apply the saved solution
Submit `POST /api/app/{orgId}/{locationId}/service-occurrences/{occurrenceId}/optimization/runs/{runId}/apply` with `{ "solution_index": number, "expected_occurrence_version"?: number }`. The backend checks permissions, locks the occurrence, validates the run and replaces table assignments for reservations included in the selected solution.
- 5.
Verify the live result
Check the returned occurrence and assignments. Applied assignments are stored with `assignment_mode = "optimizer_applied"` and `source_run_id = run.ID`; reservations omitted from the selected solution are left unchanged.
- 6.
Separate direct apply from visual preload
When using the current product capture, describe Preload in schedule (`Precargar en cronograma`) as a related review/preload workflow. A direct apply result capture needs a supervised setup that calls the authenticated apply endpoint before reopening the occurrence.
Validations and limits
- The app route must be exactly `/service-occurrences/{occurrenceId}/optimization/runs/{runId}/apply` under `/api/app/{orgId}/{locationId}`.
- The method must be `POST` or `PUT`; the frontend API helper uses `POST`.
- The body must decode as `OptimizationApplySolutionRequest` with `solution_index`; `expected_occurrence_version` is optional.
- If `expected_occurrence_version > 0`, it must match the locked occurrence version or the action returns a conflict.
- The run ID is trimmed before lookup, and the run must belong to the same occurrence with `Status == OptimizationRunStatusSucceeded`.
- `solution_index` must be `>= 0` and lower than the number of alternatives in the run response.
- The persisted `ResponsePayloadJSON` must be valid optimiser response JSON.
- Empty table IDs are ignored, repeated table IDs are deduplicated, and missing reservations or tables fail the assignment replacement.
- A solution with no assignments can still update occurrence metadata and `SelectedSolutionIndex`.
- Do not document the current preload UI as evidence that `useApplyOptimizationSolution` or `/apply` ran.
Expected result
The selected optimiser alternative becomes the live assignment set for the reservations included in that solution. The occurrence version increments, optimisation cache is marked stale, waitlist analysis cache is cleared, and the run records `SelectedSolutionIndex` for traceability.