SMART functional conformance passes. Inferno is green functionally; HTTPS/TLS closure is the remaining SMART gate. View the roadmap

PocketBase Is the Runtime, Not Ilavrita's FHIR Contract

Ilavrita Engineering · September 22, 2026

PocketBase Is the Runtime, Not Ilavrita's FHIR Contract

Version: dev
Source revision: 946221398bc8fa8731838e98e3d040c102df7b63
Last verified: September 22, 2026
Data policy for examples: synthetic data only

Ilavrita uses an embedded runtime to get a compact operational foundation, but clients are not supposed to program against that runtime. The public contract is FHIR R4: Ilavrita owns the routes, error shapes, search behavior, versioning, project isolation, authorization and audit semantics, while persistence sits behind interfaces in packages/storage.

That extra layer is deliberate. Exposing the runtime's collections and REST semantics directly would be faster initially, but it would make internal storage behavior part of the healthcare API and turn a future storage change into an API migration.

The architecture rule is therefore simple:

Runtime choices are implementation details. FHIR behavior is the contract.

This post explains what that means in the current developer preview, why the repository enforces the boundary, and what the design does not prove yet.

The problem with making a database runtime your API

A self-hosted server needs a lot of machinery before its domain API becomes interesting: process lifecycle, persistence, migrations, an embedded database, configuration and operational plumbing.

Reusing a runtime for those primitives is attractive. The dangerous shortcut is to reuse its public data API as the product API too.

For a FHIR server, that leaks the wrong abstractions.

A FHIR client should reason about resources, interactions, versions, OperationOutcome, search parameters, Bundles and the capabilities a server declares. It should not need to know an internal collection name, database filter syntax or a runtime-specific error shape.

Ilavrita's accepted architecture decision, docs/adr/0004-own-the-fhir-contract.md, records exactly this trade-off. The repository accepts more code in exchange for owning the healthcare-facing behavior independently of the storage engine.

The boundary in the current architecture

At the verified source revision, the documented layering is:

text
FHIR client
    |
    v
HTTP surface — apps/ilavrita
    |
    v
FHIR services — packages/fhir, packages/search
    |
    v
tenancy / authorization / audit
    |
    v
storage interfaces — packages/storage
    |
    v
SQLite backend — packages/storage/embedded-runtime

A future PostgreSQL backend is shown behind the same storage boundary, not above it.

The important part is not the diagram. It is the dependency direction.

The repository documentation states four architecture rules:

  1. only the storage backend may import the embedded runtime;
  2. SQL stays below the storage boundary;
  3. runtime concepts must not reach /fhir/R4;
  4. the server must not advertise behavior it has not implemented and tested.

The first rule is documented as being enforced by depguard in .golangci.yml, rather than left as an architectural convention.

That distinction matters. A diagram can drift. A dependency rule can fail a build.

Search is planned before it becomes SQL

FHIR search is a good example of why this boundary exists.

The public request might be:

http
GET /fhir/R4/Patient?family=Nguyen&birthdate=ge1990-01-01

Ilavrita does not define the meaning of that request in SQLite syntax.

The documented architecture parses supported FHIR search parameters into a backend-independent plan. Only the storage backend compiles that plan into its persistence query.

That gives the project two useful properties.

First, the meaning of family, repeated parameters, token matching or a date prefix belongs to the FHIR/search layer rather than to whichever database happens to be underneath it.

Second, adding another backend should require a compiler for the same plan rather than a second implementation of the external search contract.

That does not mean every FHIR R4 search feature is implemented. The current supported surface is deliberately bounded. Token, string, reference and date parameters are documented; number, quantity, URI, composite and special parameters remain outside the current index implementation. Chaining, _has, _include, _revinclude, _sort, _summary and _elements are also documented as unsupported.

Ilavrita's policy is to refuse unsupported behavior rather than approximate it silently. The previous engineering note covers that choice in detail: Why Ilavrita Refuses Unsupported FHIR Search Parameters.

OperationOutcome belongs at the boundary

The same principle applies to failures.

An internal runtime can fail for many reasons, but a FHIR client should not have to understand those implementation-specific errors.

ADR 0004 states that FHIR failures are translated into OperationOutcome at the product boundary. The current project overview likewise says undeclared resource types, unsupported interactions and authentication failures return FHIR-shaped responses rather than framework errors.

That is important for portability. If a database constraint error, collection error or runtime exception became part of the client-visible behavior, changing storage would risk changing the API even when the successful path remained identical.

Owning the error contract is therefore part of owning the API contract.

CapabilityStatement is about the server, not its storage engine

FHIR R4 gives servers a standard place to describe their supported REST behavior: GET /fhir/R4/metadata.

Ilavrita's current API reference says its CapabilityStatement is generated from the same table used to register FHIR routes. The intended invariant is that the statement cannot name an interaction the router does not dispatch, and that a resource is declared only once the matching behavior is implemented and covered by tests.

That is the right architectural level for capability discovery.

A client should be able to ask:

bash
curl -s \
  -H 'Accept: application/fhir+json' \
  http://127.0.0.1:8090/fhir/R4/metadata

and learn about FHIR behavior. It should not need to inspect the database schema or runtime configuration to infer what the server can do.

The same applies to build identity:

bash
curl -s http://127.0.0.1:8090/version

