
timothyandClaude Opus 4.8
5c9f04fdec
feat(#253 PR2): optimistic-concurrency on schedule-items aggregate
Wire the frozen #253 ETag/If-Match/412 recipe onto ProgramSchedule /
schedule-items, keeping the PR#258 positional in-place reconcile intact.
Backend:
- ReplaceProgramScheduleItems command gains Option<int> ExpectedVersion;
ReplaceScheduleItemsRequest.ToCommand threads it.
- Handler: standalone CheckVersion Either AFTER validation (so 412 isn't
flattened to 422), unconditional Version++ before save, guarded save via
SaveChangesWithConcurrencyGuard, and 412 propagated without running the
post-save reload/enqueue.
- ProgramScheduleViewModel + Mapper carry Version.
- ScheduleController: GET /items emits ETag; PUT /items parses If-Match
(malformed -> 400), threads ExpectedVersion, re-queries for the new ETag,
and advertises 400/412.
- Sibling config-writers (Add/Delete item, Update schedule) bump Version.
Frontend:
- schedules.ts: getScheduleItemsWithMeta + replaceScheduleItems(ifMatch)
returning ResponseWithMeta.
- SchedulesScreen: etagRef threaded through the #242 dirty-guard (set from
load + every successful save); 412 opens a conflict ConfirmDialog whose
Reload discards the draft and re-runs loadItems.
Tests: handler concurrency suite (stale->412 no mutation + fill-group state
untouched, match/absent success+bump, no-op still bumps, racing save->412);
controller ETag/If-Match/412 cases; SchedulesScreen 412-conflict-dialog test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 18:36:25 +02:00
..
2026-07-11 18:36:25 +02:00
2026-07-11 17:18:35 +02:00
2026-06-30 18:49:35 +02:00
2022-04-19 17:47:18 -05:00
2026-07-07 12:11:11 +02:00
2026-07-09 19:53:29 +02:00
2025-12-31 15:18:07 -06:00
2026-02-15 09:46:07 -06:00
2026-07-09 20:06:26 +02:00
2026-07-11 12:54:48 +02:00
2026-07-07 12:11:11 +02:00
2026-01-20 09:50:45 -06:00
2026-07-07 14:06:26 +02:00
2026-07-11 16:06:11 +00:00
2026-02-04 14:20:43 -06:00
2023-09-03 08:52:00 -05:00
2025-08-16 14:44:48 +00:00
2023-03-16 06:21:02 -05:00
2026-02-26 10:43:48 -06:00
2026-02-03 13:52:52 -06:00
2026-06-27 07:37:15 +00:00
2022-04-19 17:47:18 -05:00
2024-03-05 10:39:06 -06:00
2026-07-11 16:45:03 +02:00
2026-01-08 11:51:16 -06:00
2026-02-04 14:20:43 -06:00
2023-05-10 13:18:18 -05:00
2025-08-23 20:16:12 +00:00
2026-01-07 16:46:17 -06:00
2023-09-03 06:23:42 -05:00
2023-08-11 13:57:50 -05:00
2026-07-11 16:39:56 +02:00
2026-07-06 18:43:39 +02:00