Resources & Tech · HMO Solution

Access computed from contracts, not from a tenant column.

Most healthcare admin systems answer 'can this person see this record?' with a tenant id. This one answers it by walking a graph of the contracts between organizations. That single decision shapes the schema, the auth layer, the query patterns and the audit trail — and it is what lets a health plan, an IPA and a clinic share one system while each sees only its own slice.

Overview

The engineering record behind delegated UM, credentialing, claims and quality on one contract graph.

Technology stack by layer
LayerWhat runs thereWhy
Portal frontendNext.js 14 App Router, TypeScript, Tailwind, shadcn/uiServer rendering was chosen deliberately so page reads are auditable on the server side rather than assembled in the browser.
StateZustand for client state, TanStack Query for the server cacheEntity switching and auth live in Zustand; every read and write goes through one apiFetch() wrapper and a per-domain query hook, so cache invalidation has a single owner.
FormsReact Hook Form with Zod schemasThe same schema validates in the browser and describes the payload, so a write form cannot drift from the endpoint it posts to.
APIPython FastAPI, async end to endOver a hundred domain routers mount from one app factory. Every handler is async def, so a slow external lookup never blocks the worker.
DatabaseMySQL 8.0 on AWS RDS, SQLAlchemy 2.0 async ORM over aiomysqlRelational, because the entity graph and the money are both relational. Identifiers are CHAR(36): MySQL has no native UUID column type and no JSONB, and the schema is written to that constraint rather than around it.
MigrationsAlembic, applied automatically at application startupAlembic runs on the synchronous pymysql driver — the only place in the system that is not async — so migration scripts stay ordinary and debuggable.
AuthRS256 JWT in an httpOnly, SameSite=Strict cookie; bcrypt password hashingAsymmetric signing, explicitly not HS256. The browser never handles a bearer token, so there is nothing for a script to read out of storage.
Session controljti claim plus an access_version stamp on the user rowMakes an otherwise stateless token genuinely revocable — the session list in Settings acts on something real instead of only looking like it does.
CacheRedis 7 via the async client, entity-scoped keys, short fixed TTLsDashboard, KPI, compliance and activity reads only. Reachable from services, never exposed externally, and it fails open: if Redis is down the endpoint computes the answer instead of erroring.
Background jobsAPScheduler with a dedicated synchronous engineJobs run on a thread pool, not the event loop, so the SLA sweep and scheduled report dispatch cannot starve request handling. The engine is disposed after each run to keep the connection pool clean.
DocumentsAWS S3 with presigned URLs and entity-prefixed keysCredentialing files, generated PDFs and EDI archives. Isolation is in the key prefix, expiry is on the URL, and with no AWS keys configured the service logs and no-ops rather than crashing.
CI/CDHarness pipeline — lint, unit tests, image build, registry push, approval gate, deployThe approval gate is deliberate: nothing reaches an environment because a test went green.
Architecture

How the engine actually works

Each section describes a mechanism that exists in the codebase today, not a pattern we admire.

The core decision

Access as a graph traversal, not a column check

Organizations are rows in one entities table, typed by a MySQL enum with eleven values — regulatory bodies, health plans, MCOs, ACOs, IPAs, PHOs, MSOs, TPAs, FQHCs, individual providers and PACE organizations. They are linked by a closure table, entity_relationships, keyed on ancestor, descendant and relationship type, with a depth column where zero means self and one means direct parent.

Request path

What the token carries, and what it cannot be talked into

Every JWT embeds the subject, issue and expiry times, and a jti naming the session. On each request the token is decoded from the cookie, the session is checked against the revocation list, and the token's access_version claim is compared against the live value on the user row — so revoking or editing a grant invalidates outstanding tokens immediately instead of waiting for them to expire.

Delegation

The contract is the record

A delegation row is an agreement between an owning IPA and a health plan: a scope array naming the delegated functions, effective and end dates, a configurable SLA threshold in days that drives the expiring-soon warnings, and a status of active, pending, inactive or expired.

