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 @@
twala.rahamafresh.com01–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.
+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.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: