Handler hardening (deliberate deviation, documented in-code): CreateDecoTemplateHandler group-existence 422 (the S2-review latent FK-500); ReplaceDecoTemplateItemsHandler now REJECTS what it previously silently dropped — unknown decoId (422), start≥end (422, end 00:00 treated as 24:00), overlaps (422, strict <, adjacency allowed), and out-of-day-range TimeSpans (422 — were persisting raw while displaying .TimeOfDay).
SPA
/app/deco-templates list + editor (deco-group→deco cascade picker with reset-on-group-change, start time + duration hours/minutes, sorted items table with 24:00 end-of-day display, client-side validation mirroring the server exactly — verified identical math in review; Save disabled on violations).
decoTemplates.ts api module + tests; nav next to Decos.
Adds DecoTemplateController mirroring TemplateController: CRUD for deco
template groups, deco templates (flat list + by-id), item listing, and a
full-replace PUT for a deco template's item list.
Hardening (deviation from a literal port of the existing handlers, matching
the #144 S2 fix for ReplaceTemplateItemsHandler):
- CreateDecoTemplateHandler now validates DecoTemplateGroupId exists before
insert (previously a bad id hit the FK constraint at SaveChanges and
surfaced as a 500; now a 422).
- ReplaceDecoTemplateItemsHandler now rejects invalid items (unknown DecoId,
StartTime >= EndTime unless EndTime is the end-of-day sentinel 00:00:00,
or overlapping ranges) with a 422 instead of silently dropping/persisting
them - the same silent-drop/silent-overlap bug class already fixed for
templates.
Response DTOs serialize the raw item TimeSpans (via .TimeOfDay), so an
end-of-day item still round-trips as StartTime=22:00:00/EndTime=00:00:00
regardless of the ViewModel's day-wrapping DateTime representation.
Adds DecoTemplatesScreen mirroring TemplatesScreen: list mode groups deco
templates by deco template group with create/delete dialogs; editor mode
(/app/deco-templates/{id}) has an add-content row (deco group -> deco ->
start time -> duration hours/minutes pickers), a time-sorted items table
displaying end-of-day items as "24:00", and client-side validation mirroring
ReplaceDecoTemplateItemsHandler's hardened rules (start must precede its
effective end time; no overlapping ranges, with EndTime 00:00:00 treated as
end-of-day for both checks) that disables Save on violation.
No copy action: neither the Blazor DecoTemplateEditor nor the CQRS layer has
a deco-template copy command (unlike Templates, which has both Copy* and a
/copy route), so this isn't a parity gap - just matches upstream scope.
Registered at /app/deco-templates in the primary nav, next to Decos.
Out-of-range TimeSpans (25:00:00, 1.06:00:00, negatives) previously
persisted raw while the read side projected .TimeOfDay, so display and
playout behavior diverged silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
timothy
merged commit 4ea5273770 into main2026-07-07 20:06:36 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Slice S4 of the #162 scheduling REST plan (parity issue #144): Deco Templates + Deco Template Groups.
API (new
DecoTemplateController, sibling of TemplateController)GET/POST /api/deco-templates/groups,DELETE /api/deco-templates/groups/{id}(cascade verified in DB config)GET /api/deco-templates(flat list, groups×by-group per the DecoController precedent),GET/POST/DELETE /api/deco-templates[/{id}]GET /api/deco-templates/{id}/items(404-guarded, startTime-sorted, decoName included;endTime "00:00:00"= end-of-day round-trips exactly)PUT /api/deco-templates/{id}— full replaceCreateDecoTemplateHandlergroup-existence 422 (the S2-review latent FK-500);ReplaceDecoTemplateItemsHandlernow REJECTS what it previously silently dropped — unknown decoId (422), start≥end (422, end 00:00 treated as 24:00), overlaps (422, strict<, adjacency allowed), and out-of-day-range TimeSpans (422 — were persisting raw while displaying.TimeOfDay).SPA
/app/deco-templateslist + editor (deco-group→deco cascade picker with reset-on-group-change, start time + duration hours/minutes, sorted items table with 24:00 end-of-day display, client-side validation mirroring the server exactly — verified identical math in review; Save disabled on violations).decoTemplates.tsapi module + tests; nav next to Decos.Verification
c745d01a). Known follow-up families already tracked in #172 (duplicate-item value-equality skip, null-name NRE, exists-query, unreachable 404 docs).Parity note: no deco-template copy exists upstream (Blazor nor CQRS) — nothing deferred. Part of #144 / #162 (slice S4 — do not auto-close).
🤖 Generated with Claude Code
Adds DecoTemplatesScreen mirroring TemplatesScreen: list mode groups deco templates by deco template group with create/delete dialogs; editor mode (/app/deco-templates/{id}) has an add-content row (deco group -> deco -> start time -> duration hours/minutes pickers), a time-sorted items table displaying end-of-day items as "24:00", and client-side validation mirroring ReplaceDecoTemplateItemsHandler's hardened rules (start must precede its effective end time; no overlapping ranges, with EndTime 00:00:00 treated as end-of-day for both checks) that disables Save on violation. No copy action: neither the Blazor DecoTemplateEditor nor the CQRS layer has a deco-template copy command (unlike Templates, which has both Copy* and a /copy route), so this isn't a parity gap - just matches upstream scope. Registered at /app/deco-templates in the primary nav, next to Decos.