RayVerify is the program-integrity sibling of RayHealth EVV. Where EVV proves a visit happened at a time and place, RayVerify asks the harder question: was it real? It layers identity, device, and location signals into an explainable fraud score from 0 to 100 that an investigator can act on before a payment goes out. It is a foundation-stage build: the scoring engine, data model, API, and cloud architecture are real, and I am upfront below about which parts are still designed rather than built.
Overview
RayVerify is an npm workspaces monorepo: a NestJS 11 backend with Prisma and PostgreSQL, a Next.js investigator dashboard with shadcn/ui, and a shared types package. Around it sits an unusually complete paper trail: a 585-line physical SQL schema, a 28-path OpenAPI 3.1 contract, seven Terraform modules defining 150 AWS resources, and about 9,000 lines of design docs covering the fraud engine, security model, and compliance mapping.
The product thesis: EVV compliance data already exists, but states pay first and chase fraud later. RayVerify is built to flip that order.
The problem
Medicaid home-care fraud is usually simple in kind and massive in volume: visits billed from the wrong place, two caregivers sharing one phone, shifts that overlap in ways physics disagrees with. Time and location checks alone miss most of it, and investigators drown in raw data with no ranking.
The system that catches this has to explain itself. A score that says 87 with no reasons is useless in an administrative hearing, so explainability is a hard requirement, not a nice-to-have.
The verification chain
Every visit runs a verification chain: identity, GPS geofence, device posture, patient confirmation, then fraud scoring, fused into an overall pass, review, or fail. Missing evidence always resolves to review, never to a silent pass. The chain result is hashed with SHA-256 over its canonical form and stored immutably, so what the system believed at decision time is provable later.
The fraud engine runs six pure rule detectors: identity mismatch, GPS anomaly, impossible travel, duplicate visit, shared device, and abnormal duration. Detectors are deliberately pure functions with no database access, which makes them trivially testable and versioned. Each one returns a severity, a plain-English explanation, and structured evidence.
Why this stack
NestJS over plain Express because this codebase is guard-heavy by nature: three global guards run on every request (throttling, JWT auth, permissions), and Nest's module system keeps eleven feature modules from melting into each other. Prisma owns the logical model, but the physical schema lives in raw SQL because the important guarantees are things an ORM cannot say: monthly range partitioning on the visits and audit tables, row-level security forced on 19 tables, and triggers that refuse mutations on evidence.
The frontend is Next.js 15 with shadcn/ui and Recharts, styled as a deliberately dense, data-first investigator console. Terraform defines the AWS estate (VPC, RDS with a read replica, ECS Fargate, S3 with object-lock WORM evidence storage, CloudFront, KMS, WAF) so the day the product needs to exist in a government cloud, the infrastructure is a plan-and-apply, not a whiteboard.
Explainability by construction
The composite score uses a weighted noisy-OR: each fired detector contributes a probability, and the fusion computes the chance that at least one is a real problem. The useful side effect is that each detector's share of the final score falls out of the math, so the dashboard can show exactly which signals drove an 87 and by how much.
Every detection run writes one fraud event per fired detector, with the detector name, its version, the explanation, and the evidence. Scores are never overwritten; a rescore is a new row. Combined with the append-only audit log and its per-tenant SHA-256 hash chain, the whole decision history is tamper-evident: change one historical row and every hash after it stops matching.
One visit, end to end
A visit is created and the caregiver clocks in: the API writes an append-only GPS verification with a geofence verdict, snapshots the device, and moves the visit in progress. An identity verification lands as its own append-only record. At clock-out the duration and billed units compute, and the verify endpoint runs the full chain: gather the latest evidence, run the six detectors over a lookback window, fuse the score, hash the chain, and set the visit to approved, flagged, or rejected.
Above the alert threshold the visit surfaces to investigators, ranked by score, with the per-detector breakdown and evidence attached. The design docs take it further: scores above 81 auto-open a case, but an actual payment hold always requires a human investigator. The system ranks and explains; it does not punish on its own.
Security model
Tenant isolation is defense in depth. Every request binds the organization into a transaction-scoped Postgres setting, and row-level security policies enforce it at the database layer, forced even on table owners. A forgotten where-clause in application code returns zero rows instead of another tenant's data.
Auth is argon2id password hashing, optional TOTP, account lockout after five failed attempts, and JWT access tokens with rotating refresh tokens stored only as hashes. Permissions are granular resource-action pairs seeded across roles, and every new endpoint must declare one. The compliance docs map all of it to HIPAA, NIST 800-63, and SOC 2 criteria, because this product's customers are the kind who ask for that mapping on day one.
Challenges and honest tradeoffs
Rules first, ML later, on purpose. Day-one Medicaid fraud has no labeled training data, so deterministic detectors give instant explainability and zero cold start, and the design reserves a queue-fed ML scorer (isolation forests to start, gradient boosting once enough labeled cases exist) as a second opinion that can never be the only opinion. Precision is favored over recall because a false positive delays a caregiver's paycheck and disrupts someone's care.
Being a foundation build, some parts are honest scaffolding: the identity provider is a stub behind a clean interface awaiting a real biometric vendor, the dashboard currently renders mock data while the API contract settles, and Redis plus the async scoring queue are designed but not wired. The docs describe a hypothetical fraudster clocking in 3,950 km away within 15 minutes, a commute of roughly Mach 13, which is exactly the kind of case the impossible-travel detector exists to catch.
Outcomes
The foundation is real and runs: 27 Prisma models, 34 tables with partitioning and forced row-level security, six versioned detectors with passing tests, a 28-path OpenAPI contract, four CI workflows including CodeQL and security scanning, and 150 Terraform resources ready to build the production estate.
Just as important, the hard product decisions are already made and written down: explainable scoring as a legal requirement, humans in the loop for adverse action, and append-only evidence everywhere. The next phase is wiring, not rethinking.