Vaulth AI
Founder & CTO · 2026—

Your records. Your rules. Your vault.

A health records custody and consent platform, built India-first. I am its founder, its CTO, and its only engineer — backend, web, mobile, infrastructure, AI, security and compliance.

vaulthai.health — the platform this page describes →


In short

Problem
Every existing answer to who holds a family's medical records has an owner problem. Hospital portals hold them hostage; aggregators take custody in exchange for access. Neither survives a relative in an emergency room in another city.
Constraint
Protected health information, one engineer, and no certification to hide behind. Anything that needed a second engineer to be safe could not be built.
Decided
Consent architecture first, everything hung off it. Guardrails in code rather than in prompts. Redact before write. Failure direction chosen per surface. Two refactors that shipped no features.
Rejected
The aggregator posture — access in exchange for custody. The faster product and the better-funded business model.
Hardest
Reconciling the right to erasure against tamper evidence. Blocking audit-log mutation protects the log and breaks a legal obligation; a cryptographic hash chain protects both.
Built
207 endpoints, 67 tables, 7 services, 630 tests, ~109 audit findings closed, 276 error-swallow sites closed, and a measured ~30m recovery drill.
Stage
Pre-launch. The next evidence is whether the people this is built for understand and trust the consent model. DPDP-aligned and HIPAA-aligned; not certified, and phrased that way everywhere.

Question

Who should hold a family's medical records — the hospital that produced them, the app that displays them, or the family they describe?

Every existing answer has an owner problem. Hospital portals hold records hostage to one provider. Aggregator apps take custody in exchange for access. Neither arrangement survives the moment that actually matters: a relative in an emergency room in a different city, needing a drug allergy off a discharge summary issued four years ago.

In India the records themselves are scattered further than the software assumes — across hospital silos, WhatsApp threads, prescription drawers and lab portals. So the product question is not "how do we display health data." It is who the canonical owner is, and whether the software will still behave as though they are the owner on the day it would be more convenient not to.

Vaulth's answer is a portmanteau and a stance in the same word. Vault plus health: a private, durable, family-owned custody layer. Prescriptions, lab reports, discharge summaries, vitals, medications and vaccination history, held under the family's control rather than borrowed from someone else's database.

The product sits deliberately across three categories that rarely coexist: a personal health record, a family caregiving platform, and a non-diagnostic clinical AI companion. One governing phrase decides every conflict between them — consent over convenience, custody over copy.

The test

Before the platform earns any scale claim, the consent thesis has to survive contact with the people it was built for.

The first learning loop is deliberately narrow: a primary custodian putting a family's scattered records in one place; a caregiver receiving exactly-scoped access that expires; and a clinician or first responder getting the smallest safe view without installing an app. The product is not proved when those flows exist in code. It is proved when those people understand what they can share, what they cannot, and why.

The first measures are chosen accordingly: activation means a first document uploaded and its AI summary seen; then family-member-added rate, share-link creation, weekly-insight use, and D30 retention. Daily activity and notification clicks are intentionally not success criteria for a records vault. The next work is design partners and the evidence that decides whether the consent model holds.

Constraint

Protected health information, one engineer, and no certification to hide behind.

The data is PHI, so a mistake is not a bug

Everything in the vault is protected health information. A defect that leaks a medication list is not a defect; it is a breach, with a regulator attached. That single fact rules out the entire category of "ship it and iterate" decisions that make small teams fast.

It also changes what the product is optimising for. Trust becomes as load-bearing as usability, and correctness as load-bearing as speed. Patients withhold information when they do not trust how it will be handled — which means a health product nobody trusts is not merely commercially weak, it is clinically counterproductive. Privacy stops being a legal footnote and becomes part of the experience.

Bus factor one

I am the only engineer across the full-stack monorepo — backend, frontend, mobile, infrastructure and AI integration, alongside product, UX, security, DevOps and compliance. Anything that needed a second engineer to be safe could not be built. Anything that needed a second engineer to be reviewed had to have that review manufactured, which is decision 09.

My background is roughly six years in product management, UX and front-end development — a B.Tech in CSE and a dual Master's in HCI and Interaction Technology through EIT Digital, split between the University of Twente and Universidad Politécnica de Madrid — and a prior Product Manager role through April 2026. The backend and infrastructure depth is recent and deliberate. That is the honest shape of it, and it is also why the governance in section Governance exists at all.