Utilization management

A decision you can reconstruct months later

Prior-authorization reviews carry an append-only status history: every status change is written in the same database transaction as the update to the review itself. That dual write is what makes the audit trail trustworthy — there is no window in which the review has moved and the history has not.

Claims

An adjacency map, and 409 for everything else

Claim status is an eight-value enum, and the legal moves between those values live in one explicit adjacency map in the service layer. Submitted can become in-review, paid, denied or voided. Denied can only become resubmitted. Paid, adjusted and voided are terminal — their successor sets are empty. Any transition not in the map raises a 409 rather than being applied.

Credentialing

Two paths, one namespace, and an honest gap

IPA-initiated credentialing tracks a delegation-driven review through pending, in-review and then approved, denied or returned — where returned is deliberately non-terminal, so a provider can correct and resubmit without the case being recreated. A JSON checklist travels with the application, and primary source verification queries are logged individually against their source.

Risk adjustment

One RAF calculation, after three was one too many

Risk adjustment factor scoring runs through a single canonical implementation of the CMS-HCC V28 methodology: a demographic factor plus the sum of HCC coefficients plus interaction factors, divided by the published normalization factor.

Logging and audit

Routes that carry PHI are named, not guessed

The request logging middleware holds an explicit allow-list of route prefixes that carry protected health information — patients, UM, claims, care, population health, analytics, admin, billing, enrollments, eligibility, network and more — and never logs request or response bodies for them verbatim. A redaction helper walks nested structures stripping named PHI fields.

Data model

The records underneath, and the rules that hold them true

Core entities and their invariants
EntityWhat it holdsRule that always holds
entitiesOne row per organization in the graph, typed by an eleven-value MySQL enum, plus its credentialing lifecycle state and next recredentialing due date.The enum is the single source of truth for entity_type; a test fails the suite if the Pydantic literal, the frontend list or the docs drift from it.
entity_relationshipsClosure table for hierarchy, delegation and contract traversal, with a depth column.Composite key on ancestor, descendant and relationship type — one pair may hold several types. Inserts are all-or-nothing per transaction.
entity_data_accessPer-user access grant: role, permissions, delegated scopes and the entity ids that grant reaches.Unique per user, entity and role.
delegationsThe agreement between an owning IPA and a health plan — scope array, effective dates, SLA threshold, status.Display id is unique per entity, not globally.
delegation_auditAppend-only change log for delegations, carrying a JSON diff per action.No update or delete ever touches this table.
um_status_historyEvery prior-authorization status transition, with from and to status.Written in the same transaction as the parent review update — the review and its history can never disagree.
um_appealsMulti-level appeal workflow attached to a review, up to external review.An overturned appeal does not auto-flip the parent review; an explicit re-determination is required.
claimsThe claim itself — eight-value status, CMS-1500 and UB-04 fields, and the full financial breakdown.Claim number and display id are unique per entity; transitions are gated by an explicit adjacency map and rejected with 409 otherwise.
claim_lines · claim_denials · claim_remittances · claim_paymentsLine items, denial categorisation, remittance detail and payment allocation.Every row carries its own entity id — scoping is never inherited implicitly from the parent claim.
credentialing_applicationsAn IPA-initiated credentialing case with a JSON checklist and a status that includes the non-terminal returned state.Turnaround time is computed at the API layer, never stored, so it cannot go stale.
psv_verificationsOne row per primary source verification query, against a named source.Status is resolved by a human reviewer — there is no automated registry integration behind it.
edi_filesTracking for each received EDI batch: type, record counts, and processing status.The file_type column is shaped to carry claim and remittance transaction sets, but only enrollment is parsed today.
hedis_measures · cms_stars_measures · ncqa_measures · state_doi_reportsQuality and regulatory measure snapshots per entity and reporting period.Rates are computed at ingestion, not live, so a reported period does not change after the fact.
hcc_categories · icd10_to_hcc_mapRisk-adjustment category catalog and the diagnosis crosswalk that feeds RAF scoring.One canonical scoring function reads them — there is no second implementation.
audit_eventsMutation audit log: actor, action, resource, IP address, user agent and request id.Append-only at the application layer. Database-level immutability is a documented future goal, not a current guarantee.
Interfaces

