Commit Graph

5 Commits

Author SHA1 Message Date
serversdown 09db988a35 feat(sfm): editable UnitAssignment date windows (backdate deployments)
Operators couldn't change a unit's assigned_at / assigned_until after
creating the assignment, so a unit physically deployed in December 2025
but only recorded in terra-view today would show "deployed today" and
all its real events would be invisible on the project's location page.

Backend:
- PATCH /api/projects/{project_id}/assignments/{assignment_id}
  Accepts JSON body with optional assigned_at, assigned_until, notes.
  - assigned_at is required (cannot be cleared)
  - assigned_until can be null to mark active / indefinite
  - assigned_until must be after assigned_at
  - rejects overlaps with other assignments of the same unit at the
    same location (different units overlapping is fine — that's a
    legitimate swap window)
  - assignment.status flips to "active" when assigned_until is cleared,
    "completed" when set
  - 404 if the assignment doesn't belong to {project_id} (security)

Frontend (vibration_location_detail.html):
- Pencil icon next to each row in the "Seismographs deployed at this
  location" card. Click to open a modal with datetime-local inputs for
  From + Until (blank = active) and a Notes textarea. Save reloads the
  Events tab so KPI tiles and the event table reflect the new window.
- Helper line under the assignment list explains the workflow:
  "Click the pencil to backdate a deployment so historical events get
  attributed to this location."

Verified end-to-end against real data: backdating BE11529's assignment
on a vibration location from 2026-04-14 to 2025-12-01 surfaced 10
additional events (24 -> 34) that were previously invisible.

Validation suite (all returning correct HTTP codes):
  - assigned_until < assigned_at -> 400
  - cross-project assignment_id -> 404
  - assigned_at cleared -> 400
  - notes-only update -> 200

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 22:30:32 +00:00
serversdown df771a87de feat(sfm): wire SFM events into project-location detail page
Phase 1 of the SFM project/location integration. When viewing a vibration
monitoring location, operators now see the events that were actually
recorded there — fanned out across every seismograph that was ever
assigned to that location (handles mid-project unit swaps).

Backend:
- backend/services/sfm_events.py: new events_for_location() async helper.
  Walks UnitAssignment rows for the location (active + closed), intersects
  each assignment's [assigned_at, assigned_until] window with the requested
  filter, and concurrently queries SFM /db/events for each (serial, window)
  pair via httpx.AsyncClient.  Unions, sorts newest-first, computes summary
  stats (event count, peak PVS + when/who, last event, false-trigger count)
  over the full set, and trims to the user's display limit.  Over-fetches
  per-window (up to 5000) so stats stay accurate even with a small display
  limit.

- backend/routers/project_locations.py: new GET endpoint
  /api/projects/{project_id}/locations/{location_id}/events.  Validates
  project/location pairing (404 on mismatch).  SLM locations return an
  empty payload rather than 404 so the frontend can render gracefully.

Frontend:
- templates/vibration_location_detail.html: new "Events" tab on the
  location detail page.  KPI tiles (total / peak PVS / last event / false
  triggers), "Seismographs deployed at this location" assignment list
  (transparency: shows each assignment's date range and contributed event
  count), date / false-trigger / limit filters, and the paginated event
  table.  Lazy-loaded on first tab visit; manual refresh button.

Architectural notes:
- SFM remains the single source of truth for events.  No event sync; live
  HTTP per page load.
- UnitAssignment is the join key (not MonitoringSession).
- Events whose timestamp falls outside every assignment window are NOT
  surfaced here.  Those orphan events get a dedicated "Unattributed
  events" view on the per-unit detail page in Phase 2.

Out of scope (this commit):
- Phase 2 (per-unit history view) and Phase 3 (project-level roll-up)
  reuse this helper but ship separately.
- Phase 4 (deprecating deployment_records) is independent.
- Extracting the event-table JS to a shared file is a follow-up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 21:57:14 +00:00
serversdown 20e180644e feat: enhance swap modal with search functionality for seismographs and modems 2026-03-31 20:16:47 +00:00
serversdown ac48fb2977 feat: add swap functionality for unit and modem assignments in vibration monitoring locations 2026-03-27 20:33:13 +00:00
serversdown 8e292b1aca add: Vibration location detail template 2026-02-24 20:06:55 +00:00