Deep dive2026
RayHealth EVV logo

RayHealth EVV

A full-stack Electronic Visit Verification platform for home-care agencies.

Role
Solo: full-stack, mobile and infrastructure
RayHealth EVV landing page: care, finally on the same page
One calm workspace for scheduling, EVV, authorizations, credentialing, and audit.

RayHealth EVV is a production Electronic Visit Verification platform for home-care agencies. Caregivers clock in and out from a mobile app with GPS verification, coordinators run scheduling and compliance from a web console, and verified visits flow out to state Medicaid aggregators and billing. It is live at rayhealthevv.com, built for the 21st Century Cures Act rules that govern every Medicaid-funded home-care visit.

Overview

The platform is a Turborepo monorepo with four workspaces: a core package that owns the domain models and the database, an Express 5 API, a React web console, and an Expo caregiver app. Around 40 PostgreSQL tables, roughly 190 API route handlers, and about 668 tests hold it together.

The design goal was simple to say and hard to do: make Medicaid compliance a side effect of a normal workday. Schedule a visit, clock in, clock out, and the audit trail, state submission, and claim build themselves.

The problem

Federal law requires agencies to verify who delivered care, to whom, where, when, and under which authorization, for every single visit. Miss a data point and the claim gets denied. The existing tools are fragmented across web, mobile, and state-reporting portals, and caregivers are busy caring for people, not babysitting forms.

Home care also has a fraud problem, which is why the data model treats visits as evidence: once a clock-in exists, nobody gets to quietly rewrite history. Not even the people who run the database.

One typed core, three surfaces

The core package is the only workspace allowed to touch PostgreSQL. It holds Zod domain entities, about 30 Knex repositories, the migration runner, and the state aggregator integrations. The Express API composes those into routes, the React console and the Expo app are pure API clients. A scheduling or billing rule lives in exactly one place and behaves the same everywhere.

The database does its own enforcement. The audit log has a trigger that refuses UPDATE and DELETE outright, visit rows lock their clock-in facts after creation, and event types are guarded by CHECK constraints kept in lockstep with the domain code. The comment on the audit trigger says it best: nobody, including future us with a SQL console open, gets to edit evidence.

System map
Caregiver appExpo + React NativeOffline queuestore and forwardAgency consoleReact + ViteExpress APIExpress 5 + KnexCopilotClaude on AWS BedrockGeofence checkHaversine, 150 mAudit logappend-only triggerPostgreSQL~40 tablesSandataPA aggregatorHHAeXchangeCSV exportClaims + EDI837P out, 835 in
drag to exploreA verified visit flowing from the caregiver's phone to the state and the claim.

Why this stack

Express 5 with Knex instead of a heavy ORM, because the compliance guarantees live in hand-written PL/pgSQL triggers and raw SQL that an ORM cannot express. A CI check literally fails the build if string-built SQL sneaks in, so everything stays parameterized. PostgreSQL was non-negotiable: append-only triggers, timestamptz hardening, and CHECK-constraint enums are the backbone.

Expo and React Native cover the caregiver app on both iOS and Android from one codebase, with tokens in the platform keychain via SecureStore. The web console is React with Vite because coordinators live in it all day and it needs to feel instant. AI runs exclusively through Claude on AWS Bedrock: the app refuses to boot in production if a non-BAA AI key is present, because PHI only travels to vendors with a signed business associate agreement.

How the pieces talk

The mobile app authenticates with short-lived JWTs pinned to HS256, and every token carries a server-side session id that can be revoked. The web console uses HttpOnly session cookies with CSRF tokens compared in constant time. Both funnel into the same capability-based access control: 18 capabilities mapped across four roles, checked per route, so a coordinator can read billing but only an admin can write claims.

Offline is a first-class citizen. The caregiver app keeps a store-and-forward queue in AsyncStorage: a clock-in with no signal gets a local id, and when the network returns the queue replays in order and remaps the local id to the server one. Punches are treated as evidence, so only a definitive rejection ever drops one, and the server accepts offline timestamps up to 72 hours old before insisting on a formal visit correction.

One visit, end to end

A recurring schedule materializes into assignments, checked for conflicts and caregiver eligibility. At the door, the caregiver clocks in: the API resolves the assignment, pulls the client's geofence anchor, and runs a Haversine distance check against a 150 meter radius. Outside the fence gets a 422 with the exact distance, plus an audit event. Inside, the visit row snapshots every Cures Act data point at that moment.

Clock-out re-runs the geofence, detects exceptions, and marks the visit verified or flagged. From there the Sandata integration takes over: clients, employees, and visits are submitted as batches over REST, polled for per-record accept or reject, with monotonic sequence numbers on resubmission because Sandata demands them. Verified visits then feed claim generation, which applies the CMS 8-minute rule, scores denial risk, and emits a structurally valid 837P EDI file that goes to the clearinghouse over SFTP. Remittances come back as 835 files and post against the claims. That whole sentence used to be somebody's entire week of manual work.

Security and compliance

PHI columns like Medicaid numbers are encrypted cell by cell with AES-256-GCM before they hit the database, with a random IV per write. Rate limits are tiered per surface, login attempts are capped, TOTP two-factor is available, and super-admin access uses WebAuthn passkeys. The audit middleware records every PHI read, write, and export with a server-generated correlation id, and the retention sweep archives seven years of history, which is longer than HIPAA's own floor.

The AI copilot gets the same treatment. Every prompt is logged as a hash, never as text, because prompts can contain PHI. And when the copilot proposes an action, like enrolling a caregiver in training, it returns a typed, schema-validated proposal that a human must confirm before anything executes. The AI suggests. People decide.

Challenges and honest tradeoffs

GPS is noisy and people are creative. The geofence check deliberately ignores the phone's self-reported accuracy value, because trusting it would let someone borrow 50 meters by spoofing low confidence. On the flip side, the check fails open when a client has no geocoded address yet, because a new client's first visit should not be blocked by missing setup, and the gap is still audited.

Immutability creates its own puzzles. The retention sweep cannot DELETE through its own append-only trigger, so system maintenance briefly and explicitly bypasses triggers inside a transaction, chunked and logged. And since visit rows refuse edits, all corrections flow through a dedicated maintenance workflow with a seven-day window, exactly how Pennsylvania wants it. The HHAeXchange integration is honest about its state: automated submission is not implemented yet, so the code says so and offers a portal-ready CSV export instead of faking success.

Outcomes

RayHealth EVV is live in production at rayhealthevv.com, aligned to Pennsylvania DHS requirements with all Cures Act data elements captured, Sandata submission wired end to end, and real 837P and 835 EDI handling. Adding the next state is a registry entry, not a refactor: New Jersey already exists in the codebase as a config object waiting for its production flag.

The delivery pipeline runs seven required CI checks including type checking, security scanning, and a job that verifies the audit triggers still refuse mutations. Around 668 tests keep the compliance math honest.

RayHealth EVV product demo showing haptic clock-in, the visit review queue, and the state export format
A real visit, end to end: clock-in, the coordinator review queue, and the state EVV export.
Built with
TypeScriptReactViteNode.jsExpress 5PostgreSQLKnexExpoAWS BedrockTurborepoVercel
At a glance
Live
In production at rayhealthevv.com
~668
Tests across core, app, web and mobile
7 yrs
Audit retention, beyond the HIPAA floor
837P
Real X12 EDI claims out, 835 remits in

Want to see more?

Explore the rest of my work, or get in touch about a project.