Commit graph

165 commits

Author SHA1 Message Date
jedarden
da116c546b feat: add environment variable validation with documented defaults
- Create internal/config package with Load() function for all env vars
- Validate types (string, bool, int, enum, URL) and ranges
- Collect all validation errors before returning (fail fast)
- Log non-sensitive values at INFO on startup (MQTT_PASSWORD masked)
- Return error slice; main() logs each error and exits(1)
- Unit tests for valid/invalid cases

Env vars validated:
- SPAXEL_BIND_ADDR (string, default '0.0.0.0:8080')
- SPAXEL_DATA_DIR (string, default '/data')
- SPAXEL_STATIC_DIR (string, default '/dashboard')
- SPAXEL_MDNS_ENABLED (bool, default true)
- SPAXEL_MDNS_NAME (string, default 'spaxel')
- SPAXEL_LOG_LEVEL (enum: debug|info|warn|error, default 'info')
- SPAXEL_FUSION_RATE_HZ (int, range [1,20], default 10)
- SPAXEL_REPLAY_MAX_MB (int, range [10,10000], default 360)
- SPAXEL_INSTALL_SECRET (string, optional, 32+ chars if set)
- SPAXEL_NTP_SERVER (string, default 'pool.ntp.org')
- SPAXEL_MQTT_BROKER (string, optional, must be valid URL if set)
- SPAXEL_MQTT_USERNAME (string, optional)
- SPAXEL_MQTT_PASSWORD (string, optional, never logged)
- TZ (string, default 'UTC', validated via time.LoadLocation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 12:15:06 -04:00
Argo Workflows CI
529d6108d3 ci: auto-bump version to 0.1.58 2026-04-07 16:10:33 +00:00
jedarden
0377426926 fix: wire anomaly detection & security mode API endpoints
- Add missing CountAnomaliesSince method to mockDetectorProvider
  in security_test.go to satisfy the DetectorProvider interface
- Fix variable shadowing bug in anomaly.go QueryAnomalyEvents
  where incomplete rename from 'events' to 'result' caused
  append(events, &e) to reference the package instead of the slice

All security mode endpoints verified:
- GET /api/anomalies?since=24h — lists recent anomaly events
- POST /api/security/arm + /api/security/disarm — arm/disarm
- GET /api/security/status — {armed, learning_until, anomaly_count_24h}
- Anomaly events push to dashboard WS as 'alert' messages
- Arm/disarm state persists across restarts via learning_state table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 12:10:01 -04:00
Argo Workflows CI
c15e03a9d2 ci: auto-bump version to 0.1.57 2026-04-07 15:52:03 +00:00
jedarden
001c17bd85 feat: implement 10-step SIGTERM graceful shutdown sequence
Implements the full ordered shutdown sequence so the mothership drains
cleanly without data loss on SIGTERM (Docker stop, Kubernetes termination).

Shutdown sequence (30s hard deadline):
1. Set shutting_down=true; ingestion server returns HTTP 503 to new WebSocket upgrade requests
2. Broadcast {type:'shutdown', reconnect_in_ms:30000} to all dashboard WebSocket clients
3. Cancel fusion loop context (stops fusion goroutine)
4. Drain signal processing pipeline: wait for in-flight CSI frames (max 2s)
5. Flush in-memory baselines to SQLite in a single transaction
6. Sync CSI recording buffer to disk (close writer, fsync)
7. Close all node WebSocket connections with normal close frame (1000)
8. Write {type:'system', description:'Mothership stopped'} event to events table
9. PRAGMA wal_checkpoint(FULL) to collapse WAL into main DB file
10. sqlite3.Close()

Each step gets its own log line: '[SHUTDOWN] Step N/10 — ...'
Steps that fail log ERROR but do not abort remaining steps.
Exit code 0 if all steps completed within deadline; exit code 1 if deadline exceeded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 11:51:38 -04:00
Argo Workflows CI
1305890f49 ci: auto-bump version to 0.1.56 2026-04-07 15:39:03 +00:00
jedarden
5db3110a2a feat: implement automation triggers CRUD REST endpoints
Add full CRUD endpoints for triggers with OpenAPI-style godoc comments:
- GET/POST /api/triggers (list all, create new)
- PUT/DELETE /api/triggers/{id} (update, delete)
- POST /api/triggers/{id}/test (fire trigger once for testing)

Both TriggersHandler (simple) and VolumeTriggersHandler (3D geometry)
implement all endpoints with table-driven tests covering validation,
persistence, and round-trip lifecycle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 11:38:34 -04:00
Argo Workflows CI
173490ba98 ci: auto-bump version to 0.1.55 2026-04-07 15:09:47 +00:00
jedarden
e44dd345f6 feat: implement comprehensive /healthz endpoint
Add complete health check implementation for Docker HEALTHCHECK and
Traefik health routing with:

Response fields:
- status: "ok" or "degraded"
- uptime_s: seconds since mothership boot
- version: mothership version string
- nodes_online: count of connected nodes
- db: "ok" or "failing" (SELECT 1 with 100ms timeout)
- load_level: 0-3 from load shedding state
- reason: human-readable explanation (only when degraded)

HTTP status codes:
- 200 for healthy (status="ok")
- 503 for degraded (status="degraded")

Degraded conditions:
- Database unreachable
- Load level 3 sustained for >60 seconds
- No nodes connected after 5 minutes uptime

Docker HEALTHCHECK updated to verify status="ok" response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 11:09:36 -04:00
Argo Workflows CI
4c3e6e3dd5 ci: auto-bump version to 0.1.54 2026-04-07 15:05:12 +00:00
jedarden
97f1eafc6f feat: process buffered events from delta WebSocket updates
Events (zone entries/exits, portal crossings, presence transitions)
were already broadcast immediately via BroadcastEvent, but the
buffered copies included in the 10 Hz delta tick were silently
dropped by handleIncrementalUpdate. Now delta events are processed
through the same handleEventMessage path, with dedup to avoid
double-processing when both immediate and delta copies arrive.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 11:04:49 -04:00
Argo Workflows CI
c77bf42178 ci: auto-bump version to 0.1.53 2026-04-07 14:52:40 +00:00
jedarden
4eada81a96 chore: add missing go-chi/chi/v5 dependency for floorplan package
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 10:52:08 -04:00
Argo Workflows CI
d30f886efc ci: auto-bump version to 0.1.52 2026-04-07 14:27:50 +00:00
jedarden
391ed884e4 feat: implement NVS schema migration on boot
Implement versioned NVS key migration on ESP32-S3 firmware so
OTA-updated firmware gracefully handles NVS written by older versions.

- Add nvs_migration.c/h with migration framework
- On boot, read schema_ver from NVS; initialize to 1 if missing
- Run migrations sequentially if schema_ver < COMPILED_NVS_VERSION
- Each migration commits after each write for durability
- Log all migration steps to UART for debugging
- Example migration v1→v2: rename 'ms_ip' to 'mothership_ip',
  add 'ntp_server' with default 'pool.ntp.org'
- Migration failure leaves NVS in consistent state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 10:27:38 -04:00
Argo Workflows CI
80bca356cd ci: auto-bump version to 0.1.51 2026-04-07 14:22:10 +00:00
jedarden
cac25e86e8 feat: implement security mode dashboard UI
- Update learning progress display to show "X of Y days complete" format
- Add last anomaly location info to security dialog stats
- Add CSS styling for anomaly event type in timeline

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 10:22:00 -04:00
Argo Workflows CI
f5c71b5113 ci: auto-bump version to 0.1.50 2026-04-07 14:21:33 +00:00
jedarden
9f53218f16 fix: correct no-op trigger update test expectation
The "no-op update returns current" test case was missing wantEnable: true,
causing a false negative since the seeded trigger has Enabled: true.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 10:21:02 -04:00
jedarden
3d3cb41d25 feat: add security mode persistence and tracker blob lifecycle events
- Add GetArmedAt() method to persist armed timestamp across restarts
- Add blob appear/disappear callbacks to tracker for security events
- Add security handler for arm/disarm API endpoints
- Update /api/security endpoint to return armed_at timestamp
- Add tracker tests for blob lifecycle callbacks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 10:14:51 -04:00
jedarden
80ac99ca7c feat: implement security mode dashboard UI
- Add security status indicator in status bar with mode badge
  (DISARMED / LEARNING / ARMED / ALERT)
- Add arm/disarm toggle button with confirmation dialog
- Add learning period progress bar display
- Add alert banner for anomalies when armed
- Add acknowledge functionality for anomalies
- Integrate with WebSocket for real-time updates
- Add security.css with responsive styles

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 10:14:51 -04:00
Argo Workflows CI
3e561593cf ci: auto-bump version to 0.1.49 2026-04-07 13:55:07 +00:00
jedarden
01547269cc feat: verify dashboard WebSocket feed supports events, alerts, BLE, triggers, health
All 5 new message types (event, alert, ble_scan, trigger_state,
system_health) were already implemented in hub.go with broadcast methods,
called from main.go/ingestion/volume_triggers/events, and handled in
app.js. Also includes security mode persistence from anomaly DB and
OpenAPI docs for triggers endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 09:54:14 -04:00
Argo Workflows CI
6a57997ec5 ci: auto-bump version to 0.1.48 2026-04-07 13:36:58 +00:00
jedarden
fe68bb5fdc feat: implement BLE Devices REST endpoints with OpenAPI docs
- GET /api/ble/devices: list all BLE devices with filtering
- PUT /api/ble/devices/{mac}: update device label and assign to person
- Added comprehensive OpenAPI-style godoc comments
- Supports filtering by registered/discovered/archived status
- Includes device history and aliases endpoints
2026-04-07 09:36:32 -04:00
Argo Workflows CI
dcd0b4e71c ci: auto-bump version to 0.1.47 2026-04-07 13:31:19 +00:00
jedarden
56c28bce63 feat: implement BLE Devices REST endpoints with OpenAPI docs
- Add GET /api/ble/devices to list known devices with filtering
- Add PUT /api/ble/devices/{mac} to set label and assign to person
- Add comprehensive OpenAPI-style godoc comments for all BLE endpoints
- Add table-driven tests for BLE handler endpoints

Endpoints support:
  - Filtering by registration status (registered/discovered)
  - Time window filtering (hours parameter)
  - Device labels and person assignment
  - Sighting history per device

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 09:30:55 -04:00
Argo Workflows CI
52aeb7a6ef ci: auto-bump version to 0.1.46 2026-04-07 13:19:49 +00:00
jedarden
a873663cfc feat: implement Replay/Time-Travel REST endpoints
Add OpenAPI-style godoc comments and comprehensive table-driven tests
for replay endpoints:
- GET /api/replay/sessions - list recording sessions and replay store info
- POST /api/replay/start - start replay at timestamp (speed 1/2/5)
- POST /api/replay/stop - stop replay, return to live
- POST /api/replay/seek - seek within session
- POST /api/replay/tune - update pipeline parameters mid-replay

Improvements:
- Fix writeJSON calls to use proper 3-argument signature
- Add detailed request/response type documentation
- Add mockRecordingStore for isolated unit testing
- Add 12 table-driven test cases covering all endpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 09:19:36 -04:00
Argo Workflows CI
12efb9a097 ci: auto-bump version to 0.1.45 2026-04-07 13:11:22 +00:00
jedarden
86a373debb feat: implement Notifications REST endpoints
- GET /api/notifications/config to get all delivery channel settings
- POST /api/notifications/config to set channel configurations
- POST /api/notifications/test to send test notifications
- Support for ntfy, pushover, gotify, webhook, and mqtt channel types
- Config validation for each channel type
- Table-driven tests for all endpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 09:11:01 -04:00
Argo Workflows CI
d9f58ab79a ci: auto-bump version to 0.1.44 2026-04-07 13:05:36 +00:00
jedarden
72b340d03a feat: implement Settings REST endpoints
Implement GET and POST/PATCH /api/settings endpoints with:

- GET /api/settings: Returns all configurable settings as JSON with
  default values merged in for any settings not explicitly set

- POST/PATCH /api/settings: Partial update with merge semantics,
  only updating the keys provided in the request body

- SQLite persistence: Settings stored in settings table with
  JSON-encoded values, loaded on startup

- Comprehensive validation: All known settings validated with
  proper range checks (fusion_rate_hz, grid_cell_m, delta_rms_threshold,
  tau_s, fresnel_decay, n_subcarriers, breathing_sensitivity,
  motion_threshold, dwell_seconds, vacant_seconds, max_tracked_blobs,
  replay_retention_hours, replay_max_mb, security_mode,
  events_archive_days)

- OpenAPI-style godoc comments: Documentation for all endpoints
  using swagger annotations

- Table-driven tests: Comprehensive test coverage for all
  functionality including GET, POST, PATCH, validation,
  persistence, and error cases

- Helper utilities: Extracted writeJSON, writeJSONError,
  writeJSONData to utils.go for reuse

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 09:04:55 -04:00
Argo Workflows CI
827d35002b ci: auto-bump version to 0.1.43 2026-04-07 12:47:12 +00:00
jedarden
9f3099e86a test: add table-driven tests for BroadcastSystemHealth WebSocket messages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 08:46:48 -04:00
Argo Workflows CI
9b4876ab05 ci: auto-bump version to 0.1.42 2026-04-07 12:41:47 +00:00
jedarden
5b24192186 feat: add trigger_state WebSocket message type to /ws/dashboard feed
Broadcasts { type: 'trigger_state', trigger: { id, name, last_fired, enabled } }
on trigger fire, enable, and disable events. Handled in app.js onmessage
and forwarded to window.Automations.updateTriggerState().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 08:41:17 -04:00
Argo Workflows CI
8e763b8ec2 ci: auto-bump version to 0.1.41 2026-04-07 12:13:06 +00:00
jedarden
0849be713f feat: wire BLE handler in ingestion server for ble_scan broadcast
The BLE handler was set but never invoked when BLE messages arrived
from nodes. Replace the TODO with actual bleHandler call so BLE scan
data flows to the registry, enabling the existing 5s ble_scan
WebSocket broadcast to dashboard clients.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 08:12:27 -04:00
jedarden
653c642108 fix: align BroadcastEventFromDB field names with frontend event spec
BroadcastEventFromDB was using inconsistent field names (timestamp_ms,
type, person) that didn't match the canonical event format (ts, kind,
person_name) expected by handleEventMessage in app.js. This caused
DB-sourced events to render with "undefined" kind/person and "Invalid
Date" timestamps.

