Staging environment + FleetOps split #17

Open
kianiadee wants to merge 23 commits from feat/staging-fleetops-architecture into main
Showing only changes of commit 2f6ab1ba3b - Show all commits

View file

@ -6,12 +6,10 @@ developers (mixed technical/ops background — readable without prior context).
> **As-built (2026-06-10).** All six surfaces are live: staging `fleetapi` / `fleetops` /
> `fleetnow` `.fivetitude.com`, and prod `fleetops.rahamafresh.com` + `/analytics/*` on
> `fleetapi.rahamafresh.com`. The dedicated read-only `dashboard_ro` role backs the staging
> bridge; the prod bridge still uses the app role (stage-2 migration to `dashboard_ro` is ready
> but deferred). Migrations 17 + 18 applied. The client's live FleetNow map was unaffected
> throughout. **Remaining operational follow-ups** (no code): register the two Forgejo→Coolify
> webhooks for the *FleetOps-prod* and *FleetNow-staging* apps (FleetOps-staging is done) per
> [`webhook-auto-deploy.html`](../../15_fleetops/docs/webhook-auto-deploy.html) in the fleetops
> repo; review/merge tracksolid PR #17.
> bridge **and now the prod bridge too** (stage 2 done — reads via `dashboard_ro`, the `v_trips`
> refresher keeps a privileged connection via `REFRESH_DATABASE_URL`). Migrations 17 + 18 applied.
> Both Forgejo→Coolify webhooks (FleetOps, FleetNow) registered + active. The client's live
> FleetNow map was unaffected throughout. **Remaining:** review/merge tracksolid PR #17.
This document describes how we (a) introduce a **staging environment** under the
`fivetitude.com` umbrella so the production FleetNow map is never edited directly, and (b)
@ -180,9 +178,11 @@ not by a separate DB:
TABLES`), `EXECUTE` on the `reporting.fn_*` map functions, and `ALTER DEFAULT PRIVILEGES` so
future objects are auto-readable ("dynamic"). No write/REFRESH privilege, so accidental writes
are impossible. The password is generated on the host into `~/.dashboard_ro.pw` (0600), never
in the repo. **Two-stage:** stage 1 backs the *staging* bridge (done); stage 2 migrates the
*live prod* `fleetapi.rahamafresh.com` connection off the app role onto `dashboard_ro` (which
already grants the full read surface, incl. the live `fn_*` path).
in the repo. **Both stages done:** staging *and* prod bridges now connect reads via
`dashboard_ro`. Because the prod bridge also runs the `v_trips` refresher (which needs write
perms `dashboard_ro` lacks), the refresher uses a **separate privileged connection**
`REFRESH_DATABASE_URL` (the app/superuser role); `DATABASE_URL` is `dashboard_ro`. Staging
keeps the refresher disabled, so it needs only `dashboard_ro`.
- The **`reporting.v_trips` materialized-view refresher is disabled on staging** — production
owns it. The refresher needs write perms and is already pg-advisory-lock guarded (key
`920_145`, FIX-D02); a read-only staging role would only log errors, so disable it explicitly