docs: dashboard_ro role + two-stage rollout; mark Phase 1 done
Updates STAGING_FLEETOPS_ARCHITECTURE.md to reflect the dedicated read-only dashboard_ro role (replacing the grafana_ro reuse), the explicit v_trips matview grant, DEFAULT PRIVILEGES, host-only password, and the two-stage plan (staging now, live prod connection later). Notes migrations 17+18 applied; Phase 0 read-only role complete, webhook deploys still pending. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
cbbe3dab87
commit
2603f0e726
1 changed files with 15 additions and 8 deletions
|
|
@ -82,7 +82,7 @@ Traefik host `fleetapi.rahamafresh.com`). Staging mirrors it:
|
|||
| Port | 8890 | **8891** |
|
||||
| Code mount | `~/dashboard_api/` | `~/dashboard_api_staging/` (WIP checkout) |
|
||||
| Deploy script | `~/deploy_dashboard_api.sh` | **`deploy_dashboard_api_staging.sh`** (checked into this repo) |
|
||||
| DB role | app role (read/write) | **read-only** (`dashboard_ro` / `grafana_ro`) |
|
||||
| DB role | app role (read/write) | **read-only** `dashboard_ro` (dedicated) |
|
||||
| `v_trips` refresher | **owns it** | **disabled** |
|
||||
| CORS origins | `fleetnow.rahamafresh.com`, `fleetintelligence.…`, `liveposition.…`, **+ `fleetops.rahamafresh.com`** | `fleetnow.fivetitude.com`, `fleetops.fivetitude.com` |
|
||||
|
||||
|
|
@ -105,9 +105,9 @@ the JSONB/GeoJSON return style of the existing `/webhook/*` routes:
|
|||
| `GET /analytics/filters` | `reporting.v_filter_*` (alias of `GET /webhook/fleet-dashboard`) |
|
||||
|
||||
Aggregations that aren't thin wrappers get a **new numbered migration** — never edit an applied
|
||||
one. The fuel roll-up ships as `migrations/17_fleetops_fuel_view.sql` (the live migration head is
|
||||
**16**, not 13 as older docs imply); it also `GRANT`s `SELECT` to `grafana_ro` for the staging
|
||||
read-only role.
|
||||
one. The fuel roll-up ships as `migrations/17_fleetops_fuel_view.sql` (the live migration head was
|
||||
**16**, not 13 as older docs imply; 17 + 18 are now applied). `dashboard_ro` reads `v_fuel_daily`
|
||||
via the schema-wide `SELECT` grant in `scripts/dashboard_ro_role.sql`.
|
||||
|
||||
> **Reuse the existing reporting layer.** The analytics building blocks are `reporting.*`
|
||||
> (migrations 11/14) and the surviving `tracksolid.v_*` views (migration 07). The `ops.*` and
|
||||
|
|
@ -163,9 +163,16 @@ Production is touched **only** by a merge to `main`. That branch discipline is w
|
|||
Staging hits the **production database**, so isolation is enforced at the **DB-role level**,
|
||||
not by a separate DB:
|
||||
|
||||
- The staging `dashboard_api` connects as a **read-only role** — reuse `grafana_ro`, or add a
|
||||
dedicated `dashboard_ro` with `GRANT SELECT` on `reporting.*` and the `tracksolid.v_*`
|
||||
views. Accidental writes from staging are then impossible.
|
||||
- The staging `dashboard_api` connects as a **dedicated read-only role `dashboard_ro`**
|
||||
(`scripts/dashboard_ro_role.sql` + `scripts/bootstrap_dashboard_ro.sh`). It grants exactly
|
||||
what the API reads — `SELECT` on `reporting.*` + `tracksolid.*`, an explicit `SELECT` on the
|
||||
`reporting.v_trips` **materialized view** (matviews aren't covered by `GRANT ... ON ALL
|
||||
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).
|
||||
- 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
|
||||
|
|
@ -182,7 +189,7 @@ client's production domains **last**.
|
|||
|
||||
| Phase | Scope | Exit criterion |
|
||||
|---|---|---|
|
||||
| **0 — Foundation** | This document; migrate all Coolify apps to Forgejo webhook deploys; provision the read-only DB role | Every existing Coolify app redeploys via webhook; read-only role can `SELECT` `reporting.*` + `tracksolid.v_*` and nothing else |
|
||||
| **0 — Foundation** | This document; provision the read-only `dashboard_ro` role (**done**); migrate all Coolify apps to Forgejo webhook deploys (**pending**) | `dashboard_ro` can `SELECT` `reporting.*` + `tracksolid.*` + `v_trips` and nothing else; every Coolify app redeploys via webhook |
|
||||
| **1 — Staging backbone** | Staging `dashboard_api` bridge (`deploy_dashboard_api_staging.sh`, 8891, `fleetapi.fivetitude.com`, read-only, refresher off, staging CORS) | `curl https://fleetapi.fivetitude.com/health` ok; verifiably read-only; no staging rows in `reporting.refresh_log` |
|
||||
| **2 — FleetNow staging** | FleetNow repo: `staging` branch + parameterized API base + `fleetnow.fivetitude.com` Coolify app | Renders against staging API; `staging` push deploys staging only, `main` merge deploys prod only; prod FleetNow untouched |
|
||||
| **3 — FleetOps backend** | `/analytics/*` endpoints in `dashboard_api_rev.py` + `migrations/17_fleetops_fuel_view.sql`; refresher made disable-able (`VTRIPS_REFRESH_INTERVAL_S<=0`); tested on the staging API | Every route returns correct shape on `fleetapi.fivetitude.com`; fuel route returns "needs data" flags |
|
||||
|
|
|
|||
Loading…
Reference in a new issue