The file had drifted four indexes behind c2-server, so the 2026-08-23 deploy offered to delete four live indexes and then added ASC copies of two that already existed as DESC. Reconciled against gcloud's actual list. Adds the two backend indexes that were live but undeclared and are genuinely in use -- calls(status, ended_at) for recorrelation_sweep's ended-call scan and calls(system_id, ended_at) for vocabulary_learner. Deleting either would have broken a background loop with no frontend symptom. Declares every index ASCENDING. Firestore scans an index in either direction, so org_id+started_at ASC already serves the orderBy(started_at, 'desc') that every frontend hook actually asks for; a matched ASC/DESC pair is one index of pure write amplification on every call document. The three duplicates now left undeclared are named in the file header so the next deploy's interactive delete prompt has a documented answer instead of a guess. Refs server-26#33. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
3.9 KiB
JSON
73 lines
3.9 KiB
JSON
{
|
|
"//": "Composite indexes for the c2-server database. Firestore auto-indexes single-field lookups and equality-only compound queries; an equality filter combined with an inequality, an orderBy on a different field, or array-contains needs an explicit composite index or the query fails at runtime with FAILED_PRECONDITION. Deploy with: firebase deploy --only firestore:indexes --project <project-id> (firebase.json pins database c2-server — without that key the CLI targets (default) and changes nothing the app can see).",
|
|
"//direction": "Every index here is declared ASCENDING. Firestore scans an index in either direction, so org_id+started_at ASC serves orderBy(started_at, 'desc') as well — which is what every frontend hook actually asks for. Declaring only the ASC form keeps one index per query shape instead of a matched pair.",
|
|
"//drift-2026-08-23": "Reconciled against `gcloud firestore indexes composite list --database=c2-server` (server-26#33). The file had drifted four indexes behind the live database, and a deploy against the stale file then added ASC copies of indexes that already existed as DESC. The next deploy will offer to delete three live indexes that are deliberately not declared here — answer YES to all three: calls(org_id ASC, started_at DESC) and incidents(org_id ASC, started_at DESC) are duplicates of the ASC entries below, and alert_events(acknowledged ASC, triggered_at DESC) predates tenancy and is superseded by the org-scoped entry below. Nothing else may be deleted.",
|
|
"indexes": [
|
|
{
|
|
"//": "drb-frontend lib/useCalls.ts — org-scoped call list, orderBy started_at desc.",
|
|
"collectionGroup": "calls",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{ "fieldPath": "org_id", "order": "ASCENDING" },
|
|
{ "fieldPath": "started_at", "order": "ASCENDING" }
|
|
]
|
|
},
|
|
{
|
|
"//": "drb-frontend lib/useCalls.ts — the calls attached to one incident.",
|
|
"collectionGroup": "calls",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{ "fieldPath": "org_id", "order": "ASCENDING" },
|
|
{ "fieldPath": "incident_ids", "arrayConfig": "CONTAINS" }
|
|
]
|
|
},
|
|
{
|
|
"//": "c2-core internal/recorrelation_sweep.py:45 — status == 'ended' AND ended_at >= cutoff. Backend only; was live but undeclared until 2026-08-23.",
|
|
"collectionGroup": "calls",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{ "fieldPath": "status", "order": "ASCENDING" },
|
|
{ "fieldPath": "ended_at", "order": "ASCENDING" }
|
|
]
|
|
},
|
|
{
|
|
"//": "c2-core internal/vocabulary_learner.py:290 — system_id == X AND ended_at >= cutoff. Backend only; was live but undeclared until 2026-08-23.",
|
|
"collectionGroup": "calls",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{ "fieldPath": "system_id", "order": "ASCENDING" },
|
|
{ "fieldPath": "ended_at", "order": "ASCENDING" }
|
|
]
|
|
},
|
|
{
|
|
"//": "drb-frontend lib/useIncidents.ts — org-scoped incident browse, orderBy started_at desc.",
|
|
"collectionGroup": "incidents",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{ "fieldPath": "org_id", "order": "ASCENDING" },
|
|
{ "fieldPath": "started_at", "order": "ASCENDING" }
|
|
]
|
|
},
|
|
{
|
|
"//": "drb-frontend lib/useAlerts.ts — org-scoped alert feed, orderBy triggered_at desc.",
|
|
"collectionGroup": "alert_events",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{ "fieldPath": "org_id", "order": "ASCENDING" },
|
|
{ "fieldPath": "triggered_at", "order": "ASCENDING" }
|
|
]
|
|
},
|
|
{
|
|
"//": "drb-frontend lib/useAlerts.ts useUnacknowledgedAlerts — the nav badge.",
|
|
"collectionGroup": "alert_events",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{ "fieldPath": "org_id", "order": "ASCENDING" },
|
|
{ "fieldPath": "acknowledged", "order": "ASCENDING" },
|
|
{ "fieldPath": "triggered_at", "order": "ASCENDING" }
|
|
]
|
|
}
|
|
],
|
|
"fieldOverrides": []
|
|
}
|