From f0def8d7814f459f2be64abc9cb43d00894821a1 Mon Sep 17 00:00:00 2001 From: kianiadee Date: Fri, 12 Jun 2026 00:02:41 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20reflect=20deployed=20state=20=E2=80=94?= =?UTF-8?q?=20migrations=2002/03=20(EAT),=20read-side=20push=20status?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- README.md | 10 +++++++--- docs/deployment.html | 13 +++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index af7a788..5d29533 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ keyed by number plate (`car`). | Piece | What | |---|---| -| `migrations/01_fuel_schema.sql` | The `fuel` schema: `fuel.records` (raw-jsonb-first + trigger-derived columns), `fuel.norm_plate` / `fuel.canon_fuel_type` / `fuel.canon_department` normalizers, `fuel.ingest_state` (CDC watermark), and `reporting.v_fuel_fills` / `reporting.v_fuel_efficiency` (the read views) | +| `migrations/*.sql` | The `fuel` schema: `fuel.records` (raw-jsonb-first + trigger-derived columns), `fuel.norm_plate` / `fuel.canon_fuel_type` / `fuel.canon_department` normalizers, `fuel.ingest_state` (CDC watermark), and `reporting.v_fuel_fills` / `reporting.v_fuel_efficiency` (the read views). `01` base schema · `02` one-device-per-fill join fix · `03` standardize timestamps to **Africa/Nairobi (EAT)** | | `import_fuel.py` | Pulls fuel records from the rustfs `fuel` bucket and upserts them on `id` | | `s3util.py` | rustfs (S3-compatible) client factory — path-style, custom endpoint | | `run_migrations.py` | Applies `migrations/*.sql` in order (ledger: `fuel.schema_migrations`) | @@ -34,8 +34,12 @@ normalizers (`fuel.norm_plate`, `fuel.canon_fuel_type`, `fuel.canon_department`) source of truth. Soft-deletes (`deleted_at`) are kept on the row and excluded by the read views. The fuel record links to the fleet by plate: `reporting.v_fuel_fills` joins -`fuel.norm_plate(car)` to `fuel.norm_plate(devices.vehicle_number)` to pick up `cost_centre` / -`assigned_city` / `imei`. +`fuel.norm_plate(car)` to `fuel.norm_plate(devices.vehicle_number)` (LATERAL + `LIMIT 1`, since a +plate can map to more than one device over time) to pick up `cost_centre` / `assigned_city` / `imei`. + +**Timezone:** the source stamps `record_datetime` in UTC; FleetFuel stores all fuel timestamps as +**Africa/Nairobi (EAT, UTC+3)** wall-clock (`timestamp` without tz), so `record_datetime::date` +(the daily-trend bucket) is the Kenyan calendar day. See `migrations/03_fuel_timezone_eat.sql`. ## Bucket layout diff --git a/docs/deployment.html b/docs/deployment.html index a99731f..4c63471 100644 --- a/docs/deployment.html +++ b/docs/deployment.html @@ -64,6 +64,14 @@
See also: plan.html (implementation plan) · host: twala.rahamafresh.com
+
+ Status (2026-06-12): ingestion is live in the prod DB — migrations 01–03 applied, + ~1,900 rows ingested, reporting.v_fuel_fills = 1,888 rows / 1,775 matched (94%). Read-side is + pushed, awaiting promotion: FleetOps tab on branch staging (auto-deploys staging); + dashboard_api on feat/staging-fleetops-architecture (PR #17) — promote to + staging then main to light up the API. +
+

1Solution flow

Five stages. The WhatsApp fuel feed is exported to object storage by n8n; FleetFuel pulls it, normalizes and stores it, the API reads it back, and the SPA renders it.

@@ -184,6 +192,11 @@ python run_migrations.py # creates fuel.* + reportin python import_fuel.py --snapshot # DRY-RUN: parse + log counts, writes nothing python import_fuel.py --snapshot --apply # full reconcile from fuel_records/latest.json +
run_migrations.py applies the whole set in order (ledger fuel.schema_migrations): +01 base schema · 02 one-device-per-fill join fix (a plate can map to several +devices rows) · 03 standardize all fuel timestamps to Africa/Nairobi (EAT) so +record_datetime::date buckets by the Kenyan day. All idempotent.
+

3b · Recurring: the ingest cron

A scheduled container that keeps the DB current. The --snapshot full-reconcile is idempotent and self-healing (picks up edits + soft-deletes), so a simple hourly run is safe: