Backend: POST api/recorded-routes/{id}/trim (epic #992) #993

Closed
opened 2026-08-07 03:50:41 +00:00 by spikerj · 1 comment
Owner

Part of epic #992. Lands first.

  • TrimRecordedRouteRequestDto {KeepStartIndex, KeepEndIndex, ExpectedPointCount?} in RecordedRouteDtos.cs.
  • New Commands/TrimRecordedRoute/ command + validator (shape rules only) + handler: load owner-scoped tracked summary (404 convention), load points doc, validate indices against deserialized array length (never summary PointCount), 409 RecordedRouteTrimConflictException on ExpectedPointCount mismatch, no-op short-circuit, inclusive slice + segment rebase, recompute via RouteStatsCalculator, ordered writes: delete analysis doc → replace PointsJson → update summary. Log ids/counts only — never coordinates.
  • Controller [HttpPost("{id}/trim")] (UpdateMetadata try/catch shape + Conflict catch); RecordedRouteMapper.ToDetailDto(route, points).
  • Tests: handler (slice/rebase/recompute/analysis-deleted, no-op, kept<2, out-of-range, 409, foreign-owner, partial-failure self-heal), validator, controller. Reuse GpsTraceBuilder; pin the shared trim fixture (apply+stats). Build SpikerSoft.UnitTests.slnf.
Part of epic #992. Lands first. - `TrimRecordedRouteRequestDto {KeepStartIndex, KeepEndIndex, ExpectedPointCount?}` in `RecordedRouteDtos.cs`. - New `Commands/TrimRecordedRoute/` command + validator (shape rules only) + handler: load owner-scoped tracked summary (404 convention), load points doc, validate indices against **deserialized array length** (never summary PointCount), 409 `RecordedRouteTrimConflictException` on ExpectedPointCount mismatch, no-op short-circuit, inclusive slice + segment rebase, recompute via `RouteStatsCalculator`, ordered writes: delete analysis doc → replace PointsJson → update summary. Log ids/counts only — never coordinates. - Controller `[HttpPost("{id}/trim")]` (UpdateMetadata try/catch shape + Conflict catch); `RecordedRouteMapper.ToDetailDto(route, points)`. - Tests: handler (slice/rebase/recompute/analysis-deleted, no-op, kept<2, out-of-range, 409, foreign-owner, partial-failure self-heal), validator, controller. Reuse `GpsTraceBuilder`; pin the shared trim fixture (apply+stats). Build `SpikerSoft.UnitTests.slnf`.
Author
Owner

Verified complete 2026-08-07 — closing.

  • Code: spikersoft-backend@f8f402cd (PR #527, feat/recorded-route-trim-993, commit d2b81036) —
    • SpikerSoft.Api/Domain/Map/RecordedRoutes/RecordedRoutesController.cs:218 → [HttpPost("{id}/trim")]
    • SpikerSoft.Business/Domain/Map/RecordedRoutes/Commands/TrimRecordedRoute/ — TrimRecordedRouteCommand.cs, TrimRecordedRouteCommandHandler.cs, TrimRecordedRouteCommandValidator.cs
    • SpikerSoft.Data/DTOs/RecordedRouteDtos.cs — TrimRecordedRouteRequestDto
    • Tests: SpikerSoft.Business.Tests/Domain/Map/RecordedRoutes/Commands/TrimRecordedRouteCommandHandlerTests.cs + …ValidatorTests.cs, plus SpikerSoft.API.Tests/Controllers/RecordedRoutesControllerTests.cs.
  • Live: unauthenticated POST https://api.spikersoft.com/api/recorded-routes/000000000000000000000000/trim → 401, while POST …/000000000000000000000000/bogusnothing → 404. The 401-vs-404 split proves the trim route is registered in the deployed API, not merely on master.
  • Shipped by: PR #527.

Not migrated: nothing left to do. (The iOS consumer, #994, is the piece still outstanding in this epic — migrated to spikerj/spikersoft-ios#16.)

— Opus 5 Agent

Verified complete 2026-08-07 — closing. - **Code:** `spikersoft-backend@f8f402cd` (PR #527, `feat/recorded-route-trim-993`, commit `d2b81036`) — - `SpikerSoft.Api/Domain/Map/RecordedRoutes/RecordedRoutesController.cs:218` → `[HttpPost("{id}/trim")]` - `SpikerSoft.Business/Domain/Map/RecordedRoutes/Commands/TrimRecordedRoute/` — `TrimRecordedRouteCommand.cs`, `TrimRecordedRouteCommandHandler.cs`, `TrimRecordedRouteCommandValidator.cs` - `SpikerSoft.Data/DTOs/RecordedRouteDtos.cs` — `TrimRecordedRouteRequestDto` - Tests: `SpikerSoft.Business.Tests/Domain/Map/RecordedRoutes/Commands/TrimRecordedRouteCommandHandlerTests.cs` + `…ValidatorTests.cs`, plus `SpikerSoft.API.Tests/Controllers/RecordedRoutesControllerTests.cs`. - **Live:** unauthenticated `POST https://api.spikersoft.com/api/recorded-routes/000000000000000000000000/trim` → **401**, while `POST …/000000000000000000000000/bogusnothing` → **404**. The 401-vs-404 split proves the trim route is registered in the **deployed** API, not merely on master. - **Shipped by:** PR #527. Not migrated: nothing left to do. (The iOS consumer, #994, is the piece still outstanding in this epic — migrated to spikerj/spikersoft-ios#16.) — Opus 5 Agent
Sign in to join this conversation.