Pre-certification, permanently phrased that way

The platform is DPDP-aligned and HIPAA-aligned. It is not certified, and every document, page and email says so in those words. India's DPDP Rules were notified on 13 November 2025 with full enforcement due in May 2027, which is precisely the window in which an unbacked compliance claim becomes its own legal exposure — under the very law you are claiming to satisfy.

Decision

Ten decisions. The first one determines the architecture; the last one determines whether any of the others can be trusted.

Decision 01

Consent is the product. The records are just what it governs.

I built the consent architecture first and let everything else hang off it. That ordering is the whole platform, so it is worth being concrete about what it means.

Seven granular caregiver permission scopes — read and write vitals, read and write documents, manage medications, manage appointments, read lab results — enforced across 61 endpoint applications in 16 route files. A caregiver grant is time-boxed between 1 and 365 days and names exactly which of those seven scopes it carries. "Medications only, ninety days" is a sentence the system can actually express and then enforce.

Every external view of a record is token-gated, time-bound or single-use, rate-limited, scoped, and logged. A doctor gets a share link with an expiry, an access count and a revoke button. A first responder scans an ICE card backed by a random 64-character hex token that the owner can revoke instantly, with every access logged by IP, timestamp and user agent. A relative authorising their own device data into the vault does it through a single-use, fifteen-minute, row-locked token.

Family circles share shapes, not values. Inside a circle of up to six members — joinable by email invitation or a 16-character Crockford-Base32 code, with invitations older than 30 days cleaned up automatically — vitals show a trend and never the raw number; medications show name and dosage only; labs show status only; appointments show date and specialty only. Sharing is toggled per user and per circle across eight data types independently. The circle tells you your father's blood pressure is trending badly. It does not hand you his readings.

Dependant migration closes the loop on ownership: a child who grows up can claim their own account, and their entire health record transfers out of the parent's custody with them. Custody that cannot be handed over is not custody.

Traded away: every convenience that assumes the app may read what it holds. No cross-user analytics, no aggregate insight products, no silent claiming of registered users as dependants, and a permanent commitment never to sell data — which is the one promise that ends the company if it is ever broken.

Rejected: the aggregator posture, where access is granted in exchange for custody. It is the faster product and the better-funded business model, and adopting it would have made every other sentence on this page dishonest.

Decision 02

Guardrails in code, not in prompts

Seven AI capabilities run against Vertex AI and Gemini, and every one of them is non-diagnostic by construction. The way that constraint is enforced is the decision.

Every prose-generating call is prefixed with a safety instruction — no diagnoses, no starting, stopping or changing medication, deflect on emergencies. That is the part everyone does. The part that matters is what happens next: the output is post-scanned against a pattern list, with a safe-deflection fallback, in code.

The failure mode this prevents is specific. A system prompt is a request to a probabilistic system, and the request is honoured most of the time. "Most of the time" is an acceptable standard for a summariser and an unacceptable one for a thing that might tell a diabetic to change their dose. A prompt is a request. A scanner is a control. Only one of them can be pointed at in an audit.

AI guardrails enforced in code rather than in the prompt Document text enters wrapped in per-request 96-bit nonce delimiters so adversarial text inside a prescription cannot address the model as though it were the operator. A safety prefix instructs the model not to diagnose. The model's output is then post-scanned in code against a pattern list; anything matching is replaced by a safe deflection rather than returned. DOCUMENT TEXT96-bit nonce delimitersSAFETY PREFIXno diagnosisMODELGeminiOUTPUT SCANNERpattern list, in codeRESPONSESAFE DEFLECTIONuntrusted inputthe controlA prompt is a request. A scanner is a control. Only one of them can be pointed at in an audit.
Fig. 03 — The safety instruction is the part everyone does. The scanner is the part that holds.

The same reasoning shapes the smaller defences. Document text going into the analysis model is wrapped in per-request 96-bit nonce delimiters, so a prescription containing adversarial text cannot address the model as though it were the operator. In the assistant, tool results are sanitised and any record ID the model supplies is discarded server-side and re-resolved from the session — the model can ask for a lab result, but it cannot choose whose.

