Appearance
Atlas Access Matrix
Generated from
infra/atlas/access-matrix.tsbynpm run docs:atlas. Do not edit by hand.
Canonical source of truth for every MongoDB Atlas user, role, env-var binding, and code consumer across the AskFlorence stack. Read this file first before adding or modifying any Mongo user — it tells you what already exists and which code paths break if you narrow privileges.
Summary
- Total users: 19
- Active: 19
- Legacy / pending deletion: 0
- Staging cluster users: 13
- Prod cluster users: 6
How this stays accurate
Three CI guards keep this doc + the manifest + Terraform + the live Atlas state in sync. Live ECS task defs are now in sync with Terraform source by construction — Terraform owns the task definition resource end-to-end as of ENG-277 (2026-05-13). See ADR 0007.
atlas-env-var-coverage(PR-time, static) — every env-var declared in the manifest must be wired in the corresponding Terraforminfra/envs/<env>/*.tf files. Catches the ENG-272 class of bug (manifest says "this env needs this var" but Terraform doesn't wire it).staging-cluster-drift(nightly, live Atlas) — every active user withnightlyDriftCheck=trueis verified against the live Atlas API. Catches the ENG-239 class of bug (someone widens a role via Atlas UI by hand).atlas-docs-sync(PR-time, static) — re-runsnpm run docs:atlasandgit diffs the result. If the committed doc is stale, the PR fails. Catches the ENG-272 class of doc-rot (manifest changes but the human-readable view doesn't).
Workflow when adding a new user or modifying an existing one: see the file header in infra/atlas/access-matrix.ts.
Why this matrix exists
Three earlier issues (ENG-239, ENG-249/PR91, ENG-271) each added or narrowed a Mongo user without a single place to verify the change against the FULL set of code paths that depend on it. ENG-272 surfaced the resulting silent regression: ENG-271's narrowing of staging's MONGODB_URI from app_read_staging → app_read_local_staging lost FIND on providers_staging + formularies_staging, and getReferenceDb() silently fell back to the wrong user. The break shipped to apex (the YC-application surface) and was only caught when the founder typed a real doctor name and saw "not covered" incorrectly.
This matrix prevents that class of failure by making the FULL access surface visible in one file, with CI-enforced consistency between four layers (manifest, Terraform, Atlas API, doc).
Compliance / audit relevance
- SOC 2 CC6.1 — least privilege per user, demonstrable via this file
- SOC 2 CC6.6 — segmentation enforced (no
inheritedRoles, no cross-collection grants beyond the privilege list here) - HIPAA § 164.312(a)(1) — access control narrow + auditable
- EDE Phase 3 — auditor lookback can grep this file's git history to reconstruct who had access to what at any point in time
Staging cluster
app_read_local_staging
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_reader_local_staging |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: plans, zip_county, regions, plan_years, audit_log, agent_waitlist_submissions
Env-var bindings:
- staging →
MONGODB_URI
Consumers:
src/lib/db.ts:getDb() (staging deploy)src/app/api/eligibility/route.tssrc/app/api/plans/route.tssrc/app/api/counties/route.tssrc/app/api/agents/discovery/route.ts (back-link dedup)
Rationale: ENG-271 — separated deployment-local reads from cross-cluster reference reads after ENG-239 narrowing of app_read_staging broke the staging consumer flow. Companion to app_read_staging.
app_read_staging
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_reader_reference |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: formularies_staging, providers_staging, drug_search_index, plans, mrpuf_issuers_staging
Env-var bindings:
- staging →
MONGODB_REFERENCE_URI - prod →
MONGODB_REFERENCE_URI - local →
MONGODB_URI
Consumers:
src/lib/db.ts:getReferenceDb()src/lib/provider-network-fallback.ts:lookupStagingProviderNetworks()src/lib/drug-tier-fallback.ts:lookupStagingDrugTiers()src/app/api/providers/covered/route.ts (network_tier enrichment)src/app/api/drugs/covered/route.ts (drug_tier enrichment)
Rationale: ADR 0004 + Phase 11 — cross-cluster PrivateLink reads from prod into staging cluster's §1311 MRF dataset. ENG-272 added the missing staging env-var binding so staging doesn't 500 on the same code path that works on prod.
app_writer_survey
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_writer_survey |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agent_survey_responses - INSERT on
askflorence: agent_survey_responses - UPDATE on
askflorence: agent_survey_responses - CREATE_INDEX on
askflorence: agent_survey_responses - LIST_INDEXES on
askflorence: agent_survey_responses
Env-var bindings:
- staging →
MONGODB_URI_SURVEY_WRITE - local →
MONGODB_URI_SURVEY_WRITE
Consumers:
src/app/api/agents/discovery/route.ts (survey insert + partial-save)scripts/agent-discovery-cron-reminder.ts (read partials)
Rationale: Issue #56 / Phase 2 — narrow writer for /agent-discovery survey. CLAUDE.md compliance: never share user with waitlist/agents writers.
app_writer_plans
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_writer_plans |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: plans, zip_county, regions, plan_years, audit_log - INSERT on
askflorence: plans, zip_county, regions, plan_years, audit_log - UPDATE on
askflorence: plans, zip_county, regions, plan_years, audit_log - REMOVE on
askflorence: plans, zip_county, regions, plan_years - CREATE_INDEX on
askflorence: plans, zip_county, regions, plan_years, audit_log
Env-var bindings:
- staging →
MONGODB_URI_PLANS_WRITE - local →
MONGODB_URI_PLANS_WRITE
Consumers:
scripts/db/ingest-puf-augment.jsscripts/db/ingest-qrs-ratings.jsscripts/db/* (other ingest scripts)
Rationale: Issue #56 — narrow writer for ingest scripts. Replaces app-write usage in scripts/db/*.
app_writer_waitlist
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_writer_waitlist |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agent_waitlist_submissions - INSERT on
askflorence: agent_waitlist_submissions - UPDATE on
askflorence: agent_waitlist_submissions - CREATE_INDEX on
askflorence: agent_waitlist_submissions - LIST_INDEXES on
askflorence: agent_waitlist_submissions
Env-var bindings:
- staging →
MONGODB_URI_WAITLIST_WRITE - local →
MONGODB_URI_WAITLIST_WRITE
Consumers:
src/app/api/waitlist/route.ts (consumer + agent waitlist writes)
Rationale: Issue #56 commit 07fd8aa — narrow writer for /api/waitlist. Used by both consumer and agent flows.
app_writer_hubspot_sync
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_writer_hubspot_sync |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log - INSERT on
askflorence: hubspot_sync_log - UPDATE on
askflorence: hubspot_sync_log - CREATE_INDEX on
askflorence: hubspot_sync_log
Env-var bindings:
- staging →
MONGODB_URI_HUBSPOT_SYNC_WRITE - local →
MONGODB_URI_HUBSPOT_SYNC_WRITE
Consumers:
src/lib/hubspot/sync.ts:getHubSpotSyncWriteClient()scripts/hubspot/backfill.ts (with --apply)
Rationale: PR91 — distinct from app_writer_waitlist because main's earlier ENG-249 attempt re-used waitlist user and ran into perm-denied on hubspot_sync_log writes (commit b77a1ba degrade-gracefully fix).
app_writer_agents
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_writer_agents |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agents, agencies, agent_sessions, agent_audit_log - INSERT on
askflorence: agents, agencies, agent_sessions, agent_audit_log - UPDATE on
askflorence: agents, agencies, agent_sessions - REMOVE on
askflorence: agent_sessions - CREATE_INDEX on
askflorence: agents, agencies, agent_sessions
Env-var bindings:
- staging →
MONGODB_URI_AGENTS_WRITE - local →
MONGODB_URI_AGENTS_WRITE
Consumers:
src/app/api/agents/* (Phase 5 portal, not yet in use)
Rationale: Issue #56 / Phase 5 — narrow writer for agent portal. Append-only on agent_audit_log per ADR 0002.
app_admin_agents
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_admin_agents |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agents, agencies, agent_sessions, agent_audit_log, admins - INSERT on
askflorence: agents, agencies, agent_sessions, agent_audit_log - UPDATE on
askflorence: agents, agencies, agent_sessions, admins - REMOVE on
askflorence: agent_sessions - CREATE_INDEX on
askflorence: agents, agencies, agent_sessions, admins
Env-var bindings:
- staging →
MONGODB_URI_AGENTS_ADMIN - local →
MONGODB_URI_AGENTS_ADMIN
Consumers:
src/app/admin/* (Phase 5, not yet in use)
Rationale: Issue #56 / Phase 5 — admin dashboard writer. Append-only on agent_audit_log preserved (no UPDATE/REMOVE).
app_admin_schema
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_admin_schema |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log - CREATE_INDEX on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log - LIST_INDEXES on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log - DROP_INDEX on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log
Env-var bindings:
- staging →
MONGODB_URI_ADMIN_SCHEMA
Consumers:
scripts/db/ensure-indexes.ts (run via in-VPC ECS RunTask in deploy workflow)
Rationale: ENG-266 Phase 3.5 — separate admin user for deploy-time index ensure. Removed from request-time route handlers; runs in a one-shot Fargate task before the ECS service swap.
audit_reader
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_audit_reader |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agent_audit_log
Env-var bindings:
- staging →
MONGODB_URI_AUDIT_READ - local →
MONGODB_URI_AUDIT_READ
Consumers:
ad-hoc compliance queries (no production code path yet — Phase 5)
Rationale: Issue #56 — read-only auditor. Sole user with FIND on agent_audit_log without any write privilege.
app_read
| field | value |
|---|---|
| Cluster | staging |
| Custom role | (built-in) |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
Built-in role — privileges not enumerated here.
Env-var bindings:
- staging →
MONGODB_URI - local →
MONGODB_URI
Consumers:
src/lib/db.ts:getDb() (staging deploy + local dev primary)src/lib/db.ts:getReferenceDb() (staging deploy local + cross-cluster source for prod via PrivateLink)src/app/api/eligibility/route.tssrc/app/api/plans/route.tssrc/app/api/counties/route.tssrc/app/api/providers/covered/route.ts (network_tier enrichment via cross-cluster path)src/app/api/drugs/covered/route.ts (drug_tier enrichment via cross-cluster path)src/app/api/agents/discovery/route.ts (back-link dedup)
Rationale: ENG-279 / ADR 0006 — consolidated reader. Replaces app_read_local_staging + app_read_staging. Built-in read on askflorence DB covers every collection the app reads (no per-collection role enumeration). Cross-cluster reads (prod -> staging) go through this same user via the staging-cluster PrivateLink endpoint.
app_write
| field | value |
|---|---|
| Cluster | staging |
| Custom role | (built-in) |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
Built-in role — privileges not enumerated here.
Env-var bindings:
- staging →
MONGODB_WRITE_URI - local →
MONGODB_WRITE_URI
Consumers:
src/lib/agent-db.ts:getSurveyWriteClient()src/lib/agent-db.ts:getWaitlistWriteClient()src/lib/agent-db.ts:getHubSpotSyncWriteClient()scripts/db/* (ingest + maintenance scripts)scripts/hubspot/backfill.ts (with --apply)ENG-236 LARK delta-aware MRF refresh pipeline (writes mrf_file_state_staging, formularies_staging, providers_staging)
Rationale: ENG-279 / ADR 0006 — consolidated writer. Replaces app_writer_survey, app_writer_plans, app_writer_waitlist, app_writer_hubspot_sync, app_writer_agents, app_admin_agents. Built-in readWrite on askflorence DB covers every collection the app writes plus future collections (e.g., mrf_file_state_staging) without role updates. Phase 5 per-tenant isolation shifts to MongoDB views + JWT-in-middleware rather than per-tenant DB users (see ADR 0006).
app_audit_writer
| field | value |
|---|---|
| Cluster | staging |
| Custom role | role_audit_writer |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agent_audit_log - INSERT on
askflorence: agent_audit_log
Env-var bindings:
- staging →
MONGODB_AUDIT_WRITE_URI - local →
MONGODB_AUDIT_WRITE_URI
Consumers:
src/lib/db.ts:getAuditDb() (Phase 5 audit-log writers; no consumer Phase 1-4)
Rationale: ENG-279 / ADR 0006 — consolidated append-only audit writer. Preserves ADR 0002 verbatim (FIND + INSERT on agent_audit_log only; UPDATE/REMOVE denied at the DB permission layer). Replaces the dual append-only-on-audit_log grant previously embedded in role_writer_agents + role_admin_agents.
Prod cluster
app-read
| field | value |
|---|---|
| Cluster | prod |
| Custom role | (built-in) |
| Status | 🟢 active |
| Nightly drift check | ❌ no |
Privileges:
Built-in role — privileges not enumerated here.
Env-var bindings:
- prod →
MONGODB_URI - local →
MONGODB_URI
Consumers:
src/lib/db.ts:getDb()src/lib/agent-db.ts (read paths)src/app/api/eligibility/route.ts (zip lookup → CMS proxy)src/app/api/plans/route.ts (plan filter / search)
Rationale: Phase 8 prod rollout deferred narrow users to a follow-up. Issue #56 prod session adds app_read_prod + writers; app-read deleted in lockstep.
app-write
| field | value |
|---|---|
| Cluster | prod |
| Custom role | (built-in) |
| Status | 🟢 active |
| Nightly drift check | ❌ no |
Privileges:
Built-in role — privileges not enumerated here.
Env-var bindings:
- prod →
MONGODB_WRITE_URI - local →
MONGODB_WRITE_URI
Consumers:
src/lib/agent-db.ts (write paths until narrowed)scripts/db/* ingest scripts
Rationale: Dev-convenience writer. CLAUDE.md hard rule: deletion is exit criterion on Issue #56 before prod GA.
app_admin_schema
| field | value |
|---|---|
| Cluster | prod |
| Custom role | role_admin_schema |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log - CREATE_INDEX on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log - LIST_INDEXES on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log - DROP_INDEX on
askflorence: agent_waitlist_submissions, agent_survey_responses, hubspot_sync_log
Env-var bindings:
- prod →
MONGODB_URI_ADMIN_SCHEMA
Consumers:
scripts/db/ensure-indexes.ts (run via in-VPC ECS RunTask in deploy workflow)
Rationale: ENG-266 Phase 3.5 prod mirror — separate admin user for deploy-time index ensure on the prod cluster. Identical pattern to staging's app_admin_schema (entry above).
app_read
| field | value |
|---|---|
| Cluster | prod |
| Custom role | (built-in) |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
Built-in role — privileges not enumerated here.
Env-var bindings:
- prod →
MONGODB_URI
Consumers:
src/lib/db.ts:getDb() (prod deploy)src/app/api/eligibility/route.tssrc/app/api/plans/route.tssrc/app/api/counties/route.tssrc/app/api/agents/discovery/route.ts (back-link dedup)
Rationale: ENG-279 / ADR 0006 — consolidated prod reader. Replaces app-read (hyphenated, built-in read) — same role shape, new snake_case name aligned with staging. Issue #56 prod deletion criterion satisfied at Phase G.
app_write
| field | value |
|---|---|
| Cluster | prod |
| Custom role | (built-in) |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
Built-in role — privileges not enumerated here.
Env-var bindings:
- prod →
MONGODB_WRITE_URI
Consumers:
src/lib/agent-db.ts:getSurveyWriteClient()src/lib/agent-db.ts:getWaitlistWriteClient()src/lib/agent-db.ts:getHubSpotSyncWriteClient()scripts/db/* when run against prod cluster
Rationale: ENG-279 / ADR 0006 — consolidated prod writer. Replaces app-write (hyphenated, built-in readWrite). CLAUDE.md exit criterion: app-write deletion before production launch is satisfied at Phase G.
app_audit_writer
| field | value |
|---|---|
| Cluster | prod |
| Custom role | role_audit_writer |
| Status | 🟢 active |
| Nightly drift check | ✅ yes |
Privileges:
- FIND on
askflorence: agent_audit_log - INSERT on
askflorence: agent_audit_log
Env-var bindings:
- prod →
MONGODB_AUDIT_WRITE_URI
Consumers:
src/lib/db.ts:getAuditDb() (Phase 5 audit-log writers)
Rationale: ENG-279 / ADR 0006 — consolidated append-only audit writer on prod cluster. Mirror of staging app_audit_writer. ADR 0002 append-only property preserved.