Apache-2.0-licensed, self-hosted first vertical slice for a single ACO. It proves a synthetic BCDA v3 NDJSON → immutable manifest → canonical claim lineage → paid-claims metrics → FastAPI → Next.js dashboard flow.
Not a production clinical or payment system. All repository fixtures are deterministic, synthetic, and non-PHI. Parts A/B paid TCOC and Part D paid spend are separate
operational_estimatevalues—not official CMS reconciliation. The BCDA v3 synchronization adapter is contract-tested with mocked HTTP; this repository has not validated CMS sandbox or production access. No HCC score, attribution logic, or production identity provider is included.
- FastAPI
/health, database-backed/ready, and versioned/api/v1routes. - SQLAlchemy 2 models tested on SQLite and configured for PostgreSQL via
DATABASE_URL. - Immutable, SHA-256-addressed source manifests and ingestion jobs.
- Minimal BCDA v3 NDJSON parsing for
Patient,Coverage, andExplanationOfBenefit. - A typed
httpxBCDA v3 client for in-memory bearer caching,all/explicitrunoutexports, bounded polling/retries, recoverable job history, strict manifests, confined URLs, and streamed downloads that refresh authorization after a 401. - Durable export-run and downloaded-file lineage plus an atomic, SHA-256-addressed filesystem artifact store. The narrow store protocol is the future MinIO/S3 adapter boundary; no object-store implementation is claimed here.
- Canonical beneficiaries, claims, and current/historical claim versions with source lineage.
Decimal/NUMERIC(18,2)paid amounts; UTC source/data-through timestamps.- Separate Parts A/B paid TCOC and Part D paid spend.
- Permission-gated and audited beneficiary CSV; an
XLSXExportAdapterprotocol boundary only. - Minimal responsive Next.js executive dashboard.
- Compose stack: API, web, PostgreSQL, and MinIO (raw-object-store boundary).
The first synthetic raw-to-dashboard slice and mocked BCDA v3 synchronization slice are complete.
The next milestone is credential-safe live CMS sandbox validation. A new developer or agent should
start with docs/HANDOFF.md, then follow the reviewed implementation plan in
docs/LIVE_BCDA_SANDBOX_VALIDATION_PLAN.md. The
repository must continue to state that sandbox access is unvalidated until a real run produces
sanitized, dated evidence.
Prerequisites: Python 3.12+, Node 22+, npm, and Docker for the container path.
python -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/pytest
.venv/bin/ruff check .
.venv/bin/mypy
cd apps/web
npm ci
npm test
npm run lint
npm run typecheck
npm run buildRun against SQLite and load the synthetic sample:
# repository root
.venv/bin/python -m aco_health.cli fixtures/synthetic/bcda_v3.ndjson \
--source-uri file://synthetic/bcda_v3.ndjson
.venv/bin/uvicorn aco_health.main:app --reload
# separate terminal
cd apps/web
API_INTERNAL_URL=http://localhost:8000 npm run devOpen http://localhost:3000; API docs are at http://localhost:8000/docs.
BCDA credentials are read only from BCDA_CLIENT_ID and BCDA_CLIENT_SECRET. Keep them in an
untracked local environment or secret manager. The CLI exits clearly before making a request when
either is absent. It requests only Patient,Coverage,ExplanationOfBenefit, downloads and ingests
them in that dependency order, and records only non-secret failure summaries—never bearer tokens
or raw response bodies.
After installing the project and loading an untracked environment, start a Group all export:
aco-health-bcda-sync --scope all --since 2026-07-01T00:00:00Zrunout is never implicit:
aco-health-bcda-sync --scope runoutRecover a known job without starting another remote export:
aco-health-bcda-sync --recover-job YOUR_EXISTING_JOB_IDThe configured origin must be HTTPS (official defaults: sandbox
https://sandbox.bcda.cms.gov, production https://api.bcda.cms.gov). Job and data URLs are
restricted to that exact origin and the v3 /api/v3/jobs/… or /data/… paths before authorization
is forwarded. Redirects are rejected. Recovered scope and _since values come only from the
completed manifest's authoritative request URL; recovery rejects caller-supplied values. Files
default to ./bcda-artifacts; downloads have a configurable byte limit and partial temporary files
are removed on failure.
Copy the non-secret template and replace every replace-* value with locally generated
credentials. Compose deliberately has no credential defaults and fails configuration when a
required variable is absent. Every published first-slice port binds to 127.0.0.1, including the
API, dashboard, PostgreSQL, and MinIO console, while the API uses the temporary trusted-upstream
header contract described below.
cp .env.example .env
# edit .env before continuing
docker compose config --quiet
docker compose up --build -d
docker compose exec api python -m aco_health.cli fixtures/synthetic/bcda_v3.ndjson \
--source-uri s3://synthetic/bcda_v3.ndjson
# restart the server-rendered dashboard only if a browser had cached an earlier error
curl http://localhost:8000/api/v1/executive-summaryDashboard: http://localhost:3000. MinIO console: http://localhost:9001. MinIO is provisioned as the object-store boundary but the first ingest command intentionally reads a local synthetic file—there is no fake BCDA download/OAuth implementation.
The PostgreSQL-specific raw-to-metrics integration test is guarded against non-test databases. With the Compose database running, create a disposable test database and execute it explicitly:
docker compose exec postgres sh -c 'createdb -U "$POSTGRES_USER" aco_health_test'
set -a
. ./.env
set +a
.venv/bin/pytest -m postgres apps/api/tests/test_postgres_integration.pyStop and remove local state with docker compose down -v.
curl http://localhost:8000/api/v1/executive-summary
curl -OJ http://localhost:8000/api/v1/exports/beneficiaries.csv \
-H 'X-Permissions: beneficiary:export' \
-H 'X-Actor-Id: local-synthetic-reviewer'X-Permissions/X-Actor-Id are a trusted-upstream authorization contract, not authentication. They make the permission and audit boundary executable for this slice. Do not expose the API directly in production; replace the dependency with validated identity-provider/gateway claims. Denied exports are HTTP 403; allowed exports write an audit row.
The local Compose loopback binding is a security boundary for this temporary contract. Publishing the API on a non-loopback address would expose caller-supplied authorization headers to that network and is unsupported until a validating gateway or identity provider is in front of the API.
The export contains canonical beneficiary IDs only, paid estimates, and UTC data-through time.
The generic EOB provider reference is stored with role unknown; it is never inferred to be a
billing or attributed provider. Geography is not derived and should be presented as Unknown until
a supplied provider-location source is implemented.
apps/api/src/aco_health/bcda.py— source parserapps/api/src/aco_health/bcda_client.py— BCDA v3 authentication and HTTP contractsapps/api/src/aco_health/bcda_sync.py— durable polling, download, and ordered ingestionapps/api/src/aco_health/artifacts.py— atomic filesystem storage and future-store protocolapps/api/src/aco_health/cli_bcda.py— start/recovery commandapps/api/src/aco_health/ingestion.py— raw-to-canonical ingestionapps/api/src/aco_health/models.py— manifests, jobs, canonical lineage, auditapps/api/src/aco_health/metrics.py— paid metric serviceapps/api/src/aco_health/exports.py— CSV and XLSX adapter boundaryapps/api/src/aco_health/main.py— presentation/APIapps/web/app/— dashboardfixtures/synthetic/— non-PHI sample
Real user authentication/authorization, official beneficiary attribution, CMS MSSP HCC modeling, XLSX rendering, scheduling/distributed queues, MinIO/S3 artifact storage, and scale/load validation are deliberately unsupported. BCDA OAuth and Bulk FHIR orchestration are implemented against the documented v3 contract and tested only with synthetic mocked HTTP. No claim of actual CMS sandbox, production, or large-ACO validation is made.
Apache License 2.0; see LICENSE.