What it exchanges, and in which direction

Optional integrations degrade gracefully: with no key configured the product still runs, it just does less.

EDI 834 enrollment

Inbound

A hand-written X12 parser auto-detects segment and element separators from the ISA header and walks enrollment segments into member records with per-row error reporting. The module's own docstring is explicit that it is not a clearinghouse-grade parser built to the full HIPAA transaction standard.

NPI Registry (NPPES)

Inbound

Public federal registry, no key required. Deliberately not cached and not entity-scoped, because it is authoritative public data and staleness would be the bigger risk.

RxNorm (NLM RxNav)

Inbound

Free, no-auth drug lookup proxied at request time rather than embedding a catalog that is hundreds of megabytes and updates monthly.

SNOMED CT (UMLS)

Inbound

Cache-first against a local catalog table, external call only on a miss, results written back. With no key configured it serves from cache rather than failing.

ICD-11 (WHO)

Inbound

OAuth2 client-credentials flow, cache-first against a local catalog table on the same pattern.

Procedure and supply code catalogs

Inbound

Served from an internal catalog table. Note that the CPT set is licensed by the AMA — the platform provides the lookup mechanism; the licensed content is the customer's to hold.

AWS S3 documents

Bidirectional

Credentialing files, generated PDFs and EDI archives behind presigned URLs with entity-prefixed keys. Absent credentials, the service logs and no-ops.

Email, SMS and AI services

Outbound

SendGrid, Twilio and Anthropic are optional by design. Each returns a safe fallback when its key is absent, so a missing integration degrades a feature instead of taking down a deployment.

Security

How access is decided and recorded

Token signing
RS256 with a key pair, explicitly not a shared secret. Keys resolve from base64 environment variables in containers or PEM file paths locally, and are never committed.
Cookie posture
httpOnly and SameSite=Strict. No bearer token is ever handled in browser JavaScript.
Revocation
A jti per session plus an access_version stamp on the user row. Changing a grant invalidates outstanding tokens on the next request rather than at expiry.
Account enumeration
A failed login runs a real bcrypt comparison against a decoy hash so response timing does not distinguish a real account from a miss.
Scope enforcement
Entity id comes from the decoded token on every route. Cross-entity access returns 404 rather than 403, so error codes leak nothing about what exists.
PHI in logs
Route prefixes carrying PHI are named on an allow-list and their bodies are never logged verbatim; a redaction helper strips named fields recursively.
Audit trail
A general mutation log plus domain-specific append-only tables for delegations and UM transitions, with actor, IP, user agent and request id captured from request context.
Compliance posture
Designed for HIPAA obligations under a BAA. Controls are documented and runbooks are handed over; no certification is claimed, because none exists for software of this kind.

Infrastructure is designed for HIPAA obligations under a BAA. We document the controls and hand over the runbooks; we do not claim a certification that does not exist for software.

Reliability

What keeps it correct under load

State machines with server-side guards
Claims, UM, credentialing, grievances and risk-pool settlements each hold an explicit map of legal transitions. An illegal move is a 409, not a silently applied update.
Atomic graph writes
Relationship creation runs inside a transaction or nested savepoint with idempotent inserts, so a partial closure-table state can never be read and a re-run is safe.
Dual-write audit
Status history rows are written in the same transaction as the parent update, which removes the window where the two could disagree.
Cache that fails open
Entity-scoped Redis keys with short fixed TTLs per endpoint class and no active invalidation — a deliberate, documented limitation. A cache miss or an unreachable Redis costs latency, never correctness.
Jobs that report their own death
Scheduled work runs single-instance with coalescing and a misfire grace window, on a separate synchronous engine disposed after each run. Each run writes a heartbeat, and the health endpoint reports the job as stale if the heartbeat ages out.
Eager loading by default
The architecture decision log records eager loading as the standing default across the portal's list views, so a page that renders a hundred rows does not issue a hundred follow-up queries.
Per-entity display identifiers
Human-readable ids are unique per entity rather than globally, avoiding a single global counter as a contention point.
Development record