Drug interaction checking is permanently pinned to commercial models and authoritative databases, and is explicitly excluded from any future self-hosting or fine-tuning roadmap. It runs automatically on every medication added, checks against the user's own allergies and conditions rather than only against other drugs, and classifies severity across none, minor, moderate and severe with an acknowledgement workflow that records whether the user dismissed it, discussed it with a doctor, or stopped the medication.

Traded away: cost control and independence on the one capability where independence would be worth most. Interaction checking is the capability I am least willing to own the failure of.

Decision 03

Redact before write, not before display

The audit logger writes fourteen-column events — actor, action, resource type and id, old and new values, IP, user agent, method, path, status, metadata — across roughly 99 call sites in 29 files, touching every feature module.

Field-level PHI and PII redaction is applied before the row is written. Passwords, tokens, ABHA identifiers, dates of birth, phone numbers, email addresses, medication and allergen names and free-text notes are stripped on the way in. Redacting at read time would have been half the work and none of the guarantee: it leaves the sensitive values sitting in a table, protected by the correctness of every future query written against it.

Two further properties follow. Audit write failures fail loud — an alertable event fires rather than the write being swallowed, because an audit log that silently stops recording is worse than none. And a BEFORE DELETE trigger hard-blocks deletion of audit rows outright.

The disclosed trade-off: UPDATE is deliberately not blocked, because the account-erasure flow needs to null the user reference on the rows it leaves behind. Two rights are in direct conflict there — the right to be forgotten needs to mutate the record, and tamper evidence needs it immutable — and no configuration of a delete trigger resolves that.

So the resolution is not a permission, it is a cryptographic hash chain across the audit log. Erasure can still null a user reference, and any edit that is not that breaks the chain and is detectable. Blocking the write would have protected the log at the cost of a legal obligation; chaining it protects both, which is the only reason the trade-off above is acceptable rather than merely documented.

The full record — decisions 04–10, the vault, the AI layer, the numbers, what two audits found The complete build log · about 5,000 words

Decision 04

Fail closed where it protects the user, fail open where it protects the user

Authentication runs on HS256 JWTs with a pinned algorithm and a one-hour TTL, delivered in HttpOnly, SameSite=Strict, secure cookies, with a bearer fallback for mobile. A sliding refresh mints a new token inside the final fifteen minutes, capped by an immutable seven-day absolute session lifetime.

Revocation is Redis-backed: a denylist of SHA-256 hashes of revoked tokens with a TTL matching each token's remaining life, plus a per-user mass-revocation timestamp, both checked on every request. If Redis is unreachable, that path returns HTTP 503. The alternative — treating an unverifiable token as not-revoked — would mean a cache outage silently reinstates every session a user has ever revoked.

The generic login-lockout counters do the exact opposite and fail open, for the same reason read the other way: a Redis outage must not become a global lockout that denies users their own records. The rule is not "fail closed"; the rule is that the direction of failure is chosen per surface, according to which way the user gets hurt.

Failure direction chosen per surface rather than as a blanket rule When Redis is unreachable, the token revocation path fails closed and returns HTTP 503, because treating an unverifiable token as not-revoked would silently reinstate every session a user has revoked. The login lockout counters fail open and allow the attempt, because a cache outage must not become a global lockout denying users access to their own records. The direction of failure is chosen per surface according to which way the user is harmed. REDIS UNREACHABLETOKEN REVOCATIONdenylist checkHTTP 503FAIL CLOSEDa cache outage must not silently reinstateevery session the user has ever revokedLOGIN LOCKOUTattempt countersALLOWFAIL OPENa cache outage must not become a globallockout that denies users their own recordsThe rule is not "fail closed". The direction of failure is chosenper surface, by which way the user gets hurt.
Fig. 02 — The same outage, two opposite answers. Both are the safe one.

The same posture runs through the infrastructure. Internal service-to-service calls carry a shared key compared in constant time, and both downstream services refuse to start if that key is unset. The server refuses to boot at all if the JWT or encryption secrets are missing or shorter than 32 characters, and refuses to boot in test mode without an explicit override.

