Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Version: 2.0.0
Status: ✅ Implemented
Last Updated: 2026-02-22
Last Verified: 2026-02-22
Spec: PM-08 Claims Management & Submission
Constitution Reference: Section 1.2 (Core Independence), Section 1.3 (Integration Patterns)

Overview

PM-08 owns claim generation from charges (837P/837I), pre-submission scrubbing, submission via clearinghouse or direct payer, status tracking, denial management (CARC/RARC), and secondary/tertiary and void/replacement claims. Key tables: pm_claims, pm_claim_lines
RLS: Full CRUD policies on both tables (tenant-isolated via organization_id). DELETE restricted to org_admin.
Scrubbing engine: src/cores/pm/utils/claim-scrubbing.ts — validates NPI, diagnosis codes, service dates, filing deadline, line-level CPT/units/POS.
Event publisher: src/cores/pm/hooks/useClaimMutation.ts

Integration Points

DependencyPatternStatusPurpose
PM-07Data (FK)✅ ImplementedApproved charges → claim lines; pm_claim_lines.charge_idpm_charges.id
PM-09Data (FK, mutation)✅ ImplementedERA payments posted against claims; status updated to paid/denied
PM-15Data / API📋 PlannedClearinghouse transmission; clearinghouse_trace_id round-trip
PM-02Data (query)✅ ImplementedEligibility check before submission; latest pm_eligibility_checks for patient+payer
PM-10Data (query)✅ ImplementedAuthorization verification in scrubbing; active auth for service type
PF-70Platform✅ ImplementedCode library (CPT/ICD-10/HCPCS) for validation via @/platform/codes

Event Contracts

claim_submitted (PM-08 → PM-15, PF-10, PF-04)

Status: ✅ Implemented
Last Verified: 2026-02-22
Channel: cl_pm_events
Publisher: src/cores/pm/hooks/useClaimMutation.ts (via publishEvent)
DB registration: fw_workflow_events row exists (owning_core: pm, category: operational)
Published when a claim transitions to submitted status.
interface ClaimSubmittedPayload {
  event_name: 'claim_submitted';
  organization_id: string;           // UUID — tenant
  payload: {
    claim_id: string;                 // UUID — pm_claims.id
    claim_number: string;             // Generated claim number (e.g., "CLM-20260222-001")
    patient_id: string;               // UUID — pm_patients.id
    payer_id: string;                 // UUID — pm_payers.id
    claim_type: 'professional_837p' | 'institutional_837i';
    total_charge: number;             // Sum of line charges (USD cents)
    line_count: number;               // Count of pm_claim_lines for this claim
    submitted_by: string;             // UUID — auth.uid() of submitting user
  };
}
Consumers:
ConsumerPatternStatusBehavior
PM-15Event subscription📋 PlannedInitiates clearinghouse 837P/I transmission
PF-10Notification✅ ImplementedNotifies billing manager of submission
PF-04Audit✅ ImplementedAudit log entry with claim_id and user

claim_status_changed (PM-08 → PM-11, PF-10, FA)

Status: ✅ Implemented
Last Verified: 2026-02-22
Channel: cl_pm_events
Publisher: src/cores/pm/hooks/useClaimMutation.ts (via publishEvent)
DB registration: fw_workflow_events row exists (owning_core: pm, category: operational)
Published on any claim status transition.
interface ClaimStatusChangedPayload {
  event_name: 'claim_status_changed';
  organization_id: string;           // UUID — tenant
  payload: {
    claim_id: string;                 // UUID — pm_claims.id
    claim_number: string;             // Claim number
    patient_id: string;               // UUID — pm_patients.id
    payer_id: string;                 // UUID — pm_payers.id
    previous_status: ClaimStatus;
    new_status: ClaimStatus;
    denial_codes?: DenialCode[];      // Present when new_status is 'denied'
    paid_amount?: number;             // Present when new_status is 'paid' (USD cents)
    changed_by: string;               // UUID — auth.uid()
  };
}

type ClaimStatus =
  | 'draft'
  | 'scrubbed'
  | 'submitted'
  | 'accepted'
  | 'rejected'
  | 'paid'
  | 'denied'
  | 'appealed'
  | 'adjusted';