The documented endpoint reports the running version and revision so an operator can match a process to source and release artifacts.

Authorization cannot be an after-the-query filter

The storage boundary also carries a security consequence.

Ilavrita documents Project as its isolation boundary. Project identity is derived server-side, and authorization restrictions are compiled into the query rather than applied to a broad result set after retrieval.

That means higher layers describe what the principal may reach, while the storage implementation is responsible for executing a query already bounded by that scope.

The security documentation describes project isolation and authorization as enforced today, including compartment and field restrictions. Audit is documented as part of the transaction that performs the action.

Those are technical controls in the current implementation. They are not a HIPAA, GDPR, EHDS or production-readiness claim. The project has not had an external security review, and the documentation explicitly says patient data should not be placed in this developer preview.

Why this makes a future PostgreSQL backend less disruptive

The architecture is intentionally SQLite-first.

That is useful for local development and small self-hosted deployments because the server can remain compact. But the roadmap places PostgreSQL and cluster storage later, in the enterprise and scale phase.

The storage-interface decision is what makes that roadmap credible without pretending PostgreSQL exists today.

If FHIR services depend on packages/storage rather than SQLite-specific queries, a PostgreSQL implementation can be added behind those interfaces. Search plans can gain another compiler. Transaction semantics can gain another backend implementation. The public FHIR routes do not need to become PostgreSQL routes.

There is still substantial engineering work hidden inside that sentence. Different databases have different concurrency, locking, indexing and transaction characteristics. An interface does not make those differences disappear.

What the interface does is give those differences a defined place to live.

That is a much smaller claim than "the server already scales horizontally," and it is the one the current architecture supports.

The runtime's own API is not supported product surface

The synced documentation says the embedded runtime's own REST API and administration console are disabled by default. They can be exposed for local development through configuration, but they are explicitly not a supported interface.

This is a useful architectural test.

If an application built against Ilavrita needs the runtime's internal REST API to function, then the storage abstraction has already leaked.

The same applies to administrative privilege. The security documentation states that Ilavrita does not treat a runtime superuser as a valid product principal because such an account would sit outside Project membership, grants and the audit model.

Administration is meant to happen through Ilavrita's own authorization model, not through an invisible second authority underneath it.

What we verified for this post

The article was reconciled against the live Payload-synced project documentation and current generated API reference before publication.

The synced documentation currently points to repository revision:

text
4c36f1c8e5983943710398c2d8c1bd4ea689dbdd

The generated API reference has advanced to:

text
946221398bc8fa8731838e98e3d040c102df7b63

This post therefore uses 946221398bc8fa8731838e98e3d040c102df7b63 as its visible source revision for the current API surface, while architecture claims are limited to decisions present in the synced documentation and not contradicted by that newer API reference.

The GitHub connector available to this publishing run refused direct file reads from the dev branch, so we could not independently execute a clean clone or inspect newer source files beyond the Payload-synced docs and generated API reference. No command result in this article is presented as newly executed evidence.

That limitation matters because the synced docs themselves contain stale passages. For example, the current roadmap checklist marks conditional interactions as complete while an older paragraph lower in the same file still calls them the next missing capability. docs/known-limitations.md similarly contains older prose that conflicts with its newer capability tables. Those stale passages were not used as evidence here.

What this architecture does not prove

A clean dependency graph does not prove production readiness.

It does not prove that a PostgreSQL backend will be easy to write.

It does not prove multi-node behavior.

It does not prove external security assurance.

It does not make a deployment compliant with healthcare regulation.

And it does not mean every FHIR R4 interaction is supported.

The current roadmap still leaves type-level and system-level history, Patch, XML, SMART App Launch, broader terminology behavior, PostgreSQL and several other capabilities for later work.

The value of the architecture is narrower: those capabilities have somewhere to be implemented without redefining the public contract around an internal runtime.

A practical test for contributors

When adding a feature, ask where its semantics belong.

If it changes what a FHIR client observes, it belongs in Ilavrita's public contract and should be represented in tests, documentation and—where applicable—the CapabilityStatement.

If it changes how a resource is persisted, indexed or transacted, it belongs behind the storage boundary.

If a runtime-specific type, route, error or query syntax appears above that boundary, treat it as a design smell.

That is the architectural bet behind Ilavrita's SQLite-first approach: keep the first deployment small without making the first database permanent in the API.

FAQ

Is Ilavrita a PocketBase API with FHIR-shaped routes?

No. The accepted architecture decision is specifically to avoid exposing the embedded runtime as the healthcare API. FHIR routes and semantics are owned by Ilavrita, with persistence behind storage interfaces.

Does Ilavrita support PostgreSQL today?

No. PostgreSQL and cluster storage are roadmap work. The current architecture is designed so a later backend can sit behind the same storage interfaces, but that backend is not a current capability.

Can I depend on the embedded runtime's own API?

Not as an Ilavrita product interface. The project documentation marks the runtime API and admin console as disabled by default and unsupported even when explicitly exposed for development.

Does the abstraction make Ilavrita production-ready?

No. Ilavrita remains a developer preview and should not hold patient data. There has been no external security review, upgrade/rollback work is incomplete, and several protocol capabilities remain intentionally unsupported.


Evidence and further reading

Verification note: this post is evidence from the synced documentation and generated API description, not a substitute for an independent security review or a clean-clone conformance run.

Back to blog