The documents this was built from

Analysis, design discussion, implementation notes and QA written while the work happened. These are engineering artifacts in the product repository, not published pages — listed here so you can see what exists and ask for any of it.

Development-time documentation for HMO Solution
DocumentKindDateWhat it covers
Entity-graph architecturedevelopment/docs/ARCHITECTURE.mdDesign2026-04-05The founding document for the entity graph: hierarchy diagram, the entity types, the relationship type registry and the delegation scope model. Source of the 'graph, not multi-tenancy' framing that shapes the whole platform.
Architecture decision logdevelopment/docs/DECISIONS.mdReference2026-04-05 onwardThirty-one locked decisions with rationale — stack choices, entity id on every table, token staleness handling, session timeout behaviour, eager loading as default — plus the decisions still open.
Data model designdevelopment/docs/DATA_MODEL.mdDesign2026-04-05The approved table design behind the core schema — organizations, relationships, per-user access grants and the audit trail, with the reasoning for each.
IPA management implementation recorddevelopment/docs/ipas.mdImplementation2026-04-22The IPA page as built: the access model, provider composition rules, the network adequacy source, the delegation source, and the reasoning behind each decision taken along the way.
Organization view records — ACO, MCO, PHO, health plandevelopment/docs/{acos,mcos,phos,health-plans-org-view}.mdImplementationThe same implementation-record pattern applied to each of the other organization types.
v2.4 gap analysis — IPA core cluster.planning/milestones/v2.4-gap-analysis/CLUSTER-1-IPA-CORE.mdAnalysisGap analysis across delegation, credentialing, UM and claims — what existed, what was missing, and what was scheduled to close.
v2.4 gap analysis — financial, analytics and admin clusters.planning/milestones/v2.4-gap-analysis/CLUSTER-{2,3,4}-*.mdAnalysisThe parallel gap analyses for the financial, analytics and admin-tenant module clusters.
Authorizations — full workflow phase.planning/phases/12-authorizations-full-workflow/Implementation2026-04-08The build that produced the status-history dual write, the appeal levels and the SLA sweep job, with its plan, discussion log, validation and verification artifacts.
Claims processing — full workflow phase.planning/phases/13-claims-processing-full-workflow/ImplementationThe build that produced the transition adjacency map and the line, denial, remittance and payment tables.
Delegation management phase.planning/phases/04-delegation-management/Implementation2026-04-07Delegation CRUD and the append-only audit log, including the decision to diff changes as JSON.
Employer groups, risk pools and grievances phase.planning/phases/23-employer-groups-risk-pools-grievances/DesignThree domains built in one phase, with a dedicated security artifact covering the scoping rules for each.
Claims form field mapping phase.planning/phases/30-claims-forms/ImplementationThe pass that mapped CMS-1500 and UB-04 form boxes onto named claim and claim-line columns.
IPA core completion pass.planning/phases/75-ipa-core-completion/Implementation2026-04-24A completeness sweep across delegation, credentialing, UM and claims after the initial module builds.
RAF intelligence documentationdocs/docs-raf-full.htmlReferenceLong-form documentation of the risk-adjustment engine — methodology, category mapping and how scores surface.
Per-module documentation setdocs/docs-module-*.html · docs/docs-org-*.htmlReferenceWritten module and organization-type guides covering claims, providers, billing, enrollment, population health, regulatory, risk pools, grievances, employer groups, analytics, admin and auth.
QA runs and per-organization verification reports.planning/qa/run-*/FINDINGS*.md · .planning/qa-reports/QA2026-05-12 to 2026-08-26Multi-pass QA findings including post-deploy passes, plus per-seeded-organization verification reports across IPA, ACO, PHO, MCO, TPA and provider roles.
Seed data reports.planning/seed-reports/RunbookGeneration records for the demo data every page is validated against — the project's standing rule is that no screen is built on hardcoded arrays.
Glossary