interface DenialCode {
  carc: string;                       // Claim Adjustment Reason Code (e.g., "CO-45")
  rarc?: string;                      // Remittance Advice Remark Code
  group_code: 'CO' | 'PR' | 'OA' | 'PI'; // CARC group
  amount?: number;                    // Adjustment amount (USD cents)
}
Consumers:
ConsumerPatternStatusBehavior
PM-11Dashboard query✅ ImplementedRevenue cycle metrics (denial rate, clean claim %)
PF-10Notification✅ ImplementedDenial notifications to assigned biller
FAGL posting📋 PlannedJournal entries on paid status (future integration)
Valid State Transitions:
draft → scrubbed
scrubbed → submitted | draft
submitted → accepted | rejected
accepted → paid | denied
rejected → draft
paid → adjusted
denied → appealed | draft
appealed → paid | denied
adjusted → (terminal)

Data Contracts

PM-07 → PM-08: Approved Charges Query

Status: ✅ Implemented
Last Verified: 2026-02-22
PM-08 generates claims from approved, unlinked charges:
SELECT id, organization_id, patient_id, provider_id, service_date,
       cpt_code, units, modifiers, place_of_service,
       diagnosis_codes, fee_schedule_id, amount
FROM pm_charges
WHERE organization_id = :org_id
  AND status = 'approved'
  AND claim_id IS NULL           -- not yet linked to a claim
  AND deleted_at IS NULL
ORDER BY service_date, patient_id;
Mapping: Each charge maps to one pm_claim_lines row:
pm_charges columnpm_claim_lines column
idcharge_id (FK)
cpt_codecpt_code
unitsunits
modifiersmodifiers
place_of_serviceplace_of_service
amountcharge_amount
service_dateservice_date
diagnosis_codes[0..3]diagnosis_pointers (1-indexed array)
After claim creation, the source charge’s claim_id is back-populated.

PM-08 → PM-09: Claims for Payment Posting

Status: ✅ Implemented
Last Verified: 2026-02-22
PM-09 reads claims and lines to post ERA payments:
SELECT c.id, c.claim_number, c.patient_id, c.payer_id, c.total_charge,
       c.status, c.paid_amount, c.adjustment_amount, c.patient_responsibility,
       cl.id AS line_id, cl.line_number, cl.cpt_code, cl.charge_amount,
       cl.paid_amount AS line_paid, cl.adjustment_amount AS line_adjustment
FROM pm_claims c
JOIN pm_claim_lines cl ON cl.claim_id = c.id AND cl.organization_id = c.organization_id
WHERE c.organization_id = :org_id
  AND c.status IN ('submitted', 'accepted')
  AND c.claim_number = :claim_number   -- matched from ERA/835
  AND c.deleted_at IS NULL;
Mutation contract: PM-09 updates these pm_claims columns via .update():
ColumnTypeDescription
statustextpaid, denied, or stays accepted for partial
paid_amountnumericTotal paid by payer
adjustment_amountnumericContractual adjustments (CO group)
patient_responsibilitynumericPatient balance (PR group)
denial_codesjsonbArray of DenialCode objects
adjudicated_attimestamptzDate of adjudication

PM-08 Scrubbing: Pre-Submission Validation

Status: ✅ Implemented
Last Verified: 2026-02-22
Location: src/cores/pm/utils/claim-scrubbing.ts
interface ScrubResult {
  passed: boolean;                    // true if zero errors
  errors: ScrubError[];               // blocking — must fix before submission
  warnings: ScrubError[];             // advisory — can submit with warnings
}

interface ScrubError {
  code: string;                       // e.g., "MISSING_NPI", "EXPIRED_AUTH"
  field: string;                      // e.g., "billing_provider_npi"
  message: string;                    // Human-readable description
  line_number?: number;               // Specific claim line, if applicable
}
Validations performed:
CodeFieldRule
MISSING_NPIbilling_provider_npiNPI must be present (sourced from pm_module_settings)
MISSING_DIAGNOSISprimary_diagnosis_codeAt least one ICD-10-CM required
MISSING_SERVICE_DATEservice_date_fromService date range required
PAST_FILING_DEADLINEfiling_deadlineMust be within 365-day AHCCCS deadline
MISSING_CPTcpt_code (line)Each line must have a valid CPT/HCPCS
MISSING_UNITSunits (line)Units must be > 0
MISSING_POSplace_of_service (line)Place of service required per line
MISSING_DIAG_POINTERdiagnosis_pointers (line)At least one diagnosis pointer required

Database Schema (pm_claims)

