End-to-end system documentation for the BA platform — components, data flows, knowledge layer, persona workspaces, and infrastructure. Covers Great American Insurance Group and Century Surety.
Browser → Workbench Backend → CurationStudio + MongoDB. Self-contained eligibility check runs entirely in the backend without CurationStudio. LLM-dependent operations (ACORD extraction, bulletin ingest, AI chat) proxy to CurationStudio.
Each persona maps to a distinct workspace view and carrier scope. BABulletinStewardPage is the only component serving both carriers — differentiated by the carrier prop passed from App.tsx.
All BA routes accept carrier_id. Chunks in elevatenow_gkr are partitioned by carrier_id. Runtime resolution: carrier_supersedes chunk first; fall back to platform_only chunk. New carrier = one entry in carrier-config.ts only.
| Primary Color | #003087 navy |
| Accent Color | #C8A951 gold |
| Theme Class | bas-theme-ga |
| Operational DB | ga_bindingauth_gkr |
| Appetite Seed | scripts/seed_ga_ba_appetite.py |
| Primary Pages | BABindingCheckPage + BABulletinStewardPage |
| Primary Color | #1C2A6E indigo |
| Accent Color | #60a5fa blue |
| Theme Class | bas-theme-century |
| Operational DB | ga_bindingauth_gkr (shared) |
| Portfolio Pages | CenturyBAHubPage + CenturyBAMonitorPage |
| Rules Workspace | BABulletinStewardPage (carrier=CENTURY) |
carrier_id = CARRIER & override_layer = carrier_supersedes first, then falls back to override_layer = platform_only. Per-carrier customization without forking platform rules. Adding a carrier requires only a new entry in carrier-config.ts.BA rules are versioned, lifecycle-managed knowledge chunks in elevatenow_gkr.knowledge_chunks. Class appetite is a separate static table in reference_data. All chunks trace to a source bulletin via chunk_id.
Block or refer by state and/or county. State scope required; county is optional secondary filter.
Threshold gate on a named risk score field (crime_score, wildfire_score, or custom). Hard decline threshold separates hard blocks from soft referrals.
Premium floor, minimum rate, and discount/credit rules. rule_subtype drives logic path. Credits emit APPLY_CREDIT (non-restrictive — does not affect final verdict).
Coverage restrictions by construction type / wind exposure. Currently dormant — evaluator always returns null. Schema gap: fields not yet on ga_submissions.
Industry class appetite by NAICS prefix or SIC range. NAICS uses prefix match ("236" matches "236210"). SIC supports range syntax ("1521-1799").
NOT a knowledge_chunk. Static lookup seeded via seed_ga_ba_appetite.py. Queried at Gate 0 before any rule evaluation. Immediate DECLINE if class = NOT_OFFERED.
Extracted from bulletin ingest
Steward edits fields
Sanctioned — evaluated in every /check
Superseded by new bulletin
Archived, no longer evaluated
Steward also has: suspend (temp inactive, resume without re-sanction) · stage-edits → re-sanction (edit active rule in-place) · discard-pending-edits (rollback staged). All mutations write to curation_audit.
POST /api/ba/check runs entirely in the backend. Gate 0 is a static appetite lookup. Gate 1 sweeps all active knowledge_chunks through the pure rule evaluator and aggregates verdicts by severity rank.
reference_data for carrier_id match on class_of_business. Appetite = NOT_OFFERED → immediate DECLINE. Gate 1 never runs.knowledge_chunks where carrier_id matches + curation_status = active + NOT suspended. Run evaluateRule(submission, chunk) for each. Collect all non-null verdicts into firing_rules[].construction_type and wind_exposure are not yet on ga_submissions. Activating this gate requires extending the submission schema and backfilling ga_submissions.All routes require Auth0 JWT. Mounted at app.use("/api/ba", requireAuth, baRouter) in server.ts line 62. Self-contained routes talk directly to MongoDB. Proxied routes forward to CurationStudio with X-Internal-Key.
| Method | Path | Mode | Source / Upstream | Purpose |
|---|---|---|---|---|
GET | /categories | Self | reference_data | Class taxonomy tile grid |
GET | /appetite | Self | reference_data | Class × BOP/GL/WC appetite dots |
GET | /submissions | Self | ga_submissions | Historical BA submission list |
GET | /active-rules | Self | knowledge_chunks | Active rules by carrier_id |
GET | /rule-drafts | Self | knowledge_chunks | Draft rules by bulletin_id or carrier_id |
GET | /conflicts | Self | knowledge_chunks | All detected rule conflicts |
GET | /bulletin-pdf/:id | Self | ba_bulletin_documents | Raw bulletin PDF bytes |
POST | /check | Self | reference_data + knowledge_chunks | Gate 0 + Gate 1 eligibility — core BA evaluation |
POST | /rule-drafts/:id/sanction | Self | knowledge_chunks + curation_audit | Promote draft → active; writes audit entry |
PATCH | /rule-drafts/:id/fields | Self | knowledge_chunks | Edit field_extractions on draft chunk |
POST | /rule-drafts/:id/detect-conflicts | Self | knowledge_chunks | Conflict detection: draft vs active rules |
POST | /active-rules/:id/stale | Self | knowledge_chunks + curation_audit | Mark active rule stale |
POST | /active-rules/:id/suspend | Self | knowledge_chunks | Temporarily suspend rule (excluded from /check) |
POST | /active-rules/:id/resume | Self | knowledge_chunks | Resume suspended rule |
POST | /active-rules/:id/stage-edits | Self | knowledge_chunks | Queue field edits on active rule |
POST | /active-rules/:id/re-sanction | Self | knowledge_chunks + curation_audit | Apply staged edits → re-activate |
POST | /active-rules/:id/discard-pending-edits | Self | knowledge_chunks | Rollback staged changes |
POST | /extract | Proxied | → /api/gkr/ba/extract | ACORD 125/126 PDF → structured submission fields (LLM) |
POST | /chat | Proxied | → /api/gkr/ba/chat | Conversational appetite probe (AI) |
POST | /query | Proxied | → /api/gkr/ba/query | Semantic portfolio query over ga_submissions |
POST | /ingest-bulletin | Proxied | → /api/gkr/ba/ingest-bulletin | Bulletin OCR + LLM rule extraction + knowledge_chunks write |
POST | /pdf-to-text | Proxied | → /api/gkr/ba/pdf-to-text | PyMuPDF PDF → plain text extraction |
GKR knowledge lives in elevatenow_gkr (shared with UW platform). BA operational data lives in ga_bindingauth_gkr. Both on the same Atlas cluster — getBindingAuthDb() and getGkrDb() reuse claimsClient.
| Collection | BA Role |
|---|---|
knowledge_chunks | All BA rules (ba_* types) partitioned by carrier_id + curation_status. Primary source for Gate 1 evaluation. |
reference_data | Class appetite table (Gate 0) + NAICS/SIC crosswalk + vertical index. Seeded separately. |
chunk_ontology_edges | SUPERSEDES edges between old and new rule versions after bulletin updates. |
curation_audit | Immutable append-only log. Every BA lifecycle change (sanction, stale, suspend, re-sanction) writes one document. |
| Collection | BA Role |
|---|---|
ga_submissions | Historical BA submissions. Source for: portfolio impact preview (computeImpact) and AI portfolio query. |
ga_bulletins | Raw carrier bulletin metadata — source, date, carrier, ingestion status. |
ba_bulletin_documents | Binary bulletin PDF payloads + LLM extraction metadata per bulletin_id. Served via GET /bulletin-pdf/:id. |
Conflict detection runs in-process at POST /rule-drafts/:id/detect-conflicts. Steward can override and sanction anyway — a conflict is a warning requiring confirmed precedence, not a hard block.
Two ba_geographic_restriction rules share a state. Gate action precedence must be confirmed.
A ba_geographic_restriction and ba_rating_rule share a concrete (non-ALL) state. Restrictive and pricing rules may conflict.
Two ba_score_gate rules evaluate the same score_field in overlapping states. Thresholds may produce conflicting verdicts.
Two ba_class_appetite rules share NAICS codes or SIC ranges in the same state. Class eligibility outcome would be ambiguous.
Each BA persona drives a distinct data path. The producer flow is real-time eligibility. The ingest flow converts carrier PDFs into active rules. The edit flow mutates active rules without a full draft cycle.
Canonical locations for all BA source files across frontend, backend, CurationStudio, and seed scripts.
| Layer | File Path | Purpose |
|---|---|---|
| Frontend | src/pages/BABindingCheckPage.tsx | Tom Reed — 4-phase intake, ACORD extract, eligibility check, AI portfolio query (1,754 lines) |
| Frontend | src/pages/BABulletinStewardPage.tsx | Lisa Grant — rulebook, ingest, scenario, audit log. Both carriers via carrier prop (3,759 lines) |
| Frontend | src/pages/CenturyBAHubPage.tsx | Jordan Mills hub — KPI dashboard, pending rules, violation summary, broker watch (445 lines) |
| Frontend | src/pages/CenturyBAMonitorPage.tsx | Jordan Mills portfolio violations monitor (1,237 lines) |
| Config | src/config/carrier-config.ts | CARRIER_CONFIGS — GREAT_AMERICAN + CENTURY brand, products, themeClass. Add new carrier here only. |
| Config | src/config/persona-config.ts | PersonaConfig for ba_producer (Tom Reed), ba_steward (Lisa Grant), century_ba (Jordan Mills) |
| Styles | src/styles/ba-binding-check.css | Tom Reed workspace styles |
| Styles | src/styles/ba-steward.css | Lisa Grant workspace styles |
| Styles | src/styles/century-ba-hub.css · century-ba.css | Jordan Mills hub and portfolio styles |
| Backend | src/routes/ba.ts | All /api/ba/* route handlers — self-contained + proxied (~1,350 lines) |
| Backend | src/services/ba-rule-evaluator.ts | Pure rule evaluation — evaluateRule() + computeImpact(). Must stay in sync with CurationStudio mirror. |
| Backend | src/db/mongo.ts | getGkrDb() → elevatenow_gkr · getBindingAuthDb() → ga_bindingauth_gkr · both reuse claimsClient |
| Backend | src/config.ts (line 13) | curationStudioUrl (CURATION_STUDIO_URL env) + curationStudioKey (X-Internal-Key header) |
| Backend | src/server.ts (line 62) | app.use("/api/ba", requireAuth, baRouter) — BA route registration |
| CurationStudio | kcs_api_gkr_routes.py (lines 860–2884) | All /api/gkr/ba/* — extract, check, ingest-bulletin, chat, query, pdf-to-text |
| CurationStudio | scripts/seed_ga_ba_appetite.py | Seeds GA class appetite into reference_data. Run: python seed_ga_ba_appetite.py --execute |
| CurationStudio | scripts/ba_schema_enricher.py | Enriches BA chunk field_extractions post-ingest |
| CurationStudio | seed_ba_docintel_templates.py | Doc Intel extraction templates for carrier BA bulletins |
| Scripts | src/scripts/seed-ba.ts | Seeds Great American test submission data into ga_submissions |
| Scripts | src/scripts/seed-century-ba.ts | Seeds Century Surety test submission data |
| Scripts | src/scripts/list-ba-appetite.ts | Inspect current state of reference_data appetite table |
| Scripts | src/scripts/inspect-ba-portfolio.ts | Debug ga_submissions data shapes and field coverage |
| Scripts | src/scripts/fix-ba-portfolio-data.ts | Backfill corrections to ga_submissions |
BA requires frontend, backend, and CurationStudio running together. VITE_DEV_PERSONA controls which workspace loads by default. Backend CURATION_STUDIO_URL defaults to localhost:8000 in dev.
cd elevatenow-workbench-mvp
VITE_DEV_PERSONA=ba_producer npm run dev
Tom Reed / ba-intake
VITE_DEV_PERSONA=ba_steward npm run dev
Lisa Grant / ba-steward
VITE_DEV_PERSONA=century_ba npm run dev
Jordan Mills / hub
cd elevatenow-workbench-backend
npm run dev
npm run test:connection
Verify MongoDB connectivity
npx ts-node src/scripts/seed-ba.ts
Seed GA test submissions
cd elevatenow-rule-layer/CurationStudio
uvicorn kcs_api:app --reload --port 8000
Env: GROQ_API_KEY · ARTIFI_MONGO_CONNECTION_STRING
python scripts/seed_ga_ba_appetite.py --execute
First-time: seed GA appetite data
CURATION_STUDIO_URL (CurationStudio endpoint, default localhost:8000 in dev, EC2:8001 in prod) · CURATION_STUDIO_INTERNAL_KEY (X-Internal-Key header for proxied routes) · CLAIMS_MONGO_URI (artifi Atlas cluster — shared by elevatenow_gkr and ga_bindingauth_gkr)