feat: tickets.inc_open_sla view + lowercase legacy region
- Add tickets.inc_open_sla: open tickets with derived SLA (hours_open, sla_state vs 48h; clock = created_at_service or first_seen_at fallback) + team/cluster/geog for dispatch. (One-time legacy region->lowercase backfill applied to live data.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e54e2b7c56
commit
8e119e2328
2 changed files with 61 additions and 0 deletions
|
|
@ -18,6 +18,7 @@ Field-ops **INC ticket** ingestion, geocoding, and read-schema that powers the
|
|||
| `migrations/05_inc_geography.sql` | Adds `geog geography(Point,4326)` (= `geom::geography`) + GiST index for **routing** — `ST_Distance`/`ST_DWithin`/KNN in real metres (nearest-vehicle, radius search) |
|
||||
| `migrations/06_inc_mttr_minutes.sql` | `mttr` generated column → integer **minutes** (source is decimal hours); drops the constant `is_alarm`/`is_auto_created`/`is_auto_closed` columns (kept in `raw`). `is_actionable` retained |
|
||||
| `migrations/07_inc_drop_service_type.sql` | Drops the constant `service_type` column (always `inc`; kept in `raw`) |
|
||||
| `migrations/08_inc_open_sla_view.sql` | `tickets.inc_open_sla` view — open (`is_actionable`) tickets with **derived SLA** (`hours_open`, `sla_state` vs 48h; clock = `created_at_service` ∥ `first_seen_at`), plus team/cluster/`geog` for dispatch |
|
||||
| `import_tickets.py` | Ingests the **newest INC CSV** from the rustfs `tickets` bucket (`automations/inc/<EAT-timestamp>.csv`) and upserts on `ticket_id`; geocodes clusters + INC locations |
|
||||
| `run_migrations.py` | Applies `migrations/*.sql` in order (ledger: `tickets.schema_migrations`) |
|
||||
| `shared.py` | Minimal DB/logging helpers (self-contained — no tracksolid dependency) |
|
||||
|
|
|
|||
60
migrations/08_inc_open_sla_view.sql
Normal file
60
migrations/08_inc_open_sla_view.sql
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
-- 08_inc_open_sla_view.sql — fleettickets · open-ticket SLA view
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
-- reporting view over the open (is_actionable) INC tickets with a DERIVED SLA
|
||||
-- state, since the source sla_status is only meaningful once a ticket is closed.
|
||||
--
|
||||
-- SLA clock = created_at_service, falling back to first_seen_at (the export's
|
||||
-- first-sighting) when creation is missing (~70% of open rows lack
|
||||
-- created_at_service); sla_clock_source flags which was used. Contract rule: 48h.
|
||||
-- hours_open / sla_state use now(), so the view is always current. Includes the
|
||||
-- routing-grade geog so dispatch can join straight off it.
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
SET search_path = tickets, public;
|
||||
|
||||
CREATE OR REPLACE VIEW tickets.inc_open_sla AS
|
||||
SELECT
|
||||
ticket_id,
|
||||
normalized_status,
|
||||
bucket,
|
||||
cluster,
|
||||
region,
|
||||
location_name,
|
||||
assigned_team,
|
||||
owner,
|
||||
sla_status AS source_sla_status,
|
||||
mttr, -- minutes (null until closed)
|
||||
COALESCE(created_at_service, first_seen_at) AS sla_clock,
|
||||
CASE WHEN created_at_service IS NOT NULL THEN 'service' ELSE 'first_seen' END AS sla_clock_source,
|
||||
round((EXTRACT(EPOCH FROM now() - COALESCE(created_at_service, first_seen_at)) / 3600)::numeric, 1) AS hours_open,
|
||||
CASE
|
||||
WHEN COALESCE(created_at_service, first_seen_at) IS NULL THEN 'unknown'
|
||||
WHEN now() - COALESCE(created_at_service, first_seen_at) >= interval '48h' THEN 'breached'
|
||||
WHEN now() - COALESCE(created_at_service, first_seen_at) >= interval '36h' THEN 'at_risk'
|
||||
ELSE 'ok'
|
||||
END AS sla_state,
|
||||
created_at_service,
|
||||
first_seen_at,
|
||||
scheduled_at,
|
||||
latitude,
|
||||
longitude,
|
||||
geo_source,
|
||||
geom,
|
||||
geog
|
||||
FROM tickets.inc
|
||||
WHERE is_actionable;
|
||||
|
||||
COMMENT ON VIEW tickets.inc_open_sla IS
|
||||
'Open (is_actionable) INC tickets with derived SLA (48h rule; clock = created_at_service '
|
||||
'or first_seen_at fallback). fleettickets 08.';
|
||||
|
||||
-- grants (guarded: roles may not exist on a fresh DB)
|
||||
DO $grants$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'dashboard_ro') THEN
|
||||
GRANT SELECT ON tickets.inc_open_sla TO dashboard_ro;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'grafana_ro') THEN
|
||||
GRANT SELECT ON tickets.inc_open_sla TO grafana_ro;
|
||||
END IF;
|
||||
END $grants$;
|
||||
Loading…
Reference in a new issue