diff --git a/CLAUDE.md b/CLAUDE.md
index 5ad556c..9718983 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -56,7 +56,7 @@ See `docs/CONNECTIONS.md` for the full shape. Summary:
- **SSH:** `ssh -i ~/.ssh/id_ed25519 kianiadee@stage.rahamafresh.com`
- **DB name:** `tracksolid_db` · **DB user:** `postgres` (internal) · `tracksolid_owner` (app) · `grafana_ro` (read-only)
-- **DB schemas:** `tracksolid` (live, single source of truth) · `dwh_gold` (aggregates) · `ops` (workshop / tickets / odometer) · `infrastructure`. The legacy `tracksolid_2` schema no longer exists — migrations 02–06 applied 2026-04-18.
+- **DB schemas:** `tracksolid` (live, single source of truth) · `reporting` (map-dashboard read layer) · `infrastructure`. The legacy `tracksolid_2` schema no longer exists (migrations 02–06, 2026-04-18); the `ops` and `dwh_gold` schemas were purged 2026-06-05 (migrations 12/13) as unused.
- **DB access:** `DATABASE_URL` points to `timescale_db:5432` (internal Docker network — not reachable locally). Use `docker exec` pattern above. See `docs/CONNECTIONS.md` for full reference.
- **DWH target DB:** `tracksolid_dwh` at `31.97.44.246:5888` (separate PostGIS instance, public IP). Users: `dwh_owner` (bronze writes + `dwh_control`), `grafana_ro` (reads bronze/silver/gold/`dwh_control`). Always connect with `sslmode=require`. Fed by the n8n `dwh_extract` + `dwh_load_bronze` workflows — see `docs/DWH_PIPELINE.md`.
- **Container naming:** Coolify appends a random suffix. Always resolve with:
@@ -93,10 +93,11 @@ dwh/ # DWH migrations for tracksolid_dwh@31.97.44.246:588
# 261002_bronze_constraints_audit.sql — ON CONFLICT key assertion
# 261003_dwh_roles.sql — role contract assertion
# 261004_dwh_observability_views.sql — freshness/failure views
-migrations/ # Numbered SQL migrations 02–10, applied in order by run_migrations.py
+migrations/ # Numbered SQL migrations 02–13, applied in order by run_migrations.py
# 02 full schema · 03 webhook · 04 distance fix · 05 enhancements
# 06 ops/analytics · 07 views · 08 config · 09 trips enrichment
- # 10_driver_clock_views.sql · 10_pgbouncer_auth.sql
+ # 10_driver_clock_views.sql · 10_pgbouncer_auth.sql · 11 reporting
+ # 12 drop ops schema · 13 drop dwh_gold schema (both 2026-06-05)
Dockerfile # Custom image for ingest/webhook containers
pyproject.toml # Python project + uv dependency spec
backup/ # pg_dump sidecar scripts and config
@@ -126,12 +127,13 @@ tracksolid.alarms -- Alarm events (alarm_type, alarm_name, alarm_time
tracksolid.obd_readings -- OBD diagnostics (push only, awaiting webhook registration)
tracksolid.device_events -- Power on/off tamper events (push only)
tracksolid.ingestion_log -- API call audit trail — 875 runs / 24h, 0 failures at last check (2026-04-19)
-tracksolid.dispatch_log -- Dispatch decisions for SLA tracking (migration 06; empty until ops integration)
-tracksolid.schema_migrations -- Applied files: 02,03,04,05,06 (last 06 on 2026-04-18)
-dwh_gold.fact_daily_fleet_metrics -- Nightly ETL aggregates per vehicle per day (run refresh_daily_metrics)
-ops.service_log -- Workshop service history (migration 06)
-ops.odometer_readings -- Physical odometer captures (migration 06)
-ops.tickets -- Ticket skeleton for ops integration (migration 06; empty)
+tracksolid.schema_migrations -- Applied migrations 02–13
+-- PURGED 2026-06-05 (migrations 12 + 13): the dormant `ops` schema (tickets, service_log,
+-- odometer_readings, cost_rates, kpi_targets, vw_service_forecast), tracksolid.dispatch_log,
+-- and the `dwh_gold` schema (dim_vehicles, fact_daily_fleet_metrics, refresh_daily_metrics).
+-- Those workshop/dispatch/SLA/utilisation features were never implemented. Do NOT reintroduce
+-- references to ops.* or dwh_gold.* — they no longer exist. (The separate tracksolid_dwh DB
+-- at 31.97.44.246:5888 is unrelated and untouched.)
```
Full DDL: `02_tracksolid_full_schema_rev.sql` + migrations `03`–`06`.
@@ -146,8 +148,8 @@ tracksolid.v_currently_idle -- §2.2 idle lens
tracksolid.v_driver_aggregates_daily -- §3.1 + §3.2 aggression index source
tracksolid.v_fleet_km_daily -- §7 Panel 5 distance trend
tracksolid.v_alarms_daily -- §7 Panel 7 alarm frequency
-tracksolid.v_utilisation_daily -- §7 Panel 8 utilisation heatmap (gated on dwh_gold ETL)
-tracksolid.v_sla_inflight -- §4.5 SLA panels (gated on ops.tickets)
+-- v_utilisation_daily (dwh_gold) and v_sla_inflight (ops) were DROPPED 2026-06-05 with
+-- their schemas (migrations 12/13); their Grafana panels were removed from the dashboard.
```
All views carry a `COMMENT ON VIEW` referencing their spec — `\d+ tracksolid.v_*` shows the provenance.
@@ -222,7 +224,7 @@ dwh_control.v_watermark_lag -- Grafana: extract vs. load lag per table
7. **Secrets from env only.** Connection strings, API keys, and passwords live in `.env`. Reference variable names from `docs/CONNECTIONS.md`, never values.
8. **Two developers, one incoming.** Write code and docs that a second developer (mixed technical/operations background) can follow without prior context.
9. **Forgejo API auth:** credentials stored in macOS keychain. Retrieve with `git credential fill` (host=repo.rahamafresh.com). Use basic auth against `https://repo.rahamafresh.com/api/v1` directly — no `tea` or `gh` needed.
-10. **Single live schema.** All live data lives in `tracksolid`. Aggregates live in `dwh_gold`; workshop/ticket integrations live in `ops`. Do not reintroduce references to the retired `tracksolid_2` schema.
+10. **Single live schema.** All live data lives in `tracksolid`; the map-dashboard read layer lives in `reporting`. Do not reintroduce references to the retired `tracksolid_2`, `ops`, or `dwh_gold` schemas (the latter two purged 2026-06-05, migrations 12/13).
---
@@ -256,6 +258,5 @@ Latest full snapshot: `docs/reports/260412_baseline_report.md`
| MEDIUM | Investigate 44 silent devices (only 19 of 63 reporting) — SIM installed? Activated? |
| MEDIUM | Co-develop client KPI framework (see `docs/KPI_FRAMEWORK.md`) |
| LOW | Populate geofences — depot boundaries, city zones |
-| LOW | Schedule nightly ETL: `SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1)` (cron or n8n) |
| HIGH | Deploy DWH bronze pipeline: apply `dwh/26100{1,2,3,4}.sql` to `tracksolid_dwh`, import + wire the two n8n workflows, verify first run via `dwh_control.v_table_freshness`. Runbook: `docs/DWH_PIPELINE.md` |
| MEDIUM | Rotate `dwh_owner` / `grafana_ro` passwords on `tracksolid_dwh` — plaintext in `dwh/260423_dwh_ddl_v1.sql` is a pre-existing flaw to clean up separately |
diff --git a/docs/DATA_FLOW.md b/docs/DATA_FLOW.md
new file mode 100644
index 0000000..1314cda
--- /dev/null
+++ b/docs/DATA_FLOW.md
@@ -0,0 +1,240 @@
+# Data Flow — Ingestion → Aggregation → Views → Functions → Consumers
+
+**Scope:** the *live* fleet pipeline only (`tracksolid` + `reporting`). The `ops` and
+`dwh_gold` schemas were **purged on 2026-06-05** (migrations 12/13) — those workshop /
+dispatch / SLA / utilisation features were never implemented. They are shown below only as
+a struck-out "removed" footnote for historical context. (The *separate* `tracksolid_dwh`
+server at 31.97.44.246:5888 is unrelated and was not touched.)
+
+**Verified against prod 2026-06-05** (TimescaleDB hypertable + continuous-aggregate
+catalog, `pg_depend` view graph, ingestion `INSERT` targets, `dashboard_api` queries,
+Grafana panel SQL). Key facts that surprised the docs:
+
+- Only `position_history` (and the empty/planned `heartbeats`, `fuel_readings`,
+ `temperature_readings`) are **hypertables**. `trips` and `alarms` are **plain tables**.
+- `tracksolid.v_mileage_daily_cagg` is a **real TimescaleDB continuous aggregate**, not a
+ plain view — and it currently has **no downstream consumer**.
+- `reporting.v_trips` is a **matview**, refreshed every 5 min by the in-process
+ `dashboard_api` background loop (FIX-D02), pg advisory-lock `920145`.
+
+---
+
+## Mermaid
+
+```mermaid
+flowchart TD
+ API["Tracksolid / Jimi API
poll + push webhooks · OAuth2"]
+
+ subgraph ING["Ingestion — ts_shared_rev.py: get_conn() · api_post() · clean*()"]
+ IM["ingest_movement_rev.py"]
+ IE["ingest_events_rev.py"]
+ WR["webhook_receiver_rev.py"]
+ end
+ API --> IM & IE & WR
+
+ subgraph L1["L1 · Base tables + hypertables — schema: tracksolid (single source of truth)"]
+ LP["live_positions
current fix / IMEI"]
+ PH[("position_history
HYPERTABLE · high-res GPS trail")]
+ TR["trips
plain table — NOT a hypertable"]
+ DV["devices
vehicle / driver registry"]
+ AL["alarms
plain table"]
+ ILOG["ingestion_log · api_token_cache"]
+ EMPTY["heartbeats* · fuel_readings* · temperature_readings* (HYPERTABLES, empty)
device_events · fault_codes · obd_readings · parking_events · lbs_readings · geofences (empty)"]
+ end
+ IM --> LP & PH & TR & DV
+ IM --> ILOG
+ IE --> AL
+ WR --> EMPTY
+
+ subgraph L2["L2 · Aggregation"]
+ CAGG[("v_mileage_daily_cagg
CONTINUOUS AGGREGATE")]
+ VT[("reporting.v_trips
MATVIEW · ix_v_trips_trip_id")]
+ RLOG["reporting.refresh_log"]
+ end
+ PH -->|Timescale cont-agg policy| CAGG
+ TR --> VT
+ DV --> VT
+ VT -->|"REFRESH CONCURRENTLY every 300s
(dashboard_api loop, adv-lock 920145)"| RLOG
+
+ subgraph L3L["L3 · Reporting views — fed by v_trips matview"]
+ FILT["v_filter_vehicles · v_filter_drivers
v_filter_cost_centres · v_filter_cities"]
+ SUMM["v_daily/weekly/monthly_summary
v_*_cost_centre · v_trips_today"]
+ VLP["v_live_positions"]
+ end
+ VT --> FILT & SUMM
+ LP --> VLP
+
+ subgraph L3R["L3 · Grafana views — tracksolid.* (read base tables directly)"]
+ GV["v_fleet_today · v_fleet_status · v_active_dispatch_map
v_currently_idle · v_alarms_daily · v_fleet_km_daily
v_ingestion_health · v_vehicles_not_moved_today
v_driver_aggregates_daily · v_fleet_trace · v_driver_clock_*"]
+ end
+ LP --> GV
+ TR --> GV
+ DV --> GV
+ AL --> GV
+ PH --> GV
+
+ subgraph L4["L4 · Functions — reporting.* (the only API entrypoints)"]
+ FLP["fn_live_positions(cost_centre, acc_status)"]
+ FVT["fn_vehicle_track(vehicle_number, hours)"]
+ FTM["fn_trips_for_map(veh[], driver, cc, city, start, end)"]
+ NP["normalize_plate(p) · helper"]
+ end
+ LP --> FLP
+ DV --> FLP
+ PH --> FVT
+ VT --> FTM
+ NP -.-> FTM
+
+ subgraph L5["L5 · Consumers"]
+ DAPI["dashboard_api_rev.py
FastAPI :8890 · 2 workers"]
+ SPA["SPAs: liveposition.* · fleetintelligence.*
(rustfs / S3 single-file maps)"]
+ GRAF["Grafana"]
+ end
+ FLP --> DAPI
+ FVT --> DAPI
+ FTM --> DAPI
+ FILT --> DAPI
+ DAPI -->|"HTTPS · fleetapi.rahamafresh.com"| SPA
+ GV --> GRAF
+
+ CAGG -.->|no consumer yet| NONE(["⚠ unconsumed — no panel / API reads it"])
+
+ subgraph PARK["REMOVED 2026-06-05 — purged via migrations 12 / 13 (never implemented)"]
+ GONE["ops.* (tickets · dispatch_log · service_log · odometer_readings · cost_rates · kpi_targets · vw_service_forecast)
dwh_gold.* (dim_vehicles · fact_daily_fleet_metrics · refresh_daily_metrics)
tracksolid.v_sla_inflight · tracksolid.v_utilisation_daily + their Grafana panels"]
+ end
+
+ classDef hyper fill:#e1f0ff,stroke:#3b82f6,color:#0b3d91;
+ classDef mat fill:#fff3cd,stroke:#d4a017,color:#664d03;
+ classDef cagg fill:#e7f7e7,stroke:#2e9e2e,color:#1e5e1e;
+ classDef parked fill:#f0f0f0,stroke:#999,stroke-dasharray:5 5,color:#555;
+ classDef warn fill:#fdecea,stroke:#d93025,color:#a52714;
+ class PH hyper;
+ class VT mat;
+ class CAGG cagg;
+ class PARK,GONE parked;
+ class NONE warn;
+```
+
+---
+
+## ASCII
+
+```
+ ╔══════════════════════════════════════════════╗
+ ║ TRACKSOLID / JIMI API ║
+ ║ (poll + push webhooks, OAuth2) ║
+ ╚════════════════════╤═════════════════════════╝
+ │
+ ┌──────────────────────────┬───────────┴───────────┬────────────────────────────┐
+ ▼ ▼ ▼ ▼
+┌─────────────────┐ ┌────────────────────┐ ┌──────────────────────┐
+│ ingest_movement │ │ ingest_events │ │ webhook_receiver │ (all via ts_shared_rev.py:
+│ _rev.py │ │ _rev.py │ │ _rev.py │ get_conn() pool, api_post(),
+└────────┬────────┘ └─────────┬──────────┘ └──────────┬───────────┘ clean*() , token cache)
+ │ │ │
+ │ writes │ writes │ writes (push)
+ ▼ ▼ ▼
+╔════════════════════════════════════════════════════════════════════════════════════════════╗
+║ L1 · BASE TABLES + HYPERTABLES schema: tracksolid (single source of truth) ║
+║ ║
+║ live_positions ── current fix / IMEI (plain) api_token_cache (auth) ║
+║ position_history ◀═══ HYPERTABLE (high-res GPS trail, partitioned by gps_time) ║
+║ trips ── trip summaries (plain table — NOT a hypertable) ║
+║ devices ── vehicle/driver registry (plain) ║
+║ alarms ── alarm events (plain table) ║
+║ ingestion_log ── API audit trail (plain) ║
+║ heartbeats*, fuel_readings*, temperature_readings* ◀═ HYPERTABLES (empty / planned push) ║
+║ device_events, fault_codes, obd_readings, parking_events, lbs_readings, geofences (empty) ║
+╚══════╤══════════════════════════╤══════════════════════════════════╤════════════════════════╝
+ │ │ │
+ │ TimescaleDB │ matview refresh │ direct reads
+ │ cont-agg policy │ (in-app loop) │ (Grafana SQL)
+ ▼ ▼ ▼
+╔══════════════════╗ ╔════════════════════════════════╗ ╔══════════════════════════════════╗
+║ L2 · AGGREGATION ║ ║ L2 · AGGREGATION (matview) ║ ║ L3 · GRAFANA VIEWS (tracksolid.*) ║
+║ ║ ║ ║ ║ read base tables directly ║
+║ v_mileage_daily ║ ║ reporting.v_trips [MATVIEW] ║ ║ ║
+║ _cagg ║ ║ ◀── trips + devices ║ ║ v_fleet_today v_fleet_status ║
+║ CONTINUOUS AGG ║ ║ unique ix_v_trips_trip_id ║ ║ v_active_dispatch_map ║
+║ ◀═ position_ ║ ║ ║ ║ v_currently_idle v_alarms_daily ║
+║ history ║ ║ REFRESH … CONCURRENTLY every ║ ║ v_fleet_km_daily v_ingestion_health║
+║ (auto refresh ║ ║ VTRIPS_REFRESH_INTERVAL_S=300 ║ ║ v_vehicles_not_moved_today ║
+║ policy) ║ ║ by dashboard_api bg asyncio ║ ║ v_driver_aggregates_daily ║
+╚════════╤═════════╝ ║ loop, pg advisory-lock 920145 ║ ║ v_fleet_trace ║
+ │ ║ │ ║ ║ v_driver_clock_daily/_today/_attnd ║
+ │ ║ └──▶ reporting.refresh_log ║ ╚══════════════╤═════════════════════╝
+ │ ╚═══════════════╤════════════════╝ │
+ │ │ │
+ │ ▼ │
+ │ ╔════════════════════════════════════════════╗ │
+ │ ║ L3 · REPORTING VIEWS (← v_trips matview) ║ │
+ │ ║ v_filter_vehicles v_filter_drivers ║ │
+ │ ║ v_filter_cost_centres v_filter_cities ║ │
+ │ ║ v_daily/weekly/monthly_summary ║ │
+ │ ║ v_*_cost_centre v_trips_today ║ │
+ │ ║ v_live_positions (view, ← live_positions) ║ │
+ │ ╚════════════════════════╤═══════════════════╝ │
+ │ │ │
+ │ ╔══════════════════════════════════╧═══════════════════╗ │
+ │ ║ L4 · FUNCTIONS (schema reporting — API entrypoints) ║ │
+ │ ║ ║ │
+ │ ║ fn_live_positions(cost_centre, acc_status) ║ │
+ │ ║ ◀── live_positions + devices ║ │
+ │ ║ fn_vehicle_track(vehicle_number, hours) ║ │
+ │ ║ ◀── position_history (hypertable trail) ────────╫─────┘ (also reads L1)
+ │ ║ fn_trips_for_map(veh[],driver,cc,city,start,end) ║
+ │ ║ ◀── reporting.v_trips (matview) ║
+ │ ║ normalize_plate(p) ── helper used by the above ║
+ │ ╚════════════════════════════╤══════════════════════════╝
+ │ │
+ ▼ ▼
+ (cagg currently ╔═══════════════════════════════════════════════╗
+ unconsumed — ║ L5 · CONSUMERS ║
+ no panel/API yet) ║ ║
+ ║ dashboard_api_rev.py (FastAPI :8890, ×2 wkrs) ║
+ ║ POST /webhook/fleet-dashboard → fn_trips_for_map + v_filter_*
+ ║ GET /webhook/live-positions → fn_live_positions
+ ║ GET /webhook/live-positions/track → fn_vehicle_track
+ ║ │ ║
+ ║ ▼ HTTPS (fleetapi.rahamafresh.com) ║
+ ║ SPAs: liveposition.* · fleetintelligence.* ║
+ ║ (rustfs/S3 single-file maps) ║
+ ║ ║
+ ║ Grafana ──SQL──▶ tracksolid.v_* (L3 right) ║
+ ╚═══════════════════════════════════════════════╝
+
+
+ ┌─ REMOVED 2026-06-05 · purged via migrations 12 / 13 (never implemented) ───────────────┐
+ │ ops.* : tickets, dispatch_log, service_log, odometer_readings, │
+ │ cost_rates, kpi_targets, vw_service_forecast │
+ │ dwh_gold.* : dim_vehicles, fact_daily_fleet_metrics, refresh_daily_metrics() │
+ │ tracksolid : v_sla_inflight, v_utilisation_daily (+ their Grafana panels removed) │
+ │ → Schemas dropped from prod. The separate tracksolid_dwh server is unrelated/untouched.│
+ └────────────────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## How to read it
+
+- **L1** is where ingestion lands. Only `position_history` (and three empty/planned
+ hypertables) are TimescaleDB hypertables; `trips`/`alarms` are ordinary tables.
+- **Two aggregation mechanisms** run in parallel: the TimescaleDB **continuous aggregate**
+ `v_mileage_daily_cagg` (refreshed by a Timescale policy off `position_history`), and the
+ **`reporting.v_trips` matview** (refreshed every 5 min by the in-process `dashboard_api`
+ loop — the FIX-D02 self-refresher that replaced the dead n8n job).
+- **L4 functions are the only thing the API calls.** SPAs never touch tables directly:
+ SPA → `dashboard_api` → `fn_*` → (matview / tables).
+- **Grafana** takes the right-hand path, reading the `tracksolid.v_*` analytics views
+ straight off L1.
+
+## Caveats / housekeeping notes
+
+1. **`v_mileage_daily_cagg` has no consumer** — nothing in the API or Grafana reads it. It
+ is a live continuous aggregate maintaining itself for nobody. Candidate for removal or
+ wiring into a panel.
+2. **`ops` and `dwh_gold` were purged** (2026-06-05, migrations 12/13) along with
+ `v_utilisation_daily`, `v_sla_inflight`, and their Grafana panels — the features were
+ never implemented.
+3. See the companion housekeeping audit (2026-06-05) for the full unused-object list; the
+ only clean ad-hoc drop is `public.trips_viz_v1`.
diff --git a/docs/PLATFORM_OVERVIEW.html b/docs/PLATFORM_OVERVIEW.html
index 600e3b4..a4ad785 100644
--- a/docs/PLATFORM_OVERVIEW.html
+++ b/docs/PLATFORM_OVERVIEW.html
@@ -84,7 +84,7 @@ proxy container. The dashboard_api enforces CORS for both SPA origins.
dashboard_api_rev.py bind-mounted. The durable form is the compose dashboard_api service
(already in docker-compose.yaml) once the branch is merged and the fleetapi domain is set in Coolify.Base: https://fleetapi.rahamafresh.com · all responses JSON · CORS limited to the two SPA origins.
| Method | Path | Params | Returns | Notes |
|---|---|---|---|---|
| GET | /health | — | {status: ok} | Liveness probe. |
| GET | /webhook/live-positions | cost_centre?, acc_status? | {summary, geojson} | Live Positions map feed → reporting.fn_live_positions. ~80 vehicle point features. |
| GET | /webhook/live-positions/track | vehicle_number, hours(1-24) | GeoJSON Feature (LineString) | One vehicle's recent trail. Alias: /webhook/vehicle-track. |
| GET | /webhook/vehicle-track | vehicle_number, hours | GeoJSON Feature | Alias of live-positions/track (kept for compatibility). |
| GET | /webhook/fleet-dashboard | — | {drivers, cost_centres, cities, vehicles} | Filter options for the Fleet Intelligence UI. |
| POST | /webhook/fleet-dashboard | form-urlencoded: period|start_date|end_date, vehicle_numbers, driver, cost_centre, assigned_city | trips GeoJSON payload | Trips for the map → reporting.fn_trips_for_map. period preset: today|7d|30d|custom. Body parsed by Content-Type — the SPA posts application/x-www-form-urlencoded; JSON also accepted. |
x-www-form-urlencoded; the mismatch silently dropped every filter so the map always returned the whole fleet. Now parsed by Content-Type (parse_qs for form bodies). Commit f1387d1.18 table(s) · 17 view(s) · 1 function(s) documented.
Alarm events (alarm_type, alarm_name, alarm_time).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('alarms_id_seq'::regclass) | |
| imei | text | |||
| alarm_type | text | |||
| alarm_time | timestamp with time zone | |||
| geom | geometry(Point,4326) | |||
| lat | double precision | |||
| lng | double precision | |||
| speed | numeric(7,2) | |||
| acc_status | text | |||
| updated_at | timestamp with time zone | now() | ||
| alarm_name | text | |||
| source | text | 'poll'::text | ||
| severity | text | Alarm severity level: critical | warning | info | ||
| geofence_id | text | Tracksolid geofence ID if this is a geofence alarm | ||
| geofence_name | text | Human-readable geofence name | ||
| acknowledged_at | timestamp with time zone | Timestamp when alarm was acknowledged by an operator | ||
| acknowledged_by | text | Username or ID of operator who acknowledged the alarm |
OAuth2 token cache for the Jimi/Tracksolid API.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('api_token_cache_id_seq'::regclass) | |
| account | text | NOT NULL | ||
| access_token | text | NOT NULL | ||
| refresh_token | text | |||
| app_key | text | |||
| expires_at | timestamp with time zone | NOT NULL | ||
| obtained_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() |
Device network connection and disconnection events from /pushevent webhook.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('device_events_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| event_type | text | NOT NULL | LOGIN = device connected to network; LOGOUT = device disconnected | |
| event_time | timestamp with time zone | NOT NULL | ||
| timezone | text | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| device_name | text | |||
| mc_type | text | |||
| mc_type_use_scope | text | |||
| vehicle_name | text | |||
| vehicle_number | text | |||
| vehicle_models | text | |||
| vehicle_icon | text | |||
| vin | text | |||
| engine_number | text | |||
| vehicle_brand | text | |||
| fuel_100km | numeric(6,2) | |||
| driver_name | text | |||
| driver_phone | text | |||
| sim | text | |||
| iccid | text | |||
| imsi | text | |||
| account | text | |||
| customer_name | text | |||
| device_group_id | text | |||
| device_group | text | |||
| activation_time | timestamp with time zone | |||
| expiration | timestamp with time zone | |||
| enabled_flag | smallint | NOT NULL | 1 | |
| status | text | 'active'::text | ||
| city | text | |||
| current_mileage_km | numeric(12,2) | |||
| created_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() | |
| last_synced_at | timestamp with time zone | |||
| vehicle_category | text | Vehicle type: truck | van | motorcycle | car | other | ||
| cost_centre | text | Business unit or department this vehicle belongs to | ||
| assigned_route | text | Regular route name or ID for route-based reporting | ||
| depot_geom | geometry(Point,4326) | Home base/depot coordinates (WGS84) | ||
| depot_address | text | Human-readable depot address | ||
| assigned_city | text | Operating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection. |
Persistent record of every dispatch decision. Powers SLA metrics: dispatch latency, depart delay, time-to-site, wrench time.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| dispatch_id | bigint | NOT NULL | nextval('dispatch_log_dispatch_id_seq'::regclass) | |
| ticket_id | text | NOT NULL | ||
| imei | text | NOT NULL | ||
| driver_name | text | |||
| job_lat | double precision | NOT NULL | ||
| job_lng | double precision | NOT NULL | ||
| job_geom | geometry(Point,4326) | |||
| assigned_at | timestamp with time zone | NOT NULL | now() | |
| first_movement_at | timestamp with time zone | First trip start after assigned_at. Back-filled nightly from trips. | ||
| on_site_at | timestamp with time zone | Time vehicle entered 150 m radius of job_geom. Back-filled nightly. | ||
| resolved_at | timestamp with time zone | Ticket close time from the ops system (ops.tickets.closed_at). | ||
| cancelled_at | timestamp with time zone | |||
| distance_km | numeric(8,2) | |||
| created_at | timestamp with time zone | NOT NULL | now() |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('fault_codes_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| reported_at | timestamp with time zone | NOT NULL | ||
| fault_code | text | NOT NULL | ||
| status_flags | integer | |||
| lat | double precision | |||
| lng | double precision | |||
| geom | geometry(Point,4326) | |||
| event_time | timestamp with time zone | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| reading_time | timestamp with time zone | NOT NULL | ||
| sensor_path | text | Sensor channel identifier from the device (path field in API payload) | ||
| value | numeric(10,3) | |||
| unit | text | Measurement unit: cm (tank depth), % (percentage), V (voltage), L (litres) | ||
| lat | double precision | |||
| lng | double precision | |||
| geom | geometry(Point,4326) | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Geofence boundary definitions synced from the Tracksolid platform.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('geofences_id_seq'::regclass) | |
| fence_id | text | |||
| fence_name | text | NOT NULL | ||
| fence_type | text | circle | polygon | ||
| geom | geometry(Geometry,4326) | |||
| radius_m | numeric(10,2) | Radius in metres — only applicable for circle type geofences | ||
| description | text | |||
| created_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() |
Device heartbeat hypertable.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| gate_time | timestamp with time zone | NOT NULL | ||
| power_level | smallint | |||
| gsm_signal | smallint | |||
| acc_status | smallint | |||
| power_status | smallint | |||
| fortify | smallint | |||
| created_at | timestamp with time zone | NOT NULL | now() |
API call audit trail — one row per ingestion run.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('ingestion_log_id_seq'::regclass) | |
| run_at | timestamp with time zone | NOT NULL | now() | |
| endpoint | text | NOT NULL | ||
| imei_count | integer | NOT NULL | 0 | |
| rows_upserted | integer | NOT NULL | 0 | |
| rows_inserted | integer | NOT NULL | 0 | |
| duration_ms | integer | NOT NULL | 0 | |
| success | boolean | NOT NULL | true | |
| error_code | text | |||
| error_message | text |
Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('lbs_readings_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| gate_time | timestamp with time zone | NOT NULL | ||
| post_type | text | Positioning technology: WIFI | LBS (cell tower) | ||
| lbs_data | jsonb | Raw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding. | ||
| created_at | timestamp with time zone | NOT NULL | now() |
Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| geom | geometry(Point,4326) | |||
| lat | double precision | |||
| lng | double precision | |||
| pos_type | text | |||
| confidence | smallint | |||
| gps_time | timestamp with time zone | |||
| hb_time | timestamp with time zone | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| acc_status | text | |||
| gps_signal | smallint | |||
| gps_num | smallint | |||
| elec_quantity | numeric(5,2) | |||
| power_value | numeric(5,2) | |||
| battery_power_val | numeric(5,2) | |||
| tracker_oil | text | |||
| temperature | numeric(8,2) | |||
| current_mileage | numeric(12,2) | |||
| device_status | text | |||
| expire_flag | text | |||
| activation_flag | text | |||
| loc_desc | text | |||
| recorded_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() |
OBD diagnostics — push only via /pushobd webhook.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('obd_readings_id_seq'::regclass) | |
| imei | text | |||
| reading_time | timestamp with time zone | |||
| engine_rpm | integer | Engine RPM from OBD PID 0x0C | ||
| fuel_level_pct | numeric(5,2) | Fuel tank level % from OBD PID 0x2F | ||
| updated_at | timestamp with time zone | now() | ||
| car_type | smallint | |||
| acc_state | smallint | |||
| status_flags | integer | |||
| lat | double precision | |||
| lng | double precision | |||
| geom | geometry(Point,4326) | |||
| obd_data | jsonb | Raw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.) | ||
| coolant_temp_c | numeric(6,2) | Coolant temperature °C from OBD PID 0x05 | ||
| battery_voltage | numeric(5,2) | Battery voltage (V) from OBD PID 0x42 | ||
| intake_pressure | numeric(6,2) | Intake manifold pressure kPa from OBD PID 0x0B | ||
| throttle_pct | numeric(5,2) | Throttle position % from OBD PID 0x11 | ||
| vehicle_speed | numeric(7,2) | Vehicle speed km/h from OBD PID 0x0D | ||
| engine_load_pct | numeric(5,2) | Calculated engine load % from OBD PID 0x04 |
Stop events with duration + address.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('parking_events_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| event_type | text | |||
| start_time | timestamp with time zone | NOT NULL | ||
| end_time | timestamp with time zone | |||
| duration_seconds | integer | |||
| geom | geometry(Point,4326) | |||
| address | text | |||
| updated_at | timestamp with time zone | now() |
All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| gps_time | timestamp with time zone | NOT NULL | ||
| geom | geometry(Point,4326) | |||
| lat | double precision | |||
| lng | double precision | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| acc_status | text | |||
| satellite | smallint | |||
| current_mileage | numeric(12,2) | |||
| recorded_at | timestamp with time zone | now() | ||
| altitude | numeric(8,2) | |||
| post_type | smallint | |||
| source | text | 'poll'::text |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| filename | text | NOT NULL | ||
| applied_at | timestamp with time zone | NOT NULL | now() |
Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| reading_time | timestamp with time zone | NOT NULL | ||
| temperature | numeric(6,2) | |||
| humidity_pct | numeric(5,2) | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('trips_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| start_time | timestamp with time zone | NOT NULL | ||
| end_time | timestamp with time zone | |||
| start_geom | geometry(Point,4326) | |||
| end_geom | geometry(Point,4326) | |||
| distance_km | numeric(12,2) | Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10). | ||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| updated_at | timestamp with time zone | now() | ||
| fuel_consumed_l | numeric(8,2) | |||
| idle_time_s | integer | |||
| driving_time_s | integer | runTimeSecond from API: total driving time in seconds | ||
| trip_seq | integer | |||
| source | text | 'poll'::text | poll = from API polling, push = from webhook push | |
| route_geom | geometry(LineString,4326) | Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window. | ||
| start_address | text | Reverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative. | ||
| end_address | text | Reverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative. | ||
| vehicle_plate | text | Denormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest. | ||
| waypoints_count | integer | Number of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate. |
01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_number | text | |||
| vehicle_name | text | |||
| driver_name | text | |||
| driver_phone | text | |||
| assigned_city | text | |||
| lat | double precision | |||
| lng | double precision | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| acc_status | text | |||
| last_fix | timestamp without time zone | |||
| status | text |
01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| day | date | |||
| alarm_name | text | |||
| alarm_count | bigint |
01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_number | text | |||
| driver_name | text | |||
| assigned_city | text | |||
| lat | double precision | |||
| lng | double precision | |||
| since | timestamp without time zone | |||
| idle_seconds | integer |
01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| assigned_city | text | |||
| day | date | |||
| km | numeric | |||
| trips | bigint | |||
| events_80 | bigint | |||
| events_100 | bigint | |||
| events_120 | bigint | |||
| harsh_events | bigint | |||
| speeding_per_100km | numeric | |||
| harsh_per_100km | numeric |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| report_date | date | |||
| driver_name | text | |||
| vehicle_number | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| reporting_time | time without time zone | |||
| start_address | text | |||
| start_lat | double precision | |||
| start_lng | double precision | |||
| status | text | |||
| mins_from_start | integer |
Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| report_date | date | |||
| reporting_time | time without time zone | |||
| closing_time | time without time zone | |||
| reporting_ts | timestamp with time zone | |||
| closing_ts | timestamp with time zone | |||
| start_lat | double precision | |||
| start_lng | double precision | |||
| start_address | text | |||
| end_lat | double precision | |||
| end_lng | double precision | |||
| end_address | text | |||
| trips_count | bigint | |||
| total_km | numeric | |||
| drive_hours | numeric |
Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| report_date | date | |||
| reporting_time | time without time zone | |||
| closing_time | time without time zone | |||
| reporting_ts | timestamp with time zone | |||
| closing_ts | timestamp with time zone | |||
| start_lat | double precision | |||
| start_lng | double precision | |||
| start_address | text | |||
| end_lat | double precision | |||
| end_lng | double precision | |||
| end_address | text | |||
| trips_count | bigint | |||
| total_km | numeric | |||
| drive_hours | numeric |
01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| day | date | |||
| assigned_city | text | |||
| km | numeric | |||
| active_vehicles | bigint | |||
| trips | bigint |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_number | text | |||
| driver_name | text | |||
| lat | double precision | |||
| lng | double precision | |||
| geom | geometry(Point,4326) | |||
| speed | numeric(7,2) | |||
| acc_status | text | |||
| gps_time | timestamp with time zone | |||
| connectivity_status | text | |||
| seconds_since_fix | integer |
01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| vehicle_name | text | |||
| assigned_city | text | |||
| enabled_flag | smallint | |||
| km_today | numeric | |||
| trips_today | bigint | |||
| drive_hours | numeric | |||
| idle_hours | numeric | |||
| first_departure | time without time zone | |||
| last_return | time without time zone | |||
| alarms_today | bigint | |||
| last_fix | timestamp without time zone | |||
| last_speed | numeric(7,2) | |||
| did_not_move | boolean |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| gid | bigint | |||
| driver_name | text | |||
| vehicle_name | text | |||
| device_name | text | |||
| imei | text | |||
| geom | geometry(Point,4326) | |||
| lat | numeric | |||
| lng | numeric | |||
| start_time | timestamp without time zone | |||
| end_time | timestamp without time zone | |||
| day_local | date | |||
| hour_local | integer | |||
| dow_local | integer | |||
| gps_time_utc | timestamp with time zone | |||
| recorded_at | timestamp with time zone | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| current_mileage | numeric(12,2) | |||
| stationary | boolean | |||
| trip_id | bigint |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| endpoint | text | |||
| run_at | timestamp with time zone | |||
| success | boolean | |||
| error_message | text | |||
| seconds_ago | integer |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| bucket | timestamp with time zone | |||
| imei | text | |||
| dist_km | numeric | |||
| avg_speed | numeric |
01_BusinessAnalytics.md §4.5 Field-Service SLA Metrics. Open tickets + last 24h resolved.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| ticket_id | text | |||
| customer | text | |||
| priority | text | |||
| job_type | text | |||
| status | text | |||
| created_at | timestamp with time zone | |||
| assigned_at | timestamp with time zone | |||
| closed_at | timestamp with time zone | |||
| assigned_imei | text | |||
| driver_name | text | |||
| first_movement_at | timestamp with time zone | |||
| on_site_at | timestamp with time zone | |||
| resolved_at | timestamp with time zone | |||
| dispatch_mins | numeric | |||
| enroute_mins | numeric | |||
| onsite_mins | numeric | |||
| resolution_mins | numeric | |||
| ticket_stage | text |
tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | |||
| imei | text | |||
| start_time | timestamp with time zone | |||
| end_time | timestamp with time zone | |||
| start_geom | geometry(Point,4326) | |||
| end_geom | geometry(Point,4326) | |||
| distance_km | numeric(12,2) | |||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| updated_at | timestamp with time zone | |||
| fuel_consumed_l | numeric(8,2) | |||
| idle_time_s | integer | |||
| driving_time_s | integer | |||
| trip_seq | integer | |||
| source | text | |||
| route_geom | geometry(LineString,4326) | |||
| start_address | text | |||
| end_address | text | |||
| vehicle_plate | text | |||
| waypoints_count | integer | |||
| trip_date_eat | date | |||
| daily_seq | bigint |
01_BusinessAnalytics.md §7 Panel 8 Utilisation Heatmap. Empty until nightly ETL runs.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| day | date | |||
| imei | text | |||
| vehicle_number | text | |||
| driver_name | text | |||
| assigned_city | text | |||
| total_distance_km | numeric(12,2) | |||
| total_drive_hours | numeric(8,2) | |||
| total_idle_hours | numeric(8,2) | |||
| alarm_count | integer | |||
| overspeed_count | integer | |||
| utilisation_pct | numeric |
01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_name | text | |||
| vehicle_number | text | |||
| driver_name | text | |||
| assigned_city | text | |||
| last_seen | timestamp without time zone | |||
| speed | numeric(7,2) |
—
| arguments | () |
| returns | trigger |
2 table(s) · 12 view(s) · 4 function(s) documented.
One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. Written by dashboard_api's built-in refresher (source='dashboard_api', every 5 min); the retired n8n job (source='n8n') was the previous writer. Read MAX(refreshed_at) for staleness.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| refreshed_at | timestamp with time zone | NOT NULL | now() | |
| source | text | NOT NULL | 'n8n'::text | |
| duration_ms | integer | |||
| row_count | integer | |||
| notes | text |
Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_id | bigint | |||
| imei | text | |||
| device_name | text | |||
| vehicle_number | text | |||
| vehicle_models | text | |||
| vehicle_category | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| assigned_driver | text | |||
| start_time | timestamp without time zone | |||
| end_time | timestamp without time zone | |||
| trip_date | date | |||
| start_hour | integer | |||
| start_dow | integer | |||
| daily_seq | bigint | |||
| distance_km | numeric(12,2) | |||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| idle_time_s | integer | |||
| driving_time_s | integer | |||
| fuel_consumed_l | numeric(8,2) | |||
| waypoints_count | integer | |||
| start_address | text | |||
| end_address | text | |||
| start_geom | geometry(Point,4326) | |||
| end_geom | geometry(Point,4326) | |||
| route_geom | geometry(LineString,4326) | |||
| route_geojson | json | |||
| is_meaningful_route | boolean | |||
| updated_at | timestamp without time zone |
Cost-centre × day rollup. Excludes trips with NULL cost_centre.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_date | date | |||
| cost_centre | text | |||
| active_vehicles | bigint | |||
| active_drivers | bigint | |||
| trip_count | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| km_per_vehicle | numeric |
Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_date | date | |||
| cost_centre | text | |||
| assigned_city | text | |||
| vehicle_number | text | |||
| assigned_driver | text | |||
| trip_count | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| first_trip_start | timestamp without time zone | |||
| last_trip_end | timestamp without time zone | |||
| avg_speed_kmh | numeric | |||
| max_speed_kmh | numeric | |||
| day_routes_geojson | json |
Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| assigned_city | text |
Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| cost_centre | text |
Driver dropdown source for the n8n dashboard. Distinct non-null drivers.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| driver | text |
Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| vehicle_number | text | |||
| drivers | text | |||
| cost_centre | text | |||
| assigned_city | text |
Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_number | text | |||
| assigned_driver | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| vehicle_category | text | |||
| vehicle_models | text | |||
| mc_type | text | |||
| device_kind | text | |||
| lat | double precision | |||
| lng | double precision | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| acc_status | text | |||
| device_status | text | |||
| gps_signal | smallint | |||
| gps_num | smallint | |||
| current_mileage | numeric(12,2) | |||
| loc_desc | text | |||
| gps_time | timestamp with time zone | |||
| updated_at | timestamp with time zone | |||
| gps_time_eat | timestamp without time zone | |||
| updated_at_eat | timestamp without time zone | |||
| source_age_hours | numeric |
Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| month_start | date | |||
| month_label | text | |||
| cost_centre | text | |||
| active_vehicles | bigint | |||
| active_drivers | bigint | |||
| active_days | bigint | |||
| trip_count | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| km_per_vehicle | numeric |
Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| month_start | date | |||
| month_label | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| vehicle_category | text | |||
| vehicle_number | text | |||
| assigned_driver | text | |||
| trip_count | bigint | |||
| active_days | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| km_per_active_day | numeric | |||
| km_per_trip | numeric | |||
| avg_speed_kmh | numeric | |||
| peak_speed_kmh | numeric |
Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_id | bigint | |||
| imei | text | |||
| device_name | text | |||
| vehicle_number | text | |||
| vehicle_models | text | |||
| vehicle_category | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| assigned_driver | text | |||
| start_time | timestamp without time zone | |||
| end_time | timestamp without time zone | |||
| trip_date | date | |||
| start_hour | integer | |||
| start_dow | integer | |||
| daily_seq | bigint | |||
| distance_km | numeric(12,2) | |||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| idle_time_s | integer | |||
| driving_time_s | integer | |||
| fuel_consumed_l | numeric(8,2) | |||
| waypoints_count | integer | |||
| start_address | text | |||
| end_address | text | |||
| start_geom | geometry(Point,4326) | |||
| end_geom | geometry(Point,4326) | |||
| route_geom | geometry(LineString,4326) | |||
| route_geojson | json | |||
| is_meaningful_route | boolean | |||
| updated_at | timestamp without time zone |
Cost-centre × week rollup. Excludes trips with NULL cost_centre.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| week_start | date | |||
| cost_centre | text | |||
| active_vehicles | bigint | |||
| active_drivers | bigint | |||
| active_days | bigint | |||
| trip_count | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| km_per_vehicle | numeric |
Vehicle × week rollup. Numeric only, no geometry.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| week_start | date | |||
| cost_centre | text | |||
| assigned_city | text | |||
| vehicle_number | text | |||
| assigned_driver | text | |||
| trip_count | bigint | |||
| active_days | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| avg_trip_km | numeric |
Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.
| arguments | p_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text |
| returns | jsonb |
Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.
| arguments | p_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date |
| returns | jsonb |
Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.
| arguments | p_vehicle_number text, p_hours integer DEFAULT 1 |
| returns | jsonb |
Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.
| arguments | p text |
| returns | text |
5 table(s) · 1 view(s) · 0 function(s) documented.
Reference rates for analytics monetisation: fuel price per litre by city, labour cost per hour by role. Resolution order in views: scope_type=city > scope_type=role > scope_type=global.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| rate_key | text | NOT NULL | ||
| scope_type | text | NOT NULL | city | role | global | |
| scope_value | text | |||
| metric | text | NOT NULL | fuel_per_litre | labour_per_hour | |
| amount | numeric(12,2) | NOT NULL | ||
| currency | text | NOT NULL | ||
| effective_from | date | NOT NULL | CURRENT_DATE | |
| notes | text | |||
| created_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() |
Traffic-light targets per KPI per scope. Resolution order in views: cost_centre > vehicle_category > city > global.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| target_id | bigint | NOT NULL | nextval('ops.kpi_targets_target_id_seq'::regclass) | |
| kpi_key | text | NOT NULL | ||
| scope_type | text | NOT NULL | ||
| scope_value | text | |||
| target_value | numeric(12,2) | NOT NULL | ||
| amber_threshold | numeric(12,2) | |||
| red_threshold | numeric(12,2) | |||
| direction | text | NOT NULL | 'higher_is_better'::text | higher_is_better -> green when value >= target. lower_is_better -> green when value <= target. |
| effective_from | date | NOT NULL | CURRENT_DATE | |
| notes | text | |||
| created_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() |
Physical odometer captures from service, fuel card, or manual entry. Powers §3.8 Odometer Divergence audit.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| reading_id | bigint | NOT NULL | nextval('ops.odometer_readings_reading_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| reading_date | date | NOT NULL | ||
| reading_km | integer | NOT NULL | ||
| source | text | service | fuel_card | driver_manual | workshop_form | ||
| recorded_by | text | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Workshop service history. Powers §10 Service-Interval Forecaster.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| service_id | bigint | NOT NULL | nextval('ops.service_log_service_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| service_date | date | NOT NULL | ||
| odometer_km | integer | NOT NULL | Physical odometer reading at service time (integer km). | |
| service_type | text | scheduled | repair | tyre | bodywork | inspection | other | ||
| cost_kes | integer | |||
| notes | text | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Skeleton for ticket data sourced from the Fireside ops system. Replace or extend to match the actual feed (Zoho Desk, Freshdesk, etc).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| ticket_id | text | NOT NULL | ||
| assigned_imei | text | |||
| driver_name | text | |||
| customer | text | |||
| job_type | text | |||
| priority | text | |||
| status | text | NOT NULL | 'open'::text | open | assigned | in_progress | resolved | cancelled |
| created_at | timestamp with time zone | NOT NULL | ||
| assigned_at | timestamp with time zone | |||
| closed_at | timestamp with time zone | |||
| job_lat | double precision | |||
| job_lng | double precision | |||
| job_geom | geometry(Point,4326) | |||
| ingested_at | timestamp with time zone | NOT NULL | now() |
Projected next-service date per vehicle based on 30-day km rate. Service interval default 10,000 km — override at query time if needed.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| last_service_date | date | |||
| last_service_odo | integer | |||
| current_odo | numeric(12,2) | |||
| km_since_service | numeric | |||
| km_to_next_service | numeric | |||
| km_per_day_30d | numeric | |||
| projected_service_date | date |
2 table(s) · 0 view(s) · 1 function(s) documented.
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| vehicle_key | integer | NOT NULL | nextval('dim_vehicles_vehicle_key_seq'::regclass) | |
| imei | text | |||
| vehicle_number | text | |||
| is_active | boolean | true |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| day | date | NOT NULL | ||
| vehicle_key | integer | NOT NULL | ||
| total_distance_km | numeric(12,2) | Total km driven that day across all trips | ||
| max_speed_kmh | numeric(7,2) | |||
| idle_hours | numeric(5,2) | |||
| total_trips | integer | Number of completed trips | ||
| total_drive_hours | numeric(8,2) | Total hours of active driving (engine on + moving) | ||
| total_idle_hours | numeric(8,2) | Total hours engine on but stationary | ||
| fuel_consumed_l | numeric(10,3) | Total fuel consumed in litres (from webhook trip reports) | ||
| alarm_count | integer | Total alarm events triggered that day | ||
| overspeed_count | integer | Number of overspeed alarm events | ||
| day_start_time | time without time zone | Time of first trip start (Africa/Nairobi) | ||
| day_end_time | time without time zone | Time of last trip end (Africa/Nairobi) | ||
| avg_speed_kmh | numeric(7,2) | Fleet average speed across all trips that day | ||
| peak_speed_kmh | numeric(7,2) | Highest max_speed_kmh recorded across all trips |
Populates or refreshes fact_daily_fleet_metrics for the given date. Call nightly: SELECT dwh_gold.refresh_daily_metrics(CURRENT_DATE - 1);
| arguments | target_date date |
| returns | void |
1 table(s) · 3 view(s) · 1 function(s) documented.
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| srid | integer | NOT NULL | ||
| auth_name | character varying(256) | |||
| auth_srid | integer | |||
| srtext | character varying(2048) | |||
| proj4text | character varying(2048) |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| f_table_catalog | name | |||
| f_table_schema | name | |||
| f_table_name | name | |||
| f_geography_column | name | |||
| coord_dimension | integer | |||
| srid | integer | |||
| type | text |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| f_table_catalog | character varying(256) | |||
| f_table_schema | name | |||
| f_table_name | name | |||
| f_geometry_column | name | |||
| coord_dimension | integer | |||
| srid | integer | |||
| type | character varying(30) |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_id | bigint | |||
| imei | text | |||
| vehicle_name | text | |||
| vehicle_number | text | |||
| cost_centre | text | |||
| start_time | timestamp with time zone | |||
| end_time | timestamp with time zone | |||
| distance_km | numeric(12,2) | |||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| vehicle_plate | text | |||
| start_address | text | |||
| end_address | text | |||
| waypoints_count | integer | |||
| driving_time_s | integer | |||
| idle_time_s | integer | |||
| fuel_consumed_l | numeric(8,2) | |||
| trip_date_eat | date | |||
| daily_seq | bigint |
pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.
| arguments | in_user text, OUT uname text, OUT phash text |
| returns | record |
Grafana is provisioned via a baked image and reads TimescaleDB directly (read-only role grafana_ro), mostly through the tracksolid.v_* analytics views documented in §5. Two dashboards ship with the stack.
noc-fleet-live · 9 panels| Section | Panel | Type | Source view / table |
|---|---|---|---|
| Total Vehicles | stat | tracksolid.devices | |
| Online Now | stat | tracksolid.v_fleet_status | |
| Recent (5-30 min) | stat | tracksolid.v_fleet_status | |
| Offline | stat | tracksolid.v_fleet_status | |
| Moving Now | stat | tracksolid.v_fleet_status | |
| Avg Speed (km/h) | stat | tracksolid.v_fleet_status | |
| Live Vehicle Locations | geomap | tracksolid.devices, tracksolid.live_positions | |
| Vehicle Status | table | tracksolid.devices, tracksolid.live_positions | |
| Ingestion Health | table | tracksolid.v_ingestion_health |
daily-ops · 21 panels| Section | Panel | Type | Source view / table |
|---|---|---|---|
| Last GPS Fix (fleet) | stat | tracksolid.live_positions | |
| Vehicles reporting today | stat | tracksolid.v_fleet_today | |
| Fleet km today | stat | tracksolid.v_fleet_today | |
| Drive hours today | stat | tracksolid.v_fleet_today | |
| Idle hours today | stat | tracksolid.v_fleet_today | |
| Open alarms (24h) | stat | tracksolid.alarms | |
| In-flight SLA jobs | stat | tracksolid.v_sla_inflight | |
| Active Vehicles Map | geomap | tracksolid.v_active_dispatch_map | |
| Currently Idle (engine on, speed < 2) | table | tracksolid.v_currently_idle | |
| Vehicles Not Moved Today | table | tracksolid.v_vehicles_not_moved_today | |
| Per-Vehicle Daily Roll-up | table | tracksolid.v_fleet_today | |
| Driver Leaderboard | table | tracksolid.v_driver_aggregates_daily | |
| Fleet Distance — 7-day (by city) | timeseries | tracksolid.v_fleet_km_daily | |
| Alarm Frequency — 30-day (by type) | timeseries | tracksolid.v_alarms_daily | |
| Idle Cost (month-to-date) | stat | tracksolid.v_utilisation_daily | |
| Utilisation Heatmap (30-day) | heatmap | tracksolid.v_utilisation_daily | |
| Row 7 — Field-Service SLAs (data-gated) | Dispatch SLA (median mins, 24h) | stat | tracksolid.v_sla_inflight |
| En-route SLA (median mins, 24h) | stat | tracksolid.v_sla_inflight | |
| On-site SLA (median mins, 24h) | stat | tracksolid.v_sla_inflight | |
| Resolution SLA (median mins, 24h) | stat | tracksolid.v_sla_inflight | |
| At-risk tickets | table | tracksolid.v_sla_inflight |
SLA panels (v_sla_inflight) and the utilisation heatmap (v_utilisation_daily) are data-gated on the ops ticket integration and nightly dwh_gold ETL respectively.
x-www-form-urlencoded; the mismatch silently dropped every filter so the map always returned the whole fleet. Now parsed by Content-Type (parse_qs for form bodies). Commit f1387d1.17 table(s) · 15 view(s) · 1 function(s) documented.
Alarm events (alarm_type, alarm_name, alarm_time).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('alarms_id_seq'::regclass) | |
| imei | text | |||
| alarm_type | text | |||
| alarm_time | timestamp with time zone | |||
| geom | geometry(Point,4326) | |||
| lat | double precision | |||
| lng | double precision | |||
| speed | numeric(7,2) | |||
| acc_status | text | |||
| updated_at | timestamp with time zone | now() | ||
| alarm_name | text | |||
| source | text | 'poll'::text | ||
| severity | text | Alarm severity level: critical | warning | info | ||
| geofence_id | text | Tracksolid geofence ID if this is a geofence alarm | ||
| geofence_name | text | Human-readable geofence name | ||
| acknowledged_at | timestamp with time zone | Timestamp when alarm was acknowledged by an operator | ||
| acknowledged_by | text | Username or ID of operator who acknowledged the alarm |
OAuth2 token cache for the Jimi/Tracksolid API.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('api_token_cache_id_seq'::regclass) | |
| account | text | NOT NULL | ||
| access_token | text | NOT NULL | ||
| refresh_token | text | |||
| app_key | text | |||
| expires_at | timestamp with time zone | NOT NULL | ||
| obtained_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() |
Device network connection and disconnection events from /pushevent webhook.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('device_events_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| event_type | text | NOT NULL | LOGIN = device connected to network; LOGOUT = device disconnected | |
| event_time | timestamp with time zone | NOT NULL | ||
| timezone | text | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Device / driver / vehicle registry. One row per tracker (IMEI). Source of plate, driver, SIM, model.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| device_name | text | |||
| mc_type | text | |||
| mc_type_use_scope | text | |||
| vehicle_name | text | |||
| vehicle_number | text | |||
| vehicle_models | text | |||
| vehicle_icon | text | |||
| vin | text | |||
| engine_number | text | |||
| vehicle_brand | text | |||
| fuel_100km | numeric(6,2) | |||
| driver_name | text | |||
| driver_phone | text | |||
| sim | text | |||
| iccid | text | |||
| imsi | text | |||
| account | text | |||
| customer_name | text | |||
| device_group_id | text | |||
| device_group | text | |||
| activation_time | timestamp with time zone | |||
| expiration | timestamp with time zone | |||
| enabled_flag | smallint | NOT NULL | 1 | |
| status | text | 'active'::text | ||
| city | text | |||
| current_mileage_km | numeric(12,2) | |||
| created_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() | |
| last_synced_at | timestamp with time zone | |||
| vehicle_category | text | Vehicle type: truck | van | motorcycle | car | other | ||
| cost_centre | text | Business unit or department this vehicle belongs to | ||
| assigned_route | text | Regular route name or ID for route-based reporting | ||
| depot_geom | geometry(Point,4326) | Home base/depot coordinates (WGS84) | ||
| depot_address | text | Human-readable depot address | ||
| assigned_city | text | Operating territory code: NBO (Nairobi) | MBA (Mombasa) | KLA (Kampala). Used for city-cohort analytics and geographic drift detection. |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('fault_codes_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| reported_at | timestamp with time zone | NOT NULL | ||
| fault_code | text | NOT NULL | ||
| status_flags | integer | |||
| lat | double precision | |||
| lng | double precision | |||
| geom | geometry(Point,4326) | |||
| event_time | timestamp with time zone | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Fuel/oil sensor readings from /pushoil webhook. Unit varies per sensor: cm | % | V | L.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| reading_time | timestamp with time zone | NOT NULL | ||
| sensor_path | text | Sensor channel identifier from the device (path field in API payload) | ||
| value | numeric(10,3) | |||
| unit | text | Measurement unit: cm (tank depth), % (percentage), V (voltage), L (litres) | ||
| lat | double precision | |||
| lng | double precision | |||
| geom | geometry(Point,4326) | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Geofence boundary definitions synced from the Tracksolid platform.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('geofences_id_seq'::regclass) | |
| fence_id | text | |||
| fence_name | text | NOT NULL | ||
| fence_type | text | circle | polygon | ||
| geom | geometry(Geometry,4326) | |||
| radius_m | numeric(10,2) | Radius in metres — only applicable for circle type geofences | ||
| description | text | |||
| created_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() |
Device heartbeat hypertable.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| gate_time | timestamp with time zone | NOT NULL | ||
| power_level | smallint | |||
| gsm_signal | smallint | |||
| acc_status | smallint | |||
| power_status | smallint | |||
| fortify | smallint | |||
| created_at | timestamp with time zone | NOT NULL | now() |
API call audit trail — one row per ingestion run.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('ingestion_log_id_seq'::regclass) | |
| run_at | timestamp with time zone | NOT NULL | now() | |
| endpoint | text | NOT NULL | ||
| imei_count | integer | NOT NULL | 0 | |
| rows_upserted | integer | NOT NULL | 0 | |
| rows_inserted | integer | NOT NULL | 0 | |
| duration_ms | integer | NOT NULL | 0 | |
| success | boolean | NOT NULL | true | |
| error_code | text | |||
| error_message | text |
Cell tower / WiFi positioning fallback data from /pushlbs webhook. Used when GPS signal is unavailable.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('lbs_readings_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| gate_time | timestamp with time zone | NOT NULL | ||
| post_type | text | Positioning technology: WIFI | LBS (cell tower) | ||
| lbs_data | jsonb | Raw JSON payload containing MCC, MNC, and cell tower list for approximate geocoding. | ||
| created_at | timestamp with time zone | NOT NULL | now() |
Latest fix per IMEI, refreshed every 60s by ingest_movement. Feeds reporting.v_live_positions.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| geom | geometry(Point,4326) | |||
| lat | double precision | |||
| lng | double precision | |||
| pos_type | text | |||
| confidence | smallint | |||
| gps_time | timestamp with time zone | |||
| hb_time | timestamp with time zone | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| acc_status | text | |||
| gps_signal | smallint | |||
| gps_num | smallint | |||
| elec_quantity | numeric(5,2) | |||
| power_value | numeric(5,2) | |||
| battery_power_val | numeric(5,2) | |||
| tracker_oil | text | |||
| temperature | numeric(8,2) | |||
| current_mileage | numeric(12,2) | |||
| device_status | text | |||
| expire_flag | text | |||
| activation_flag | text | |||
| loc_desc | text | |||
| recorded_at | timestamp with time zone | NOT NULL | now() | |
| updated_at | timestamp with time zone | NOT NULL | now() |
OBD diagnostics — push only via /pushobd webhook.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('obd_readings_id_seq'::regclass) | |
| imei | text | |||
| reading_time | timestamp with time zone | |||
| engine_rpm | integer | Engine RPM from OBD PID 0x0C | ||
| fuel_level_pct | numeric(5,2) | Fuel tank level % from OBD PID 0x2F | ||
| updated_at | timestamp with time zone | now() | ||
| car_type | smallint | |||
| acc_state | smallint | |||
| status_flags | integer | |||
| lat | double precision | |||
| lng | double precision | |||
| geom | geometry(Point,4326) | |||
| obd_data | jsonb | Raw obdJson from Jimi push. Contains dataID1..N fields (engine RPM, coolant temp, fuel level, etc.) | ||
| coolant_temp_c | numeric(6,2) | Coolant temperature °C from OBD PID 0x05 | ||
| battery_voltage | numeric(5,2) | Battery voltage (V) from OBD PID 0x42 | ||
| intake_pressure | numeric(6,2) | Intake manifold pressure kPa from OBD PID 0x0B | ||
| throttle_pct | numeric(5,2) | Throttle position % from OBD PID 0x11 | ||
| vehicle_speed | numeric(7,2) | Vehicle speed km/h from OBD PID 0x0D | ||
| engine_load_pct | numeric(5,2) | Calculated engine load % from OBD PID 0x04 |
Stop events with duration + address.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('parking_events_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| event_type | text | |||
| start_time | timestamp with time zone | NOT NULL | ||
| end_time | timestamp with time zone | |||
| duration_seconds | integer | |||
| geom | geometry(Point,4326) | |||
| address | text | |||
| updated_at | timestamp with time zone | now() |
All GPS fixes (hypertable, partitioned by gps_time). source='poll' (60s) or 'track_list' (30m high-res).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| gps_time | timestamp with time zone | NOT NULL | ||
| geom | geometry(Point,4326) | |||
| lat | double precision | |||
| lng | double precision | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| acc_status | text | |||
| satellite | smallint | |||
| current_mileage | numeric(12,2) | |||
| recorded_at | timestamp with time zone | now() | ||
| altitude | numeric(8,2) | |||
| post_type | smallint | |||
| source | text | 'poll'::text |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| filename | text | NOT NULL | ||
| applied_at | timestamp with time zone | NOT NULL | now() |
Temperature and humidity sensor readings from /pushtem webhook. For cold-chain / refrigerated cargo monitoring.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | NOT NULL | ||
| reading_time | timestamp with time zone | NOT NULL | ||
| temperature | numeric(6,2) | |||
| humidity_pct | numeric(5,2) | |||
| created_at | timestamp with time zone | NOT NULL | now() |
Trip summaries: distance_km, driving time, avg/max speed, route geometry + addresses (FIX-M20).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | NOT NULL | nextval('trips_id_seq'::regclass) | |
| imei | text | NOT NULL | ||
| start_time | timestamp with time zone | NOT NULL | ||
| end_time | timestamp with time zone | |||
| start_geom | geometry(Point,4326) | |||
| end_geom | geometry(Point,4326) | |||
| distance_km | numeric(12,2) | Trip distance in kilometres. Corrected from mm storage on migration 04 (2026-04-10). | ||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| updated_at | timestamp with time zone | now() | ||
| fuel_consumed_l | numeric(8,2) | |||
| idle_time_s | integer | |||
| driving_time_s | integer | runTimeSecond from API: total driving time in seconds | ||
| trip_seq | integer | |||
| source | text | 'poll'::text | poll = from API polling, push = from webhook push | |
| route_geom | geometry(LineString,4326) | Full GPS route polyline built at ingest from position_history points where gps_time BETWEEN start_time AND end_time. NULL when fewer than 2 fixes are available for the trip window. | ||
| start_address | text | Reverse-geocoded human-readable address near start_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative. | ||
| end_address | text | Reverse-geocoded human-readable address near end_geom (Nominatim). NULL on lookup failure; address is best-effort, not authoritative. | ||
| vehicle_plate | text | Denormalised tracksolid.devices.vehicle_number cached at trip-insert time. Avoids a join for trip displays; refreshed only on next ingest. | ||
| waypoints_count | integer | Number of position_history fixes that contributed to route_geom. Audit aid: 0 or 1 means route_geom is NULL or degenerate. |
01_BusinessAnalytics.md §4.3 All Active Vehicles Map. Geomap source.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_number | text | |||
| vehicle_name | text | |||
| driver_name | text | |||
| driver_phone | text | |||
| assigned_city | text | |||
| lat | double precision | |||
| lng | double precision | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| acc_status | text | |||
| last_fix | timestamp without time zone | |||
| status | text |
01_BusinessAnalytics.md §7 Panel 7 Alarm Frequency. Stacked-by-alarm_name time series.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| day | date | |||
| alarm_name | text | |||
| alarm_count | bigint |
01_BusinessAnalytics.md §2.2 idle lens. Engine on, speed <2 km/h, fix in last 15m.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_number | text | |||
| driver_name | text | |||
| assigned_city | text | |||
| lat | double precision | |||
| lng | double precision | |||
| since | timestamp without time zone | |||
| idle_seconds | integer |
01_BusinessAnalytics.md §3.1 (speeding) + §3.2 (harsh driving). Daily grain; panels window via $__timeFilter(day).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| assigned_city | text | |||
| day | date | |||
| km | numeric | |||
| trips | bigint | |||
| events_80 | bigint | |||
| events_100 | bigint | |||
| events_120 | bigint | |||
| harsh_events | bigint | |||
| speeding_per_100km | numeric | |||
| harsh_per_100km | numeric |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| report_date | date | |||
| driver_name | text | |||
| vehicle_number | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| reporting_time | time without time zone | |||
| start_address | text | |||
| start_lat | double precision | |||
| start_lng | double precision | |||
| status | text | |||
| mins_from_start | integer |
Driver clock-in / clock-out daily series. One row per IMEI per Africa/Nairobi date with at least one trip. Reporting/closing times are derived from trip start_time/end_time bounded by local-date start; closing_ts may cross midnight UTC. No policy embedded — n8n applies tardiness rules and cost-centre filtering. See plan i-would-like-to-wobbly-volcano (2026-05-04).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| report_date | date | |||
| reporting_time | time without time zone | |||
| closing_time | time without time zone | |||
| reporting_ts | timestamp with time zone | |||
| closing_ts | timestamp with time zone | |||
| start_lat | double precision | |||
| start_lng | double precision | |||
| start_address | text | |||
| end_lat | double precision | |||
| end_lng | double precision | |||
| end_address | text | |||
| trips_count | bigint | |||
| total_km | numeric | |||
| drive_hours | numeric |
Today snapshot of v_driver_clock_daily, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| report_date | date | |||
| reporting_time | time without time zone | |||
| closing_time | time without time zone | |||
| reporting_ts | timestamp with time zone | |||
| closing_ts | timestamp with time zone | |||
| start_lat | double precision | |||
| start_lng | double precision | |||
| start_address | text | |||
| end_lat | double precision | |||
| end_lng | double precision | |||
| end_address | text | |||
| trips_count | bigint | |||
| total_km | numeric | |||
| drive_hours | numeric |
01_BusinessAnalytics.md §7 Panel 5 Distance Trend. City-cohort cut built in.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| day | date | |||
| assigned_city | text | |||
| km | numeric | |||
| active_vehicles | bigint | |||
| trips | bigint |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_number | text | |||
| driver_name | text | |||
| lat | double precision | |||
| lng | double precision | |||
| geom | geometry(Point,4326) | |||
| speed | numeric(7,2) | |||
| acc_status | text | |||
| gps_time | timestamp with time zone | |||
| connectivity_status | text | |||
| seconds_since_fix | integer |
01_BusinessAnalytics.md §9 Fleet Readiness Scorecard. One row per device with today's roll-up.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| driver_name | text | |||
| vehicle_number | text | |||
| vehicle_name | text | |||
| assigned_city | text | |||
| enabled_flag | smallint | |||
| km_today | numeric | |||
| trips_today | bigint | |||
| drive_hours | numeric | |||
| idle_hours | numeric | |||
| first_departure | time without time zone | |||
| last_return | time without time zone | |||
| alarms_today | bigint | |||
| last_fix | timestamp without time zone | |||
| last_speed | numeric(7,2) | |||
| did_not_move | boolean |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| gid | bigint | |||
| driver_name | text | |||
| vehicle_name | text | |||
| device_name | text | |||
| imei | text | |||
| geom | geometry(Point,4326) | |||
| lat | numeric | |||
| lng | numeric | |||
| start_time | timestamp without time zone | |||
| end_time | timestamp without time zone | |||
| day_local | date | |||
| hour_local | integer | |||
| dow_local | integer | |||
| gps_time_utc | timestamp with time zone | |||
| recorded_at | timestamp with time zone | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| current_mileage | numeric(12,2) | |||
| stationary | boolean | |||
| trip_id | bigint |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| endpoint | text | |||
| run_at | timestamp with time zone | |||
| success | boolean | |||
| error_message | text | |||
| seconds_ago | integer |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| bucket | timestamp with time zone | |||
| imei | text | |||
| dist_km | numeric | |||
| avg_speed | numeric |
tracksolid.trips with computed daily_seq (Nth trip per IMEI per local Africa/Nairobi day) and trip_date_eat. Replaces reliance on the device-supplied trip_seq column, which is NULL for poll-ingested trips.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| id | bigint | |||
| imei | text | |||
| start_time | timestamp with time zone | |||
| end_time | timestamp with time zone | |||
| start_geom | geometry(Point,4326) | |||
| end_geom | geometry(Point,4326) | |||
| distance_km | numeric(12,2) | |||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| updated_at | timestamp with time zone | |||
| fuel_consumed_l | numeric(8,2) | |||
| idle_time_s | integer | |||
| driving_time_s | integer | |||
| trip_seq | integer | |||
| source | text | |||
| route_geom | geometry(LineString,4326) | |||
| start_address | text | |||
| end_address | text | |||
| vehicle_plate | text | |||
| waypoints_count | integer | |||
| trip_date_eat | date | |||
| daily_seq | bigint |
01_BusinessAnalytics.md §2.3. Enabled vehicles with zero trips today.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_name | text | |||
| vehicle_number | text | |||
| driver_name | text | |||
| assigned_city | text | |||
| last_seen | timestamp without time zone | |||
| speed | numeric(7,2) |
—
| arguments | () |
| returns | trigger |
2 table(s) · 12 view(s) · 4 function(s) documented.
One row per REFRESH MATERIALIZED VIEW CONCURRENTLY reporting.v_trips. Written by dashboard_api's built-in refresher (source='dashboard_api', every 5 min); the retired n8n job (source='n8n') was the previous writer. Read MAX(refreshed_at) for staleness.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| refreshed_at | timestamp with time zone | NOT NULL | now() | |
| source | text | NOT NULL | 'n8n'::text | |
| duration_ms | integer | |||
| row_count | integer | |||
| notes | text |
Canonical trip view, MATERIALIZED for dashboard read latency (see header diagnostic note). All timestamps in Africa/Nairobi. LEFT JOINs devices so trips with no device row keep NULL cost_centre rather than disappearing. Refresh via n8n every 5 min; see reporting.refresh_log. See 260519_trips_kepler_deployment.md §Phase 1+6.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_id | bigint | |||
| imei | text | |||
| device_name | text | |||
| vehicle_number | text | |||
| vehicle_models | text | |||
| vehicle_category | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| assigned_driver | text | |||
| start_time | timestamp without time zone | |||
| end_time | timestamp without time zone | |||
| trip_date | date | |||
| start_hour | integer | |||
| start_dow | integer | |||
| daily_seq | bigint | |||
| distance_km | numeric(12,2) | |||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| idle_time_s | integer | |||
| driving_time_s | integer | |||
| fuel_consumed_l | numeric(8,2) | |||
| waypoints_count | integer | |||
| start_address | text | |||
| end_address | text | |||
| start_geom | geometry(Point,4326) | |||
| end_geom | geometry(Point,4326) | |||
| route_geom | geometry(LineString,4326) | |||
| route_geojson | json | |||
| is_meaningful_route | boolean | |||
| updated_at | timestamp without time zone |
Cost-centre × day rollup. Excludes trips with NULL cost_centre.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_date | date | |||
| cost_centre | text | |||
| active_vehicles | bigint | |||
| active_drivers | bigint | |||
| trip_count | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| km_per_vehicle | numeric |
Vehicle × day rollup. Filtered by is_meaningful_route. day_routes_geojson is the daily multi-line geometry for long-range Kepler.gl fallback.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_date | date | |||
| cost_centre | text | |||
| assigned_city | text | |||
| vehicle_number | text | |||
| assigned_driver | text | |||
| trip_count | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| first_trip_start | timestamp without time zone | |||
| last_trip_end | timestamp without time zone | |||
| avg_speed_kmh | numeric | |||
| max_speed_kmh | numeric | |||
| day_routes_geojson | json |
Assigned-city dropdown source for the n8n dashboard. Distinct non-null cities.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| assigned_city | text |
Cost-centre dropdown source for the n8n dashboard. Distinct non-null centres.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| cost_centre | text |
Driver dropdown source for the n8n dashboard. Distinct non-null drivers.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| driver | text |
Vehicle dropdown source for the n8n dashboard. Plate is the value; drivers column lists every driver historically associated with the vehicle. cost_centre and assigned_city carry the vehicle's most-recent assignment so the frontend can auto-set those dependent dropdowns.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| vehicle_number | text | |||
| drivers | text | |||
| cost_centre | text | |||
| assigned_city | text |
Latest known fix per vehicle, deduped to one primary IMEI per normalised plate. Provenance: 260521_liveposition_deployment.md §Phase 1.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| imei | text | |||
| vehicle_number | text | |||
| assigned_driver | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| vehicle_category | text | |||
| vehicle_models | text | |||
| mc_type | text | |||
| device_kind | text | |||
| lat | double precision | |||
| lng | double precision | |||
| speed | numeric(7,2) | |||
| direction | numeric(6,2) | |||
| acc_status | text | |||
| device_status | text | |||
| gps_signal | smallint | |||
| gps_num | smallint | |||
| current_mileage | numeric(12,2) | |||
| loc_desc | text | |||
| gps_time | timestamp with time zone | |||
| updated_at | timestamp with time zone | |||
| gps_time_eat | timestamp without time zone | |||
| updated_at_eat | timestamp without time zone | |||
| source_age_hours | numeric |
Cost-centre × month rollup. Executive grain. Excludes trips with NULL cost_centre.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| month_start | date | |||
| month_label | text | |||
| cost_centre | text | |||
| active_vehicles | bigint | |||
| active_drivers | bigint | |||
| active_days | bigint | |||
| trip_count | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| km_per_vehicle | numeric |
Vehicle × month rollup with trend metrics (km_per_active_day, km_per_trip).
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| month_start | date | |||
| month_label | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| vehicle_category | text | |||
| vehicle_number | text | |||
| assigned_driver | text | |||
| trip_count | bigint | |||
| active_days | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| km_per_active_day | numeric | |||
| km_per_trip | numeric | |||
| avg_speed_kmh | numeric | |||
| peak_speed_kmh | numeric |
Today snapshot of reporting.v_trips, filtered to (NOW() AT TIME ZONE 'Africa/Nairobi')::date. Refreshes as trips land throughout the day.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_id | bigint | |||
| imei | text | |||
| device_name | text | |||
| vehicle_number | text | |||
| vehicle_models | text | |||
| vehicle_category | text | |||
| cost_centre | text | |||
| assigned_city | text | |||
| assigned_driver | text | |||
| start_time | timestamp without time zone | |||
| end_time | timestamp without time zone | |||
| trip_date | date | |||
| start_hour | integer | |||
| start_dow | integer | |||
| daily_seq | bigint | |||
| distance_km | numeric(12,2) | |||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| idle_time_s | integer | |||
| driving_time_s | integer | |||
| fuel_consumed_l | numeric(8,2) | |||
| waypoints_count | integer | |||
| start_address | text | |||
| end_address | text | |||
| start_geom | geometry(Point,4326) | |||
| end_geom | geometry(Point,4326) | |||
| route_geom | geometry(LineString,4326) | |||
| route_geojson | json | |||
| is_meaningful_route | boolean | |||
| updated_at | timestamp without time zone |
Cost-centre × week rollup. Excludes trips with NULL cost_centre.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| week_start | date | |||
| cost_centre | text | |||
| active_vehicles | bigint | |||
| active_drivers | bigint | |||
| active_days | bigint | |||
| trip_count | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| idle_pct | numeric | |||
| km_per_vehicle | numeric |
Vehicle × week rollup. Numeric only, no geometry.
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| week_start | date | |||
| cost_centre | text | |||
| assigned_city | text | |||
| vehicle_number | text | |||
| assigned_driver | text | |||
| trip_count | bigint | |||
| active_days | bigint | |||
| total_km | numeric | |||
| driving_hours | numeric | |||
| idle_hours | numeric | |||
| avg_trip_km | numeric |
Dashboard contract for liveposition.rahamafresh.com. Returns {summary, geojson}. NULL params = wildcard. Reads reporting.v_live_positions (already deduped). Provenance: 260521_liveposition_deployment.md §Phase 2.
| arguments | p_cost_centre text DEFAULT NULL::text, p_acc_status text DEFAULT NULL::text |
| returns | jsonb |
Dashboard contract: see 260519_trips_kepler_deployment.md §Phase 2. Args (positional): vehicle_numbers[], driver, cost_centre, assigned_city, start_date, end_date. NULL = wildcard; empty array also = wildcard. Returns {summary, geojson} where each feature carries daily_seq for client-side sequence colouring. Refuses unfiltered ranges >31 days.
| arguments | p_vehicle_numbers text[] DEFAULT NULL::text[], p_driver text DEFAULT NULL::text, p_cost_centre text DEFAULT NULL::text, p_assigned_city text DEFAULT NULL::text, p_start_date date DEFAULT NULL::date, p_end_date date DEFAULT NULL::date |
| returns | jsonb |
Returns a GeoJSON Feature(LineString) of the vehicle's last N hours of fixes from tracksolid.position_history. Provenance: 260521_liveposition_deployment.md §Phase 3.
| arguments | p_vehicle_number text, p_hours integer DEFAULT 1 |
| returns | jsonb |
Canonicalise Kenyan vehicle plates: trim, collapse internal whitespace, and remove the space before a single trailing letter (e.g. "KDS 453 Y" → "KDS 453Y"). Used in v_trips so plate-level grouping/joining works consistently regardless of how the plate was typed into the registry.
| arguments | p text |
| returns | text |
The ops schema (workshop / tickets / dispatch / SLA / odometer / cost_rates / kpi_targets) and the dwh_gold schema (dim_vehicles, fact_daily_fleet_metrics, refresh_daily_metrics) were purged 2026-06-05 via migrations 12 / 13 — those features were never implemented. Also dropped: tracksolid.dispatch_log, tracksolid.v_sla_inflight, tracksolid.v_utilisation_daily, and their Grafana panels. The separate tracksolid_dwh server (31.97.44.246:5888) is unrelated and untouched.
1 table(s) · 3 view(s) · 1 function(s) documented.
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| srid | integer | NOT NULL | ||
| auth_name | character varying(256) | |||
| auth_srid | integer | |||
| srtext | character varying(2048) | |||
| proj4text | character varying(2048) |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| f_table_catalog | name | |||
| f_table_schema | name | |||
| f_table_name | name | |||
| f_geography_column | name | |||
| coord_dimension | integer | |||
| srid | integer | |||
| type | text |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| f_table_catalog | character varying(256) | |||
| f_table_schema | name | |||
| f_table_name | name | |||
| f_geometry_column | name | |||
| coord_dimension | integer | |||
| srid | integer | |||
| type | character varying(30) |
—
| Column | Type | Null | Default | Comment |
|---|---|---|---|---|
| trip_id | bigint | |||
| imei | text | |||
| vehicle_name | text | |||
| vehicle_number | text | |||
| cost_centre | text | |||
| start_time | timestamp with time zone | |||
| end_time | timestamp with time zone | |||
| distance_km | numeric(12,2) | |||
| avg_speed_kmh | numeric(7,2) | |||
| max_speed_kmh | numeric(7,2) | |||
| vehicle_plate | text | |||
| start_address | text | |||
| end_address | text | |||
| waypoints_count | integer | |||
| driving_time_s | integer | |||
| idle_time_s | integer | |||
| fuel_consumed_l | numeric(8,2) | |||
| trip_date_eat | date | |||
| daily_seq | bigint |
pgbouncer SCRAM auth_query — returns (username, password-hash) for connection pooling.
| arguments | in_user text, OUT uname text, OUT phash text |
| returns | record |
Grafana is provisioned via a baked image and reads TimescaleDB directly (read-only role grafana_ro), mostly through the tracksolid.v_* analytics views documented in §5. Two dashboards ship with the stack.
noc-fleet-live · 9 panels| Section | Panel | Type | Source view / table |
|---|---|---|---|
| Total Vehicles | stat | tracksolid.devices | |
| Online Now | stat | tracksolid.v_fleet_status | |
| Recent (5-30 min) | stat | tracksolid.v_fleet_status | |
| Offline | stat | tracksolid.v_fleet_status | |
| Moving Now | stat | tracksolid.v_fleet_status | |
| Avg Speed (km/h) | stat | tracksolid.v_fleet_status | |
| Live Vehicle Locations | geomap | tracksolid.devices, tracksolid.live_positions | |
| Vehicle Status | table | tracksolid.devices, tracksolid.live_positions | |
| Ingestion Health | table | tracksolid.v_ingestion_health |
daily-ops · 13 panels| Section | Panel | Type | Source view / table |
|---|---|---|---|
| Last GPS Fix (fleet) | stat | tracksolid.live_positions | |
| Vehicles reporting today | stat | tracksolid.v_fleet_today | |
| Fleet km today | stat | tracksolid.v_fleet_today | |
| Drive hours today | stat | tracksolid.v_fleet_today | |
| Idle hours today | stat | tracksolid.v_fleet_today | |
| Open alarms (24h) | stat | tracksolid.alarms | |
| Active Vehicles Map | geomap | tracksolid.v_active_dispatch_map | |
| Currently Idle (engine on, speed < 2) | table | tracksolid.v_currently_idle | |
| Vehicles Not Moved Today | table | tracksolid.v_vehicles_not_moved_today | |
| Per-Vehicle Daily Roll-up | table | tracksolid.v_fleet_today | |
| Driver Leaderboard | table | tracksolid.v_driver_aggregates_daily | |
| Fleet Distance — 7-day (by city) | timeseries | tracksolid.v_fleet_km_daily | |
| Alarm Frequency — 30-day (by type) | timeseries | tracksolid.v_alarms_daily |
position_history, heartbeats, fuel_readings,
temperature_readings) report 0 in pg_stat_user_tables — counts above use TimescaleDB's
approximate_row_count().