Terms used on this page

Entity graph
Organizations as nodes, typed contracts as edges — this system's replacement for a flat tenant identifier.
Closure table
A table holding every ancestor–descendant pair in a hierarchy, so reachability is an indexed lookup rather than a recursive query.
Delegation
A formal grant of administrative authority — utilization management, credentialing and so on — from a health plan to an IPA, with a scope and dates.
Utilization management
The review that decides whether a requested service is approved, denied or needs more information.
Prior authorization
A utilization management decision made before the service is delivered.
Credentialing
Verifying a provider's licenses, training and history before they can practise or bill under a network.
Primary source verification
Confirming a credential directly with the body that issued it, rather than accepting a copy.
NCQA
The accrediting body whose credentialing standards shape the lifecycle states modeled here, including the 36-month recredentialing cycle.
HEDIS
A standardized set of quality-of-care performance measures used across health plans.
RAF
Risk adjustment factor — a per-member score summarizing expected cost and risk under the CMS-HCC methodology.
HCC
Hierarchical condition category — the diagnosis-driven grouping that feeds a risk score.
EDI 834
The X12 electronic transaction set carrying health-plan enrollment and eligibility changes.
CMS-1500 / UB-04
The standard professional and institutional claim forms, whose fields are mapped to named columns here.
Risk pool
A value-based arrangement where providers share savings against a budget target, or bear part of the risk.
Withhold
A portion of payment held back and released against performance or settlement.
Grievance
A formal member or provider complaint, tracked through a defined resolution workflow.
Dual write
Writing a record and its audit entry in one transaction, so the two cannot disagree.
Dead man's switch
A health check that reports failure when an expected heartbeat stops arriving, rather than only when something errors.
RS256
Asymmetric token signing using a key pair, as opposed to a shared secret both sides hold.
PHI
Protected health information — data subject to special handling, which here means named routes and fields excluded from logs.
Questions

Asked by the people who evaluate this

Why not just use a tenant id like everyone else?

Because the relationships are the product. A health plan delegates to an IPA, which contracts with practices, which employ providers — and each of those edges has a scope and an expiry date. A tenant id can express 'belongs to', but not 'may perform utilization management on behalf of, until March'. Once you need the second sentence, you need a graph, and bolting one onto a tenant column later is far more painful than starting with it.

How do I know an audit trail is real and not decorative?

Look at where the write happens. Here the status-history row is written in the same transaction as the record it describes, and the delegation log is never updated or deleted. An audit table that is written after the fact, in a separate call, from application code that can fail independently, is decorative. The test is whether a partial failure can leave the two out of step.

What happens when Redis or an external API is down?

The cache fails open — an unreachable Redis costs latency, not correctness, because the endpoint recomputes. Optional integrations return safe fallbacks when their keys are absent, so a deployment without an email provider still runs, it just does not send email. The things that fail loudly are the ones that should: database and signing keys.

Is this HIPAA compliant?

Software is not certified for HIPAA; organizations are. What we can say accurately is that the infrastructure is designed for HIPAA obligations under a BAA — protected-health routes are excluded from body logging, documents sit behind expiring signed URLs with per-entity key prefixes, mutations are audited with actor and origin, and the runbooks come with the system. Anyone who tells you their software carries a HIPAA certification is describing something that does not exist.

Can we get the underlying engineering documents?

Yes. The development record on this page lists what exists — architecture and decision logs, per-phase plans and verification artifacts, gap analyses, QA passes and seed reports. They are repository artifacts rather than published pages, so ask and we will share the relevant set under NDA.