It also produced the sharpest item on the current work list. Porting the token cache from node-redis to ioredis carries a named trap: it must set an explicit command timeout and disable offline queuing, and it must never inherit the shared queue factory's retry setting — which would silently convert a fail-closed cache into a request pile-up that looks healthy right up until it isn't.

Decision 05

Two refactors that shipped no features

This is the decision I would defend hardest, because both of these were expensive, invisible to every user, and correct.

The Flutter rewrite, then the redesign on top of it

The mobile client was rebuilt from scratch as a clean-architecture Flutter v2 app. The legacy client was deliberately and fully discarded rather than incrementally migrated — only the logo, the locale files and the model documentation were salvaged. The new app is feature-first, with Riverpod for state, go_router for navigation, dio for networking and freezed for immutable models.

Then, on top of that, a brand redesign across roughly 50 screens and 28 feature modules, executed as a behaviour-identical refactor — brand design tokens, a typography theme extension, a defined motion system and eleven new core widgets, with no change to underlying logic. Two full passes over the same surface, neither shipping a feature.

What it bought: a codebase where a change is a change rather than an excavation, and a test suite that grew to 630 tests. What it caught: the mobile app was never syncing the user's preferred language back to the backend, so server-generated AI summaries were arriving in English no matter which of the six languages the user had chosen. A localisation feature that was live, tested, and doing nothing for anyone.

Bull to BullMQ, complete rather than partial

The queue layer ran on Bull, a frozen library. Migrating it moved 12 processors, 28 producers and 7 repeat producers across 15 commits, and added 40 integration tests — the first test coverage the queue layer had ever had.

It was done completely rather than incrementally because of a standing rule: never run two versions of the same library at once. A half-migrated queue layer has two sets of semantics for the same operation and no way to reason about which one a given job got.

The migration surfaced five latent defects that had been in production, silently: a promise crash in the queue client, pause(true) behaving as local-only when the code assumed it was global, queue-level listeners being dropped without error, a circle-maintenance consumer wrongly attached at API-module load time, and a circle-maintenance job firing at the wrong time. None of those would have been found by a partial migration, because none of them announced themselves.

An earlier audit of the same layer had already found one queue — interaction-check — that had neither a processor nor a producer, and whose work was quietly happening synchronously inside a route handler instead.

Traded away: months of visible progress, as the only engineer. Both were the price of being able to change anything afterwards.

Decision 06

Never claim a certification you cannot back

"DPDP-aligned and HIPAA-aligned — not certified" is the standing phrasing everywhere, and it costs real conversion. What backs it is a set of controls that can be pointed at in code:

Right to erasure: re-authenticated deletion, with storage objects enumerated before the cascade so nothing is orphaned, and transactional deletion across Postgres foreign-key cascade, Cloud Storage, Redis sessions and derived materialized views — retaining only an anonymised trace of the deletion event itself.

Right to portability: a one-call structured export across 13 data categories, with documents exported as metadata only — deliberately excluding raw storage paths — and per-table fault isolation so a single failure cannot void the entire export.

Consent capture for minors: a parental-consent timestamp and grantor recorded when a family member under 18 is added. And the disclosed gap alongside it: that consent is self-asserted by the account holder rather than independently verified, and is captured on add but not on later updates.

Data isolation: every query scoped server-side to a resolved owner identity, never to an identifier supplied by the client.

Layered rate limiting sits under all of it: 300 requests per 15 minutes globally, 5 per 15 minutes on login, registration and verification, 3 per hour on password change, 50 per hour on upload, and dedicated caps on every public token endpoint — each of which also pre-validates the token against a strict 64-hex format check before doing any work.

Decision 07

Meet the documents where they already live

Records enter the vault three ways: web upload, mobile upload, and a WhatsApp message to a linked number. The third is the one that matters in India, because most prescriptions in India are already in a WhatsApp thread. Asking a family to re-photograph documents into a new app is asking them to redo work they have already done.

The implementation deliberately refuses to be a special case: the backend validates the webhook's HMAC signature, downloads the media, and enqueues it exactly like a web upload — same OCR, same classification, same summarisation, same pipeline. A second ingestion path would have been a second set of bugs.

