POLL-01 (FIX-M14): Add poll_track_list() calling jimi.device.track.list
- Runs every 30 min with 35-min lookback window (5-min overlap prevents gaps)
- Inserts all device waypoints into position_history with source='track_list'
- Increases position density from ~1/min to 2-6 fixes/min per active vehicle
- Single shared DB connection for all devices per cycle (efficient)
POLL-03 (FIX-M15): Add get_device_locations() utility function
- Calls jimi.device.location.get for up to 50 specific IMEIs on demand
- Used for alarm enrichment, stale device recovery, dashboard precision refresh
Manual updates:
- position_history section rewritten to document dual ingestion sources
- Three new queries: data density check, harsh driving detection, route trace
- Known Data Issues: issues 10 and 11 added and marked Fixed
- API coverage table updated to reflect all three endpoints now in use
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add sections 16–21: Daily, Weekly, Monthly, Quarterly analytics,
new table docs (device_events, fuel_readings, temperature_readings,
lbs_readings, geofences), and updated Known Data Issues
- Fix all distance queries: remove erroneous /1000000.0 division
(column is now distance_km in kilometres after migration 04)
- Update alarms section to reflect BUG-01 field mapping fix
- Update parking section to reflect POLL-02 acc_type/durSecond fix
- Rewrite "verify distance" section as accuracy cross-check query
- Expand row count query to include 5 new tables from migration 05
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BUG-01 [FIX-E06]: jimi.device.alarm.list poll response uses alertTypeId/
alarmTypeName/alertTime, not the webhook field names. All 1,054 stored alarm
records had null alarm_type/alarm_name as a result. Corrected field mapping
in ingest_events_rev.py; also added alarm_name and source columns to INSERT.
BUG-02 [FIX-M11/M12]: trips.distance_m was storing millimetres due to an
erroneous * 1000 on an already-km API value. Removed the multiplication in
poll_trips() and push_trip_report(). Column renamed to distance_km in
migration 04 (historical rows divided by 1,000,000 to correct to km).
All SQL in both ingestion files updated to reference distance_km.
POLL-02 [FIX-M13]: parking poll returned 0 rows because the required
account and acc_type=0 parameters were missing. Also fixed response field
mapping: durSecond was incorrectly read as 'seconds'.
Migration 04: corrects and renames distance_m → distance_km.
Migration 05: adds normalized OBD columns, alarm/device enrichment columns,
new tables (device_events, fuel_readings, temperature_readings, lbs_readings,
geofences), expands dwh_gold fact table, and adds refresh_daily_metrics() ETL.
tracksolid_DB_manual.md updated to reflect column rename and mark fixed issues.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers pre-deployment checklist, post-deploy verification steps for each
panel, database verification queries, troubleshooting guide, and
day-to-day NOC operations reference.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a fully-provisioned Grafana dashboard for NOC operators to monitor
80 vehicles in real-time: live geomap with direction arrows, speed, driver
info, and color-coded plates. Includes datasource and dashboard provider
YAMLs, dashboard JSON (schemaVersion 39 / Grafana 11.0.0), and
docker-compose updates to mount provisioning at container start.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Port 8000 was already in use on the host. Updated uvicorn to listen
on 8888. Added 6 importable n8n workflow JSON files for Jimi push
data forwarding (OBD, faults, alarms, GPS, heartbeats, trips).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comprehensive guide covering:
- Service architecture and scheduled tasks
- Per-service verification SQL queries grouped by service
- Health dashboard queries for monitoring
- Polling vs push coexistence and dedup strategy
- Environment variables, data retention, troubleshooting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dict.get("result", []) returns None when key exists with null value.
Changed to resp.get("result") or [] which handles both cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change image from timescaledb-ha:pg16-ts2.15-oss to pg16-ts2.15
(OSS edition lacks compression, retention, continuous aggregates)
- Add postgresql-client to Dockerfile for psql binary
- Rewrite run_migrations.py to use psql instead of psycopg2
(psql runs each statement independently; psycopg2 wraps the
entire file in one transaction so one error rolls back everything)
- Add schema verification: exits 1 if critical tables missing,
preventing services from starting with broken schema
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Coolify doesn't support service_completed_successfully dependency.
Each Python service now runs 'python run_migrations.py' before its
main process. SQL is idempotent so concurrent runs are safe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New run_migrations.py: executes 02_*.sql and 03_*.sql in order
- New db_migrate service: runs once before all other services start
- All services now depend on db_migrate (service_completed_successfully)
- Tolerates re-deploy: catches errors from already-existing objects
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port 8000 was already allocated on the host. On Coolify, Traefik routes
external traffic to the container internally — no host port needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>