Why Ilavrita Is Not Ready for Patient Data Yet
Why Ilavrita Is Not Ready for Patient Data Yet
Version: dev
Source revision: 4c36f1c8e5983943710398c2d8c1bd4ea689dbdd
Last verified: September 20, 2026
Data used in examples: synthetic only
Ilavrita can already serve a meaningful FHIR R4 surface. That does not make it ready for patient data.
Those are separate claims, and we want to keep them separate.
At the revision this post was verified against, Ilavrita's synced documentation records tested implementations for core resource interactions, declared search, version history, project isolation, authorization, audit, transaction and batch Bundles, conditional interactions, subscriptions, validation, and backup/restore.
It is also still a developer preview.
There has been no external security review. Upgrade and rollback procedures are incomplete. SMART/OAuth is not implemented. PostgreSQL and multi-node operation are later architecture goals rather than current deployment options. Several FHIR protocol areas remain deliberately unsupported.
That distinction is the operating rule for this project:
Claims stop where the tests stop.
This post explains what that means in practice, what a developer can reasonably evaluate today, and why we still tell people not to put patient data into the current build.
What Ilavrita is trying to be
Ilavrita is an open, self-hostable FHIR R4 infrastructure project.
The immediate goal is not to implement every healthcare protocol or build the largest possible platform surface. The first goal is narrower: make the FHIR behavior we do expose predictable enough that an engineer can inspect it, test it, and determine precisely where its boundary ends.
That sounds obvious until a server accepts something it does not understand.
FHIR has a wide surface. A server can support some resource types, only certain search parameters, some interactions, one representation format, or a subset of operations. A client therefore needs more than a base URL. It needs to know what the particular server actually implements.
FHIR R4 provides the CapabilityStatement resource for that purpose.
Ilavrita exposes one at:
GET /fhir/R4/metadata
Our rule is that this document should describe the running server rather than the product we eventually intend to build.
That distinction matters throughout the project.
A roadmap item is not a capability.
An interface in the source tree is not a capability.
A database table is not a capability.
A route that exists but has not had its behavior verified is not something we want to advertise as finished.
The relevant R4 definition is here: HL7 FHIR R4 CapabilityStatement.
What works at this revision
The synced documentation for this revision records the following as implemented.
FHIR resource interactions
For resource types declared by the server, the core single-resource interactions include:
- create
- read
- update
- delete
- versioned read
- instance history
The current documentation records 126 R4 resource types as declared.
A resource type being declared means more than the storage layer being technically capable of holding arbitrary JSON with a resourceType. Ilavrita intentionally separates storage capability from public FHIR capability.
That difference is important.
The public contract should describe what authorization, compartment placement, history, error handling, and other behavior can actually support.
Search
FHIR search is implemented through both:
GET /fhir/R4/{resourceType}?...
and:
POST /fhir/R4/{resourceType}/_search
But the supported search surface is intentionally smaller than the full set of possibilities in FHIR R4.
The server maintains a registry of search parameters that it knows how to index and execute.
If a parameter is outside that supported set, the intended behavior is to refuse it rather than silently discard it.
That is a safety property, not merely a product limitation.
Imagine asking:
Observation?status=final
and receiving every Observation because the server ignored status.
The HTTP request technically succeeded, but the answer is wider than the question. A caller may have no way to discover that its criterion was discarded.
For Ilavrita, unsupported search behavior should be visible.
See the known limitations for the current search boundary.
Project isolation and authorization
A Project is the isolation boundary.
The project identifier is derived by the server rather than trusted from arbitrary client FHIR content, and storage operations are designed around a project-scoped key.
Authorization predicates are pushed into the query path rather than fetching a wider dataset and filtering it afterwards.
That design exists for a simple reason: once data from another project has been fetched into the wrong request path, the isolation boundary has already been weakened.
The current build also supports policy narrowing documented in the authorization design, including compartment-aware access and field restriction.
This is a control Ilavrita implements and tests.
It is not a claim that an Ilavrita deployment is HIPAA-, GDPR-, EHDS-, or otherwise legally compliant.
Those are different questions.
Transactions and batches are now part of the implemented surface
Earlier project documentation described transaction and batch Bundles as future work.
That is no longer the current implementation state at this revision.
FHIR distinguishes the two behaviors.
A transaction is processed atomically: either the transaction succeeds as a unit or the changes do not commit as a successful transaction.
A batch is a collection of independent actions. Individual entries can succeed or fail independently.
Ilavrita's current documentation records both behaviors as implemented.
For transaction Bundles, the server also records support for resolving urn:uuid: references between entries before committing the transaction.
This is exactly the sort of claim that should remain attached to a specific revision. Bundle processing has enough edge cases that "supports transactions" is not useful evidence by itself.
Future posts will break the implementation down against the R4 transaction rules and tests instead of treating the checkbox as the end of the story.
Conditional interactions are implemented too
Conditional create, update, and delete are also recorded as working at this revision.
The important property is not simply having another endpoint form. Conditional operations combine search semantics with mutation semantics.
A conditional write first needs to determine which resource, if any, is being targeted. That search cannot bypass the authorization rules that would apply to an ordinary search.
The current design therefore runs the target search under the appropriate grant for searching that type.
That interaction between authorization and conditional writes is more interesting to us than the feature checkbox itself, and it deserves a separate implementation post.
Audit belongs to the same transaction
The current implementation records audit events for FHIR interactions and login activity.
For successful mutations, the design principle is that the audit record belongs to the same transaction as the action it describes.
We do not want this state:
clinical write committed
audit write failed
request returned success
If a system claims to have an audit trail, recording the event as an unrelated best-effort side effect creates exactly the gap an incident review would care about.
The audit record is also deliberately separate from a client-editable FHIR AuditEvent resource. It is infrastructure evidence about what the server did.
Again, this is a technical control.
It is not a compliance certification.
What we still cannot responsibly claim
This section matters more than the feature list.
No external security review
The security controls in the repository are our implementation and our tests.
They have not yet been validated by an independent security review.
Before a stable release, the project roadmap calls for review of areas including cross-project escape, authorization bypass, injection, file access, secret handling, dependencies, and accidental exposure of health information.
Until that happens, our own test suite should not be confused with independent assurance.
Upgrade and rollback are not finished
The current build can create and evolve the database structures it knows about, and backup/verify/restore workflows are implemented.
That is not the same as having a complete operational upgrade lifecycle.
In particular, the project does not yet document and prove the rollback path we would want operators to rely on between releases.
A database server can behave perfectly during normal API calls and still be unsafe to operate if an upgrade cannot be reversed predictably.
For patient data, operational behavior is part of correctness.
SMART App Launch and OAuth are not implemented
SMART/OAuth work is on the roadmap.
Design work exists, but that is not the same as a production authentication and authorization server.
The current authentication model should therefore be evaluated for what it is now rather than described using future SMART capabilities.
PostgreSQL is a future backend
Ilavrita currently takes a SQLite-first approach.
The public FHIR behavior sits behind storage interfaces so that future storage backends do not need to redefine the FHIR contract.
PostgreSQL, project-aware partitioning, distributed workers, and horizontal-scale deployments are architectural destinations.
They are not reasons to benchmark or describe the current server as a clustered system.
The FHIR surface is intentionally incomplete
Examples of explicitly unsupported or incomplete areas include:
- type-level history
- system-level history
- Patch
- XML representation
- several advanced search features and parameter types
- complete terminology services
- SMART App Launch
- Bulk Data
- FHIR R5
The right response to an unsupported protocol feature is not to hide the gap.
It is to make the boundary inspectable.
That is why known limitations are part of the product surface rather than release-note trivia.
Documentation drift is itself a bug
While verifying this article, we found something worth making public.
The synced documentation at this exact revision is not perfectly internally consistent.
The capability tables in the README, known-limitations document, and roadmap record transaction and batch Bundles and conditional interactions as implemented.
But an older paragraph in the roadmap still talks about conditional interactions as the next missing capability.
Likewise, parts of the architecture document still describe an earlier stage where only the HTTP surface existed, even though the same revision documents working storage, authorization, search, audit, Bundles, validation, subscriptions, and backup/restore elsewhere.
There is also stale introductory language around validation that does not match the newer detailed capability table later in the documentation.
For a project whose promise is evidence-first engineering, documentation drift matters.
The fix is not "pick whichever document sounds newest."
The fix is to reduce the number of independently maintained claims.
Our direction is for the website's What works today surface, documentation, CapabilityStatement, tests, and future blog posts to derive as much as possible from the same machine-checkable capability source.
Until that is complete, every blog post carries a source revision and a last-verified date.
What you should use Ilavrita for today
The current build is useful for engineering evaluation.
Clone it.
Run it locally.
Use synthetic FHIR resources.
Inspect its CapabilityStatement.
Try supported searches.
Try unsupported searches and inspect the failure.
Exercise project boundaries.
Run transactions.
Break transaction entries intentionally.
Inspect history.
Test conditional operations.
Run the backup and restore flow.
Read the implementation beside the tests.
If the behavior disagrees with the documentation, open an issue.
That is exactly the kind of feedback a developer preview needs.
What you should not do yet is treat the repository's existing controls as sufficient assurance for real patient data.
Not because nothing works.
Because enough important assurance work remains that we cannot responsibly make that claim yet.
Reproducing the starting point
The documentation for this post is pinned to:
4c36f1c8e5983943710398c2d8c1bd4ea689dbdd
The documented local setup is:
git clone https://github.com/Ilavrita/Ilavrita.git
cd Ilavrita
make bootstrap
make run
The server then exposes operational identity through:
curl -s http://127.0.0.1:8090/version
and FHIR capability discovery through:
curl -s \
-H 'Accept: application/fhir+json' \
http://127.0.0.1:8090/fhir/R4/metadata
A future article will turn that into a complete clean-clone walkthrough using synthetic resources only.
For this article, those commands come from the repository documentation at the revision above. They were not independently executed in this publishing environment, so we are not presenting their successful execution here as new verification.
That distinction is intentional.
Where the project goes next
The near-term roadmap is still about correctness before breadth.
Among the remaining gates are stronger protocol coverage, upgrade and rollback procedures, SMART/OAuth, broader terminology and profile handling, external security review, and repeatable conformance testing.
Later phases add the things that make a platform larger: PostgreSQL, higher-throughput storage, distributed queues and workers, additional interoperability protocols, enterprise deployment patterns, and developer tooling.
Those should arrive on top of a FHIR contract that already has evidence behind it.
Not instead of one.
The project is open specifically so that other engineers can challenge that evidence.
If a claim is wrong, the most valuable contribution is not agreeing with the roadmap.
It is a failing test.
Evidence for this post
