feat: business analytics expansion, driver CSV import, live DB state docs #1

Merged
kianiadee merged 11 commits from quality-program-2026-04-12 into main 2026-04-18 06:04:11 +00:00

11 commits

Author SHA1 Message Date
David Kiania
274473c544 docs: update analytics report with live DB state (18 Apr 2026)
Some checks failed
Static Analysis / static (push) Waiting to run
Tests / test (push) Waiting to run
Static Analysis / static (pull_request) Has been cancelled
Tests / test (pull_request) Has been cancelled
- §1: add current deployment state table — 63 devices, 0 driver names,
  5 trips, pipeline stopped 6 Apr (401 token expiry); note tracksolid_2
  vs tracksolid schema split
- §6: status column per question (Ready/Needs data/Blocked) reflecting
  actual DB state; add cost-per-ticket, city drift, odometer rows
- §8: add Step 0 full deployment sequence (git pull → migrations 01-06
  → container rebuild → sync_driver_audit → import_drivers_csv);
  Step 3 updated to reference import script; Step 5 collapsed to pointer
- Footer: db-state stamp and update date

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 08:39:58 +03:00
David Kiania
cebcf74ba2 feat: business analytics expansion + driver CSV import
- 01_BusinessAnalytics.md: add §0 usage tags, §2.4 cost-per-ticket,
  §3.6–3.8 alarm/drift/odometer, §4.4–4.5 dispatch log + SLA metrics,
  §9 fleet readiness scorecard, §10 service-interval forecaster,
  Appendix B threshold calibration guide (773 → 1437 lines)

- 06_business_analytics_migration.sql: schema support for all new
  analytics sections — assigned_city column, dispatch_log table,
  ops schema, service_log, odometer_readings, tickets skeleton,
  vw_service_forecast view

- import_drivers_csv.py: one-shot script to populate driver_name,
  vehicle_number, vehicle_models, cost_centre, assigned_city, sim,
  iccid, imsi from 20260414_FS__Logistics - final_fixed.csv (144 rows);
  dry-run by default, --apply to commit, --only-null for safe additive mode

- 20260414_FS__Logistics - final_fixed.csv: source data committed for
  reproducibility and container exec workflow

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 08:30:34 +03:00
David Kiania
8867be9d3d perf+fix: SAVEPOINT-per-item pollers, batched GPS inserts, parallel detail fetch
Some checks are pending
Static Analysis / static (push) Waiting to run
Tests / test (push) Waiting to run
Audit fixes across the ingestion stack:

Observability
- Move log_ingestion out of batch loops in poll_alarms and poll_parking
  (was emitting N cumulative log rows per run instead of one).
- Add missing log_ingestion + t0 to poll_trips.
- Count inserted via cur.rowcount instead of naive +=1 so ON CONFLICT
  DO NOTHING no longer inflates the metric.

Resilience
- SAVEPOINT-per-item added to poll_alarms, poll_live_positions,
  poll_trips, poll_parking so one bad row no longer aborts the batch
  (webhook handlers already had this; pollers were inconsistent).

Performance
- /pushgps and poll_track_list now use psycopg2.extras.execute_values
  with ON CONFLICT DO NOTHING — 10-50x write throughput on larger
  batches.
- sync_devices and sync_driver_audit fetch jimi.track.device.detail
  concurrently via ThreadPoolExecutor(max_workers=8), cutting the
  daily registry sync from ~24s to ~3s for an 80-device fleet.
- poll_track_list split into two phases: parallel API fetch (4 workers,
  no DB connection held) then one batched write. Previously the DB
  connection was held across every per-IMEI HTTP call, risking pool
  starvation.

Security
- _validate_token uses hmac.compare_digest for constant-time token
  comparison (closes timing side-channel).
- _parse_data_list caps incoming items at WEBHOOK_MAX_ITEMS (default
  5000) so a pathological push cannot blow memory.

Tests
- Fix test_null_alarm_type_skipped: its INSERT-count assertion was
  catching the ingestion_log insert written by log_ingestion. Filter
  that out so the test checks only data-table inserts.
- Full suite: 66 passed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 00:33:55 +03:00
David Kiania
f7cc48cc6a chore: align .python-version to 3.12.0 (matches Docker image and pyproject.toml) 2026-04-12 21:41:43 +03:00
David Kiania
20d3ddb841 feat: add db_audit health checks, runner, and scheduled Forgejo workflow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 21:40:29 +03:00
David Kiania
6ed4d3a1e2 test: add test suite - unit tests, webhook endpoint tests, and CI workflow
57 unit tests covering clean helpers, API signing, and field mapping fixes
(FIX-E06, FIX-M16, BUG-01, BUG-03); integration tests for webhook endpoints
with mocked DB; Forgejo CI workflow with TimescaleDB service container.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 21:38:20 +03:00
David Kiania
2ca3d2f021 ci: add ruff + mypy static analysis config and Forgejo workflow 2026-04-12 21:32:33 +03:00
David Kiania
75d3417a2b docs: add quality program design spec 2026-04-12 21:31:56 +03:00
David Kiania
f9834564ab Add CLAUDE.md and project docs for structured Claude project
CLAUDE.md: cached context file covering project identity, tech stack,
codebase map, schema quick-ref, API gotchas, fix history, working rules,
fleet state, and open items. Structured for maximum cache efficiency —
stable content first, dynamic state at the end.

docs/CONNECTIONS.md: connection parameter shapes (no secrets) for SSH,
DB, API, container resolution, Forgejo, Grafana, n8n.

docs/PROJECT_CONTEXT.md: client business context (telco field service,
3 cities, service types), data quality gaps, KPI framework by domain,
integration roadmap.

docs/KPI_FRAMEWORK.md: living KPI register with status tracking,
thresholds, client feedback log, and review checklist. To be co-developed
with client iteratively.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 20:59:15 +03:00
David Kiania
2131faf8c6 Add 260412 baseline report — first trip data, FIX-M16 confirmed
Post-deployment snapshot at ~00:15 EAT 2026-04-12. Key changes vs 260410:
- 3 trips recorded (FRED KMGW 538W HULETI, 6.94 km total) — pipeline validated
- FIX-M16 distance unit fix confirmed: implied speed matches API avgSpeed exactly
- 70 track_list fixes in 24h (was 13) — dense trail from active driving
- KDK 829A GP returned to primary depot from secondary Nairobi East cluster
- Uganda anomaly (X3-63282) persists — flagged for management
- Driver name root cause confirmed: not assigned in Tracksolid Pro UI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 00:14:27 +03:00
David Kiania
6a0ceb78dd Fix trip distance unit (metres→km) and full device sync on upsert
[FIX-M16] jimi.device.track.mileage returns distance in metres despite
docs claiming km. Confirmed: avgSpeed × runTimeSecond / 3600 = distance/1000.
poll_trips() now divides raw value by 1000 before storing as distance_km.
3 existing bad rows corrected in prod DB (distance_km / 1000).

[FIX-M17] sync_devices() ON CONFLICT clause was only updating 5 of 26
fields, silently dropping driver_phone, sim, iccid, vehicle_name, status
etc. on subsequent syncs. Expanded to update all device fields so driver
assignments made in Tracksolid Pro UI propagate to DB on next daily sync.

Add sync_driver_audit.py: one-shot script to compare API vs DB device
registry, report driver/IMEI gaps, and force a full field upsert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 00:06:57 +03:00