Also adds table-driven tests for BroadcastEventFromDB covering zone
entry/exit, portal crossing, anomaly, and minimal events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 08:12:27 -04:00
Argo Workflows CI
3cb62609c0 ci: auto-bump version to 0.1.40 2026-04-07 11:57:59 +00:00
jedarden
54f9d29d54 test: add table-driven tests for BroadcastEvent WebSocket messages
Add TestHub_BroadcastEvent covering all event kinds (zone_entry,
zone_exit, portal_crossing, presence_transition). Also wire
presence_transition broadcasts in the ingestion server when
motion state changes on a link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 07:57:38 -04:00
jedarden
b2d733227b feat: wire BLE scan broadcasts to dashboard WebSocket
Connect bleRegistry to the dashboard hub so ble_scan messages are
broadcast every 5s to all connected dashboard clients. Add rssi,
last_seen, and blob_id fields to GetCurrentDevices output to match
the frontend's expected message format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 07:57:38 -04:00
Argo Workflows CI
92bb8750b7 ci: auto-bump version to 0.1.39 2026-04-07 11:24:52 +00:00
jedarden
32c92f2027 feat: broadcast ble_scan messages to dashboard every 5s
Add a 5-second ticker in the dashboard hub that broadcasts BLE device
list updates as typed 'ble_scan' messages when devices are present.
The BroadcastBLEScan method and frontend handler already existed but
were never wired up to a periodic timer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 07:24:19 -04:00
Argo Workflows CI
a1d96522bf ci: auto-bump version to 0.1.38 2026-04-07 10:58:01 +00:00
jedarden
93735f70bf feat: wire alert broadcasts for anomaly detections and security mode changes
- Connect anomaly detector callbacks to BroadcastAlert for dashboard alerts
- Add security mode change callback to broadcast typed alerts
- Add blob appeared/disappeared callbacks to Tracker
- Add alert tracking state (alerts Map, unacknowledgedCount) in dashboard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 06:57:23 -04:00
Argo Workflows CI
76f25c966e ci: auto-bump version to 0.1.37 2026-04-07 10:45:25 +00:00
jedarden
30327ce6f2 test: add table-driven tests for BroadcastAlert WebSocket messages
Verify the alert message format {type:'alert', alert:{id,ts,severity,description,acknowledged}}
for anomaly detections and security mode triggers. The BroadcastAlert function and
app.js handler already existed; this adds coverage for critical anomaly, security
mode armed/disarmed, and acknowledged alert scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 06:44:57 -04:00
Argo Workflows CI
5776f8f06c ci: auto-bump version to 0.1.36 2026-04-07 07:04:04 +00:00