Three ingestion paths converge on a single processing pipeline Web upload, mobile upload and WhatsApp all feed one queue. The WhatsApp path validates an HMAC signature first and is then enqueued exactly like a web upload. From the queue every record passes through the same OCR, classification and summarisation stages before it is written to the vault. The OCR stage runs an English-only model, which the page states rather than hides. WEB UPLOADMOBILE UPLOADWHATSAPPHMAC verified, then enqueued exactly like a web uploadQUEUEBullMQOCRPaddleOCR · CPUEnglish-only — stated, not papered overCLASSIFYSUMMARISEGemini · 6 localesVAULTone pipeline — same OCR, same classification, same summarisation
Fig. 01 — Three ways in, one pipeline. A second ingestion path would have been a second set of bugs.

Decision 08

Six languages, and English-only OCR admitted in the same breath

The platform ships in English, Hindi, Telugu, Kannada, Gujarati and Marathi — interface, AI-generated document summaries, and notifications. Every intake summary is generated in all six locales.

And the OCR underneath is English-only. PaddleOCR 2.7.3, CPU, English language model. That gap is stated plainly in the technical documentation rather than papered over, because a six-language product with a one-language extraction layer has a real ceiling, and the people most likely to hit it are exactly the aging parents the product is for. The PaddleOCR 3.x upgrade is the next OCR item on the board; vision-language OCR candidates have been benchmarked against a verified extraction-pair corpus for adoption when GPU serving justifies itself.

The same honesty applies to ABHA. India's health account identifier is stored as a field. There is no ABDM gateway integration — no linking, no verification, no OTP flow — and the product does not present itself as an ABHA integration play.

Decision 09

Manufacture the review a team would have provided

A single engineer has no code review by default. So I built the friction.

An engineering constitution as a foundational governance document. Session-based development, where every working session runs read-only discovery first, then a hard sign-off gate, then bounded execution increments — no drive-by changes, strictly scoped. A technical debt register as a first-class tracked artifact. Seven blocking CI gates. Branch sequencing discipline, one thing merged before the next branches. And local gates forced to match CI exactly, after repeated CI failures traced to a weaker local check.

The operating principle underneath is worth stating directly, because it came from being wrong repeatedly: every defect of real consequence lives in a seam — repo versus production schema, test database versus deployed database, script versus actual cloud state, config versus code. Which is why "live" is defined strictly as traffic is flowing, not that a code path exists and would work if someone provisioned it.

That definition earned itself. A production schema fork dating to April 2026 — ten hand-seeded migration files that had never actually been executed against the live database — sat undetected because the repository and the deployment each looked internally consistent.

Decision 10

Treat a sign-off as a claim, including my own

Every published claim carries an explicit confidence label: Confirmed, Partial, or Inferred. Gate reports are required to re-verify sign-off claims against the underlying evidence rather than accept them.

That rule exists because sign-off documents produced three consecutive false claims: an inverted recommendation, an invented figure, and a reversed encoding call. Three in a row is not carelessness, it is a systematic property of documents written by the party being assessed.

Two related checks fall out of it. AI-generated evaluations that inflate their scores on re-asking, award the top mark on whichever dimension flatters the subject most, or resolve every contested point in the subject's favour are treated as carrying a sycophancy signature, and held to the same evidence standard as any other claim. And characterization tests must include mutation verification — proving a negative assertion actually goes red when the behaviour changes, because a test that passes while testing nothing is worse than no test at all.

The failure mode I watch for by name is the one this whole section is closest to: optimising for artifact quality at the expense of operational reality. Constitutions, design systems and documents are easier to make excellent than observability, error handling and verified production behaviour. Every count on this page carries its own counting method and grep, cross-checked adversarially before publication, for that reason.

The vault

Eight clusters, each with its own register.

The information architecture is organised around what each surface is emotionally for, not around the database. Health — vitals, alerts, medications, journal, labs — is calm and archival. Records — documents, medical history, vaccinations, reports, the ICE card — is the vault proper, plus exports. Care — doctors, appointments, family, circles, caregivers — is warmer and relational. AI is reserved and visually separated. Connect handles data entering and leaving. Settings, a lightweight unauthenticated Public tier for share and ICE links, and an internal Admin surface complete it.

What it actually does

