ElevateNow · enCODE™ · Technical Architecture

Binding Authority
Architecture & Technical Reference

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.

Date: June 2026 Version: v1.0 Classification: Internal — Technical Carriers: Great American · Century Surety

Three-tier architecture built on governed knowledge

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.

Consumer Layer — React 19 · Cloudflare Pages · auto-deploy from en-workspace.git
BABindingCheckPage.tsx
  • Persona: Tom Reed (ba_producer) · View: ba-intake
  • 1,754 lines · 4 phases: landing → extracting → checking → result
  • Quick form + ACORD 125/126 PDF/DOCX upload
  • LLM entity extraction → editable entity rows
  • Appetite tile grid (category expand, BOP/GL/WC dots)
  • AI portfolio query (POST /ba/query)
  • Risk attrs: construction_type, wind_zone for future ba_coverage_gate
BABulletinStewardPage.tsx
  • Persona: Lisa Grant (ba_steward) · 3,759 lines
  • Views: ba-steward · century-ba-rulebook · century-ba-ingest · century-ba-scenario · century-ba-audit
  • Serves both carriers via carrier prop (CARRIER_CONFIGS.GREAT_AMERICAN or .CENTURY)
  • Tab Rulebook: active rules, field editors, conflict alerts, suspend/resume/stage/re-sanction
  • Tab Ingest: bulletin upload → draft queue → review → sanction
  • Tab Scenario: portfolio impact preview (computeImpact)
  • Tab Audit Log: immutable mutation history from curation_audit
CenturyBAHubPage.tsx + CenturyBAMonitorPage.tsx
  • Persona: Jordan Mills (century_ba)
  • Views: century-ba-hub · century-ba-portfolio
  • Hub: KPI strip, pending rules (GET /rule-drafts?carrier_id=CENTURY), top violations, rule frequency, broker watch, recent activity
  • Monitor: post-bind portfolio violations surface, premium-at-risk, per-policy action management