Last Verified: 2026-02-22
ColumnTypeNullableDescription
iduuidNOPK
organization_iduuidNOTenant FK → pf_organizations
patient_iduuidNOFK → pm_patients
claim_numbertextNOGenerated claim number
claim_typetextNOprofessional_837p or institutional_837i
payer_iduuidNOFK → pm_payers
policy_iduuidYESFK → pm_insurance_policies
billing_provider_npitextYESFrom pm_module_settings
rendering_provider_npitextYESProvider NPI
facility_iduuidYESFK → pf_sites
service_date_fromdateYESDOS range start
service_date_todateYESDOS range end
primary_diagnosis_codetextYESICD-10-CM
total_chargenumericYESSum of line charges
statustextYESClaim lifecycle status
submitted_attimestamptzYESSubmission timestamp
adjudicated_attimestamptzYESAdjudication timestamp
paid_amountnumericYESPayer paid amount
adjustment_amountnumericYESContractual adjustments
patient_responsibilitynumericYESPatient balance
denial_codesjsonbYESArray of DenialCode objects
frequency_codetextYES1 (original), 7 (replacement), 8 (void)
original_claim_iduuidYESSelf-FK for replacement/void claims
filing_deadlinedateYES365-day AHCCCS deadline
clearinghouse_trace_idtextYESReturned by PM-15
custom_fieldsjsonbNODefault {}
deleted_attimestamptzYESSoft delete
created_attimestamptzNOAuto
updated_attimestamptzNOAuto
created_byuuidYESFK → pf_profiles
updated_byuuidYESFK → pf_profiles

Database Schema (pm_claim_lines)

Last Verified: 2026-02-22
ColumnTypeNullableDescription
iduuidNOPK
organization_iduuidNOTenant FK
claim_iduuidNOFK → pm_claims
charge_iduuidYESFK → pm_charges (source charge)
line_numberintNOSequence within claim
service_datedateYESLine-level DOS
cpt_codetextYESCPT/HCPCS code
modifierstext[]YESUp to 4 modifiers
unitsnumericYESService units
diagnosis_pointersint[]YES1-indexed references to claim diagnoses
charge_amountnumericYESBilled amount
paid_amountnumericYESPaid by payer
adjustment_amountnumericYESAdjustments
adjustment_reasontextYESCARC code
denial_reasontextYESDenial reason
rendering_provider_npitextYESLine-level provider
place_of_servicetextYESPOS code
revenue_codetextYESFor institutional claims
custom_fieldsjsonbYESDefault {}
deleted_attimestamptzYESSoft delete
created_attimestamptzNOAuto
updated_attimestamptzNOAuto
created_byuuidYESFK → pf_profiles
updated_byuuidYESFK → pf_profiles

RLS Policies

Last Verified: 2026-02-22
TablePolicyCommandRule
pm_claimspm_claims_selectSELECTorganization_id tenant match
pm_claimspm_claims_insertINSERTorganization_id tenant match
pm_claimspm_claims_updateUPDATEorganization_id tenant match (with WITH CHECK)
pm_claimspm_claims_deleteDELETEorg_admin role only
pm_claim_linespm_claim_lines_selectSELECTorganization_id tenant match
pm_claim_linespm_claim_lines_insertINSERTorganization_id tenant match
pm_claim_linespm_claim_lines_updateUPDATEorganization_id tenant match (with WITH CHECK)
pm_claim_linespm_claim_lines_deleteDELETEorg_admin role only

Integration Matrix

FromToPatternStatusLast VerifiedDoc
PM (PM-08)PM-07Data (charges → claims)✅ Implemented2026-02-22This doc
PM (PM-08)PM-09Data (claims for payment posting)✅ Implemented2026-02-22PM-09 Integration
PM (PM-08)PM-15Data / API (clearinghouse)📋 PlannedTBD in PM-15 integration
PM (PM-08)PM-02Data (eligibility query)✅ Implemented2026-02-22This doc
PM (PM-08)PM-10Data (auth verification)✅ Implemented2026-02-22PM-10 Integration
PM (PM-08)PF-70Platform (code library)✅ Implemented2026-02-22PF-70 Integration
PM (PM-08)PF-10Platform (notifications)✅ Implemented2026-02-22Event consumers above
PM (PM-08)PF-04Platform (audit)✅ Implemented2026-02-22Event consumers above

References