Vitals. Blood pressure, heart rate, glucose, oxygen saturation, temperature, weight and height, charted across 7-to-90-day windows, comparable across up to four family members, with count, average, min, max and standard deviation. Alerts run on user-defined thresholds with severity classification, configurable quiet hours to prevent alert fatigue, automatic caregiver email on critical readings, and an audit trail of every alert raised and acknowledged.

Medications. Full records with prescribing doctor, adherence logging across taken, missed and skipped, automatic stock deduction with low-stock alerts, refill tracking with pharmacy and cost, and custom reminder schedules with snooze.

Documents. Multi-page camera or file upload across seven formats up to 20MB, PaddleOCR extraction, AI classification into medical or non-medical with category assignment, summaries capped at 50 words, extracted dates and searchable tags. A manual override forces analysis on anything auto-classified as non-medical — the escape hatch for when the classifier is wrong about someone's records. Plus folder organisation, per-document ownership reassignment, presigned downloads and on-demand reprocessing.

Labs. Structured extraction of test name, value, unit, reference range and a confidence score, automatic classification into normal, high, low or critical, a materialized view built specifically for fast trend queries, and notifications on abnormal results.

History, appointments and vaccinations. Chronic conditions, allergies with severity and reaction, surgical history with facility and surgeon. Appointments with type, status workflow and post-visit notes. Vaccination records with batch number and facility, compared against India's National Immunization Schedule and WHO schedules, with completion percentage, a 30-day upcoming view, and upsert logic that prevents duplicate vaccine-and-dose entries.

Family. A visual family tree with computed health-status indicators derived from vital alerts in the last seven days and cached for five minutes, an alternative card view, and a one-spouse-per-user rule.

Journal. Daily mood and energy on a 1–10 scale with notes, predefined and custom symptoms, monthly summaries, and a unified timeline that merges vitals with journal entries so correlations can be seen rather than asserted.

Reports and integrations. On-demand PDF health reports with selectable sections and date scoping, retained for 30 days behind presigned URLs. Google Fit, Apple Health and Health Connect sync with conflict-handling deduplication and encrypted-at-rest OAuth tokens, on a manual trigger with a documented ~30-second update delay. Share links carry access-count and last-accessed tracking with copy, preview and revoke controls — and the AI-assisted sharing modal reuses stored ingestion output rather than making a live model call, because selecting what to share should not cost a round trip to a model.

Accessibility and personalisation. Font-size selection with live preview, light and dark themes, density modes — because the second-largest persona is an aging parent who did not sign up and will not be configuring anything twice.

The five people it is built for

Personas the codebase actively serves
PersonaNeedWhat wins them
Primary custodian, 28–45One trustworthy place; confidence that others can step inWhatsApp intake, then the first AI summary of a messy old report
Aging parent / dependentSimple views, big text, their own languageSix languages; a child who stops calling to ask for sugar readings
CaregiverExactly-scoped access that expiresA grant that says "medications only, 90 days" and means it
Doctor, transientA clean complete view with no app installA share link that opens fast and leads with a summary
First responder, anonymousBlood type, allergies, conditions, medications, contacts — nothing elseNo login, no chrome, no friction

The last row is also the one screen where motion is explicitly forbidden. The ICE page renders instantly and statically, with zero animation, because the person reading it has ten to thirty seconds of attention and is not a user in any sense the rest of the product recognises.

Design decisions I made as well