↑ Auth0 JWT Bearer — all /api/ba/* routes gated by requireAuth middleware
Application Layer — Express 4.21 · EC2:3001 · en-workspace-backend.enowclear360.com
routes/ba.ts — Self-Contained Routes (no CurationStudio dep)
  • GET /categories, GET /appetite → reference_data
  • GET /submissions → ga_submissions
  • GET /active-rules, GET /rule-drafts, GET /conflicts → knowledge_chunks
  • GET /bulletin-pdf/:id → ba_bulletin_documents
  • POST /check → Gate 0 (reference_data) + Gate 1 (knowledge_chunks)
  • POST /sanction, PATCH /fields, POST /detect-conflicts
  • POST /stale · /suspend · /resume · /stage-edits · /re-sanction · /discard-pending-edits
routes/ba.ts — Proxied to CurationStudio
  • POST /extract → /api/gkr/ba/extract
  • POST /chat → /api/gkr/ba/chat
  • POST /query → /api/gkr/ba/query
  • POST /ingest-bulletin → /api/gkr/ba/ingest-bulletin
  • POST /pdf-to-text → /api/gkr/ba/pdf-to-text
  • Header: X-Internal-Key (CURATION_STUDIO_INTERNAL_KEY env)
  • URL: CURATION_STUDIO_URL env (default: localhost:8000)
services/ba-rule-evaluator.ts
  • evaluateRule(sub, chunk) → Verdict | null
  • computeImpact(subs[], chunk) → { affected[], premium_at_risk }
  • Pure functions — no DB, no network calls
  • Mirrored in kcs_api_gkr_routes.py (_evaluate_ba_rule)
  • Verdicts: ACCEPT · REFER · DECLINE · REQUIRE_ENDORSEMENT · NOT_OFFERED · APPLY_CREDIT
  • Severity: DECLINE=4, REFER=3, REQ_END=2, CREDIT=1, ACCEPT=0
↑ X-Internal-Key    ↑ MongoDB Atlas driver (shared client)    ↑ GitHub Actions → Docker → ECR → EC2
Intelligence Layer — CurationStudio FastAPI · EC2:8001 · gkr-curationstudio.elevatenow.tech + MongoDB Atlas · artifi.2vi2m.mongodb.net
kcs_api_gkr_routes.py (BA endpoints, lines 860–2884)
  • POST /api/gkr/ba/extract — ACORD 125/126 LLM field parse
  • POST /api/gkr/ba/check — full 4-gate eval (CurationStudio-internal)
  • POST /api/gkr/ba/ingest-bulletin — OCR + LLM rule extraction + knowledge_chunks write as draft
  • POST /api/gkr/ba/chat — AI conversational appetite probe
  • POST /api/gkr/ba/query — semantic portfolio query over ga_submissions
  • GET /api/gkr/ba/appetite · GET /api/gkr/ba/categories
  • POST /api/gkr/ba/pdf-to-text — PyMuPDF text extraction
elevatenow_gkr (MongoDB)
  • knowledge_chunks — BA rules (ba_* types) partitioned by carrier_id + curation_status
  • reference_data — class appetite table + NAICS/SIC crosswalk + vertical index
  • chunk_ontology_edges — SUPERSEDES edges between BA rule versions
  • curation_audit — immutable log of all BA lifecycle mutations
  • Override: platform_only → carrier_supersedes fallback at runtime
ga_bindingauth_gkr (MongoDB)
  • ga_submissions — historical BA submissions (portfolio impact + AI query source)
  • ga_bulletins — raw bulletin metadata (source, date, carrier)
  • ba_bulletin_documents — binary PDFs + extraction metadata per bulletin_id
  • Client: getBindingAuthDb() reuses claimsClient (same Atlas cluster)
↑ Auth0 JWT tenant    ↑ Cloudflare Pages auto-deploy    ↑ ECR: 867344440197.dkr.ecr.us-east-1.amazonaws.com/curation-studio-backend
Infrastructure Layer
Cloudflare Pages
  • Frontend auto-deploy on push to en-workspace.git
  • Build: tsc -b && vite build
  • VITE_API_URL → backend
EC2 — Workbench Backend
  • en-workspace-backend.enowclear360.com · Port 3001
  • Env: CURATION_STUDIO_URL · CURATION_STUDIO_INTERNAL_KEY · CLAIMS_MONGO_URI
EC2 — CurationStudio
  • gkr-curationstudio.elevatenow.tech · Port 8001 · FastAPI Docker
  • Deploy: GitHub Actions → ECR → EC2
  • Env: GROQ_API_KEY · ARTIFI_MONGO_CONNECTION_STRING · GITHUB_PAT
MongoDB Atlas
  • artifi.2vi2m.mongodb.net
  • Shared cluster: elevatenow_gkr + ga_bindingauth_gkr
  • Connection pooled — lazy init on first call
Auth0
  • dev-y34ckcr0xp2b4064.us.auth0.com
  • JWT bearer token on all /api/* routes
  • requireAuth middleware · ENFORCE_AUTH in prod

Three personas, two carriers, one unified rule pipeline

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.

TR
Tom Reed
BA Producer · id: ba_producer
Great American default: ba-intake
Goal: Submit a risk, receive eligibility verdict and indicative quote instantly with governance citation.
  • Quick form or ACORD 125/126 PDF upload
  • LLM entity extraction → editable fields
  • Gate 0 + Gate 1 eligibility check (POST /check)
  • Firing rule citation: chunk_id + verbatim rationale
  • AI portfolio query (natural language, POST /query)
  • Risk attribute capture for coverage gate (future)
LG
Lisa Grant
BA Rules Steward · id: ba_steward
Great American Century Surety default: ba-steward
Goal: Ingest carrier bulletins, govern rule changes, preview portfolio impact before activating.
  • Bulletin ingest → OCR + LLM rule extraction → draft chunks
  • Field review and editing (PATCH /fields)
  • Conflict detection before sanction
  • Portfolio impact preview (computeImpact)
  • Sanction → active · suspend · resume · stage-edits → re-sanction
  • Immutable audit log (curation_audit)
JM
Jordan Mills
BA Portfolio Manager · id: century_ba
Century Surety default: hub
Goal: Monitor post-bind portfolio for rule violations and broker compliance across Century's book.
  • Pending rules queue from bulletin ingest
  • Top portfolio violations sorted by premium breach
  • Rule violation frequency by rule ID
  • Broker watch — violation rate per broker (critical/warning tiers)
  • Recent activity feed — sanctions, conflicts, flags

One rule engine, carrier-scoped knowledge partitions

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.

GA
Great American Insurance Group
carrier_id: GREAT_AMERICAN
BOPGLWC
Primary Color#003087 navy
Accent Color#C8A951 gold
Theme Classbas-theme-ga
Operational DBga_bindingauth_gkr
Appetite Seedscripts/seed_ga_ba_appetite.py
Primary PagesBABindingCheckPage + BABulletinStewardPage
CS
Century Surety
carrier_id: CENTURY
BOPGLWC
Primary Color#1C2A6E indigo
Accent Color#60a5fa blue
Theme Classbas-theme-century
Operational DBga_bindingauth_gkr (shared)
Portfolio PagesCenturyBAHubPage + CenturyBAMonitorPage
Rules WorkspaceBABulletinStewardPage (carrier=CENTURY)
Two-Layer Knowledge Resolution: Runtime checks 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.

Five governed chunk types — deterministic, zero-LLM evaluation

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.

ba_geographic_restriction

Block or refer by state and/or county. State scope required; county is optional secondary filter.

states[], county_list[], gate_action
DECLINEREFER

ba_score_gate

Threshold gate on a named risk score field (crime_score, wildfire_score, or custom). Hard decline threshold separates hard blocks from soft referrals.

score_field, threshold, hard_decline_threshold, applies_to_states[], gate_action, eligible_below_threshold
DECLINEREFER

ba_rating_rule

Premium floor, minimum rate, and discount/credit rules. rule_subtype drives logic path. Credits emit APPLY_CREDIT (non-restrictive — does not affect final verdict).

rule_subtype (premium_floor|minimum_rate|discount|credit), amount, rate_new, applies_to_states[], applies_to_county, elected_forms[]
DECLINEREFERAPPLY_CREDIT

ba_coverage_gate

Coverage restrictions by construction type / wind exposure. Currently dormant — evaluator always returns null. Schema gap: fields not yet on ga_submissions.

applies_to_states[], construction_type, wind_exposure [PENDING]
PENDING — schema gap

ba_class_appetite

Industry class appetite by NAICS prefix or SIC range. NAICS uses prefix match ("236" matches "236210"). SIC supports range syntax ("1521-1799").

naics_codes[], sic_ranges[], applies_to_states[], appetite (DECLINE|REFER|CONDITIONAL|NOT_OFFERED)
DECLINEREFER

reference_data (appetite table)

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.

carrier_id, class_of_business, products[], appetite
NOT_OFFERED → immediate DECLINE

Chunk Lifecycle

draft

Extracted from bulletin ingest

review

Steward edits fields

active

Sanctioned — evaluated in every /check

stale

Superseded by new bulletin

expired

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.

Two-gate eligibility check — self-contained, zero LLM

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.

0
Gate 0 — Class Appetite Check (reference_data)
Query reference_data for carrier_id match on class_of_business. Appetite = NOT_OFFERED → immediate DECLINE. Gate 1 never runs.
1
Gate 1 — Active Rule Sweep (knowledge_chunks)
Fetch all 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[].
Verdict Aggregation
Severity rank: DECLINE=4 · REFER=3 · REQUIRE_ENDORSEMENT=2 · APPLY_CREDIT=1. Final verdict = highest severity. Response includes firing_rules[] with chunk_id governance citation and verbatim rationale for each rule that fired.
ba_coverage_gate is wired but dormant. The evaluator always returns null because construction_type and wind_exposure are not yet on ga_submissions. Activating this gate requires extending the submission schema and backfilling ga_submissions.

22 routes across two modes — self-contained and proxied

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.

MethodPathModeSource / UpstreamPurpose
GET/categoriesSelfreference_dataClass taxonomy tile grid
GET/appetiteSelfreference_dataClass × BOP/GL/WC appetite dots
GET/submissionsSelfga_submissionsHistorical BA submission list
GET/active-rulesSelfknowledge_chunksActive rules by carrier_id
GET/rule-draftsSelfknowledge_chunksDraft rules by bulletin_id or carrier_id
GET/conflictsSelfknowledge_chunksAll detected rule conflicts
GET/bulletin-pdf/:idSelfba_bulletin_documentsRaw bulletin PDF bytes
POST/checkSelfreference_data + knowledge_chunksGate 0 + Gate 1 eligibility — core BA evaluation
POST/rule-drafts/:id/sanctionSelfknowledge_chunks + curation_auditPromote draft → active; writes audit entry
PATCH/rule-drafts/:id/fieldsSelfknowledge_chunksEdit field_extractions on draft chunk
POST/rule-drafts/:id/detect-conflictsSelfknowledge_chunksConflict detection: draft vs active rules
POST/active-rules/:id/staleSelfknowledge_chunks + curation_auditMark active rule stale
POST/active-rules/:id/suspendSelfknowledge_chunksTemporarily suspend rule (excluded from /check)
POST/active-rules/:id/resumeSelfknowledge_chunksResume suspended rule
POST/active-rules/:id/stage-editsSelfknowledge_chunksQueue field edits on active rule
POST/active-rules/:id/re-sanctionSelfknowledge_chunks + curation_auditApply staged edits → re-activate
POST/active-rules/:id/discard-pending-editsSelfknowledge_chunksRollback staged changes
POST/extractProxied→ /api/gkr/ba/extractACORD 125/126 PDF → structured submission fields (LLM)
POST/chatProxied→ /api/gkr/ba/chatConversational appetite probe (AI)
POST/queryProxied→ /api/gkr/ba/querySemantic portfolio query over ga_submissions
POST/ingest-bulletinProxied→ /api/gkr/ba/ingest-bulletinBulletin OCR + LLM rule extraction + knowledge_chunks write
POST/pdf-to-textProxied→ /api/gkr/ba/pdf-to-textPyMuPDF PDF → plain text extraction

Two databases, seven collections, one shared Atlas client

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.

elevatenow_gkr
CollectionBA Role
knowledge_chunksAll BA rules (ba_* types) partitioned by carrier_id + curation_status. Primary source for Gate 1 evaluation.
reference_dataClass appetite table (Gate 0) + NAICS/SIC crosswalk + vertical index. Seeded separately.
chunk_ontology_edgesSUPERSEDES edges between old and new rule versions after bulletin updates.
curation_auditImmutable append-only log. Every BA lifecycle change (sanction, stale, suspend, re-sanction) writes one document.
ga_bindingauth_gkr
CollectionBA Role
ga_submissionsHistorical BA submissions. Source for: portfolio impact preview (computeImpact) and AI portfolio query.
ga_bulletinsRaw carrier bulletin metadata — source, date, carrier, ingestion status.
ba_bulletin_documentsBinary bulletin PDF payloads + LLM extraction metadata per bulletin_id. Served via GET /bulletin-pdf/:id.

Four conflict types — flagged before sanction, not blocked

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.

geo_overlap

Two ba_geographic_restriction rules share a state. Gate action precedence must be confirmed.

geo_rating_overlap

A ba_geographic_restriction and ba_rating_rule share a concrete (non-ALL) state. Restrictive and pricing rules may conflict.

score_gate_overlap

Two ba_score_gate rules evaluate the same score_field in overlapping states. Thresholds may produce conflicting verdicts.

class_appetite_overlap

Two ba_class_appetite rules share NAICS codes or SIC ranges in the same state. Class eligibility outcome would be ambiguous.

Three end-to-end flows — producer, bulletin ingest, rule edit

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.

Flow 1 — Producer Submission (Tom Reed)

ACORD upload → POST /ba/extract → CurationStudio LLM parses class, state, products, SIC → fields auto-populated → Tom reviews/edits entities → POST /ba/check → backend Gate 0 (reference_data appetite) → Gate 1 (active knowledge_chunks rule sweep) → verdict + firing_rules[] with chunk_id governance citation + verbatim rationale quote

Flow 2 — Bulletin Ingest & Rule Activation (Lisa Grant)

Bulletin PDF upload → POST /ba/ingest-bulletin → CurationStudio: OCR → section detect → LLM rule extraction → draft chunks written to knowledge_chunks (curation_status: draft) → GET /rule-drafts (review queue) → PATCH /fields (edit extracted values) → POST /detect-conflictsPOST /sanction (curation_status: active, curation_audit write) → rule is live in next /check call

Flow 3 — Edit Active Rule Without Draft Cycle (Lisa Grant)

GET /active-rules → select rule in Rulebook → POST /stage-edits (queue field changes; rule stays active as-is) → review staged diff → POST /re-sanction (apply + curation_audit write) OR POST /discard-pending-edits (rollback; rule unchanged)

Every BA file — path, layer, and one-line purpose

Canonical locations for all BA source files across frontend, backend, CurationStudio, and seed scripts.

LayerFile PathPurpose
Frontendsrc/pages/BABindingCheckPage.tsxTom Reed — 4-phase intake, ACORD extract, eligibility check, AI portfolio query (1,754 lines)
Frontendsrc/pages/BABulletinStewardPage.tsxLisa Grant — rulebook, ingest, scenario, audit log. Both carriers via carrier prop (3,759 lines)
Frontendsrc/pages/CenturyBAHubPage.tsxJordan Mills hub — KPI dashboard, pending rules, violation summary, broker watch (445 lines)
Frontendsrc/pages/CenturyBAMonitorPage.tsxJordan Mills portfolio violations monitor (1,237 lines)
Configsrc/config/carrier-config.tsCARRIER_CONFIGS — GREAT_AMERICAN + CENTURY brand, products, themeClass. Add new carrier here only.
Configsrc/config/persona-config.tsPersonaConfig for ba_producer (Tom Reed), ba_steward (Lisa Grant), century_ba (Jordan Mills)
Stylessrc/styles/ba-binding-check.cssTom Reed workspace styles
Stylessrc/styles/ba-steward.cssLisa Grant workspace styles
Stylessrc/styles/century-ba-hub.css · century-ba.cssJordan Mills hub and portfolio styles
Backendsrc/routes/ba.tsAll /api/ba/* route handlers — self-contained + proxied (~1,350 lines)
Backendsrc/services/ba-rule-evaluator.tsPure rule evaluation — evaluateRule() + computeImpact(). Must stay in sync with CurationStudio mirror.
Backendsrc/db/mongo.tsgetGkrDb() → elevatenow_gkr · getBindingAuthDb() → ga_bindingauth_gkr · both reuse claimsClient
Backendsrc/config.ts (line 13)curationStudioUrl (CURATION_STUDIO_URL env) + curationStudioKey (X-Internal-Key header)
Backendsrc/server.ts (line 62)app.use("/api/ba", requireAuth, baRouter) — BA route registration
CurationStudiokcs_api_gkr_routes.py (lines 860–2884)All /api/gkr/ba/* — extract, check, ingest-bulletin, chat, query, pdf-to-text
CurationStudioscripts/seed_ga_ba_appetite.pySeeds GA class appetite into reference_data. Run: python seed_ga_ba_appetite.py --execute
CurationStudioscripts/ba_schema_enricher.pyEnriches BA chunk field_extractions post-ingest
CurationStudioseed_ba_docintel_templates.pyDoc Intel extraction templates for carrier BA bulletins
Scriptssrc/scripts/seed-ba.tsSeeds Great American test submission data into ga_submissions
Scriptssrc/scripts/seed-century-ba.tsSeeds Century Surety test submission data
Scriptssrc/scripts/list-ba-appetite.tsInspect current state of reference_data appetite table
Scriptssrc/scripts/inspect-ba-portfolio.tsDebug ga_submissions data shapes and field coverage
Scriptssrc/scripts/fix-ba-portfolio-data.tsBackfill corrections to ga_submissions

Local environment — three services, one persona flag

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.

Frontend (localhost:5173)

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

Backend (localhost:3001)

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

CurationStudio (localhost:8000)

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

Backend Required Env Vars: 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)
ElevateNow · enCODE™ · Binding Authority Architecture Reference · June 2026 · Internal Technical Use Only