The brand is deliberately institutional rather than clinical: a royal blue primary (#0066FE) instead of the mint-and-teal healthcare default, a warm paper background (#F8F5EF) rather than pure white, and a green (#04C092) reserved strictly for data visualisation.

One rule in that system does real work: lavender is exclusive to AI. It appears on AI-generated content and provenance surfaces and nowhere else — never navigation, never chrome, never admin. In a product whose whole claim is that the user knows where their data came from, a colour that only ever means "a model wrote this" is a consent mechanism wearing a design system's clothes.

Type is Manrope for display, Inter for interface, and a monospace face for vitals, lab values and exports, so numbers read as records rather than as running text. Motion sits at 300–450ms and is never bouncy: uploading a document should feel like sliding it into a vault, not like confetti. Illustration is isometric and architectural, deliberately avoiding both humanoid corporate illustration and the stethoscope-and-pill iconography that turns a vault product into a clinic product.

Even the copy has a banned list — empower, revolutionise, AI-powered, next-generation, unleash, "your health journey" — on the argument that the product's confidence should come from not needing to say any of them.

The AI layer

Seven capabilities, one of them routed, all of them rate-limited and none of them permitted to diagnose.

The seven production AI capabilities
CapabilityPurposeControl
Document analysisClassify, summarise, tag, extract patient name; summaries in all six localesRouted via the Intelligence Router; 96-bit nonce delimiters against prompt injection
Classifier fallbackBackup medical/non-medical call when heuristics are uncertainBackend-direct, near-zero temperature
Health insightsThe weekly narrative analysisSnapshot-hash deduplication; 20/day
Interaction checkingDrug, allergy and condition interaction severityFails soft to an empty result on error; 30/hour
Lab extractionStructured results from OCR'd textSeparate client instance
TranslationNon-English locale generationDB-cached; cluster-safe cost limiter
Assistant chatFunction-calling over the user's real recordsTool-result sanitisation; model-supplied IDs discarded; max 3 tool rounds; 30/hour

The weekly insight, and why it is deliberately quiet

A Sunday 06:00 IST cron aggregates vitals with statistics and trends, medications, lab results, journal mood and energy, symptoms, conditions and allergies into a single narrative analysis — with per-metric trend significance, risk flags across urgent, discuss-with-doctor and monitor, prioritised action items, medication-effectiveness signals, and AI-detected symptom correlations. Snapshot hashing means identical data never regenerates an identical insight, and users can mark each one helpful or not.

It is the product's core retention loop, and it is deliberately toned down. A weekly summary of your family's health is not a Spotify Wrapped, and the moment it starts performing enthusiasm it stops being trustworthy.

Model governance

The platform ran on Gemini 2.5 Flash with temperature tuned per capability — 0.1 for classification, 0.2 to 0.3 for insights, interactions and chat — and has since moved to Gemini 3.1 Flash-Lite. Any model-string change requires a structured 20-to-30 document evaluation diffing JSON outputs across versions before the switch. A model upgrade is a behaviour change to an extraction pipeline, and the fact that it is one line in a config file is exactly why it needs a gate.

Two Gemini SDK stacks currently coexist — the router on the older Vertex SDK, the backend migrated to the newer one. That is disclosed as engineering debt rather than presented as an architecture, and it violates the no-coexistence rule that drove the BullMQ migration, which is why it is on the register.

Separately, and earlier in maturity: I am fine-tuning a medical-domain model derived from Google's open MedGemma, aimed at reducing long-term Vertex AI dependence. Document classification and lab extraction are the first fine-tuning candidates, 9 to 15 months out and contingent on managed serverless GPU serving. Interaction checking is permanently excluded from that plan.

The numbers

A July 2026 repository census. Every figure carries its own counting method.

  • 207API endpoints
  • 67Database tables
  • 630Mobile tests, from 623
  • 276Error-swallow sites closed
  • ~30mDisaster-recovery RTO, drilled
  • 6Indian languages
Full platform census, July 2026 snapshot
MetricCountNote
API endpoints207Across 67 route and module files
Database tables67Distinct — reconciled by hand from 79 raw CREATE statements
Migrations38 + 3Numbered, plus three named legacy files; append-only, idempotent
Worker queues12Now fully on BullMQ: 12 processors, 28 producers, 7 repeat producers
Web pages3326 protected, 7 public
Mobile screens50Across 28 feature modules
Locales6English, Hindi, Telugu, Kannada, Gujarati, Marathi
AI capabilities7One routed, six backend-direct
Runtime services7One Docker Swarm stack, two GCE VMs, asia-south1
Caregiver enforcement61Endpoint applications across 16 route files
Audit call sites~99Across 29 files
Audit findings closed~109Across two audit cycles

The 67 tables were counted by hand for a reason

The raw repository contains 79 CREATE TABLE statements. Twelve of those are not tables: one duplicate audit-log creation, and eleven legacy duplicates inside a migration file that had been superseded. Reporting 79 would have been defensible, automatic, and wrong by eighteen percent.

The schema grew from a fifteen-table baseline — users, documents, medications, vitals, family members, audit logs — through insights and chat, medical history and caregivers, family circles, email verification, activity metrics, WhatsApp linkage, translation caching, notifications and device tokens, correlations, habits, and cycle and pregnancy tracking.

Infrastructure

Seven services deploy as a single Docker Swarm stack across two GCE virtual machines in asia-south1, fronted by Traefik v3.3 with automatic TLS. The backend runs two replicas; the worker runs one, constrained to a worker node. The Intelligence Router is internal-only with a read-only container filesystem. The OCR service sits on an isolated internal network with all Linux capabilities dropped.

Postgres is managed Cloud SQL rather than in-stack; Redis is managed Memorystore. The whole deployment — VM provisioning, image build and push to Artifact Registry, Traefik wiring, stack deploy — is orchestrated by a single script, with Swarm secrets holding the JWT keys, internal API key, SMTP, WhatsApp and OAuth credentials. CI runs on GitHub Actions with Workload Identity Federation, and Sentry carries a PHI-scrubbing allowlist so the observability layer cannot become the leak.

Encryption, stated precisely: application-level AES-256-GCM with a per-value random IV and auth tag covers exactly one surface — integration OAuth tokens — keyed from a static 32-byte environment variable that is not KMS-managed and not KMS-rotated. Everything else at rest relies on Cloud SQL and Cloud Storage platform encryption, strict per-user query scoping, and presigned expiring URLs. There is no column-level KMS encryption and no pgcrypto anywhere. That is a weaker claim than "all PHI is encrypted at the application layer," and it is the true one.

What two audits found

Roughly 109 findings across two cycles, and the remediation is the receipt.

The more recent cycle returned 51 findings and triggered a multi-session remediation effort. It closed 276 error-swallow sites — code paths that caught an exception and continued as though nothing had happened. It wired Sentry with PHI scrubbing. It reconciled the April 2026 production schema fork. It stood up real-database integration tests and production-shape CI. It built a PHI-safe typed logger with allowlist serialization. It drilled a disaster-recovery restore and measured it at roughly a 30-minute RTO rather than assuming one.

And it closed seven features that had silently never worked in production. That is the number I find most useful about this platform, because it is the one that proves the claims discipline was not theatre. Seven things that existed in the codebase, passed review, and did nothing.

What the audits changed

Findings from both cycles are closed. Caregiver write access now honours the full scope grant rather than being create-only for most resources. The rate limiters on translation and AI-sharing are cluster-safe rather than per-replica. The audit log carries the hash chain described above. The technical-debt register is current.

What remains is a roadmap item rather than a defect: caregiver management is web-only, with no caregiver screens on mobile yet — the mobile client is planned. Mobile is meanwhile ahead of web on integrations, carrying Apple Health and Health Connect that web does not.

Outcome

A production platform, built and verified. And no evidence yet that anyone uses it.

Everything above is build evidence. 207 endpoints, 67 tables, 630 tests, 276 closed error-swallow sites, a measured restore drill, two audit cycles, a full queue migration and a from-scratch mobile rewrite. The privacy policy, terms and security pages are live at vaulthai.health, with the encryption-scope and audit-log language corrected to match what the code actually does — which means the compliance phrasing described above is checkable without taking my word for it.

None of that is usage evidence. The measurement set is already chosen, and choosing it was itself a product decision — activation defined as a first document uploaded and its AI summary seen, both halves required; family-member-added rate inside week one; weekly-insight open rate; share-link creation rate; D30 retention. Daily active users, session length and notification click-through are deliberately excluded, on the reasoning that a records vault optimised for those would be a worse vault.

No adoption figure appears here because there is not one yet. Every number on this page is build or census evidence; not one of them is a person trusting the platform with their records. This note stays until that changes.

"Live" means traffic is flowing — not that the code path exists and would work if someone provisioned it. Seven features taught me that distinction the expensive way.

node.js · express · next.js 15 · react 19 · typescript · tailwind · next-intl · flutter · riverpod · go_router · dio · freezed · postgresql · cloud sql · redis · memorystore · bullmq · ioredis · vertex ai · gemini 3.1 flash-lite · paddleocr · flask · docker swarm · traefik v3.3 · google cloud storage · artifact registry · github actions · workload identity federation · sentry · dpdp-aligned · hipaa-aligned

Next