Documents / Platform

Read before changing a boundary between client, database, and model

How the NRTR platform is divided

Read this before you add a feature in the client. The product is several parts with different jobs. Install steps are in Set up a local NRTR environment. Field rules for one write are in Record a health observation.

The question the split answers

A health product collects observations, compares them with reference knowledge, and sometimes asks a model for a suggestion. If those three acts share one database and one process, three bad things happen.

  • A model write becomes indistinguishable from a measured value.
  • A vendor outage takes the person’s history offline with it.
  • A user-interface change becomes a reason to redeploy the record store.

The split below is the answer we shipped when we left hosted collections. More than 100 stores and about 30 workflows were rebuilt onto a database the operator runs. Two people did that rebuild in about two days because the old shape was already written down. The split is what they were rebuilding toward.

Parts

Client
Flutter applicationScreens for the record, training, and nutrition. It sends intents. It does not own clinical rules, and it does not keep the only copy of a record.
Application
Health, training, and nutrition rulesDecides what the next plan is, from stored history plus any suggestion it chooses to accept. Writes the decision. Names the inputs.
Record
Local databaseObservations, plans, and history for the people on this machine. Source of truth for those people.
Suggestion
Model processReturns a proposal for one question. Disposable. Not a second health record. Optional for a given task.
Reference
Shared knowledgeCodes, nutrients, conditions, compounds, and the links between them. Changes when the knowledge changes, not when someone logs a workout.
Outside
About 20 servicesLabs, literature sources, and other APIs. Reached only through the internal boundary. Product code does not see their payloads.
Client
  → application rules
       → local database
       → model process, only if this task asked for a suggestion
       → reference knowledge
       → internal boundary → outside services

Who is allowed to write

WriterMay writeMay not write
ClientA request: “store this observation,” “show the next session.”The row itself, bypassing validation. A fake suggestion to fill an empty state.
Application rulesThe decision, with the inputs used.A silent change to a past observation.
Model processA proposal returned to the application.The database.
Internal boundaryA validated observation, or an error in the NRTR shape.A vendor status code passed through to the client.
Reference knowledgeDefinitions shared by every person.One person’s lab result.

One observation, end to end

  1. The client submits a code, a number, a unit, and a time. It does not submit a person id. The token carries that.
  2. The boundary rejects a bad unit rather than converting it. See the observation contract.
  3. The local database stores the row.
  4. Application rules read history. If they need a definition, they read reference knowledge. If they need a suggestion, they call the model and keep the answer as a proposal.
  5. If the rules accept a proposal, they write a decision. The observation is still the observation. The decision is a new row that points at the inputs.

The measurement and the decision are different rows. The decision points at the inputs it used. The observation stays as it was stored.

Four kinds of state

  • Screen state lives in the client. Losing it must not lose history. Reinstalling the app is not a backup plan.
  • Record state lives in the local database. It is the history.
  • Reference state is the shared knowledge. A workout does not change it.
  • Model state is the context for one question. Discard it when the question is answered. Do not query it later as if it were the chart.

What is allowed to leave the machine

The move off hosted stores exists so a history can be useful without being copied out. A call that leaves the machine is a chosen request: a code lookup, a paper fetch, a vendor sync the operator turned on. The default path for a suggestion is the model process on that machine.

Vendor secrets stop at the boundary. So do vendor body shapes. This is the same rule the observation contract enforces for callers inside the system.

What still works when something is down

DownStill worksWhat the client says
An outside serviceLocal history, and any decision that does not need that service.The specific action failed. History is still there.
The model processRules that do not need a suggestion. Storing observations.Suggestions are unavailable. It does not show a made-up plan.
The clientThe database.Nothing, until a client connects again. The data does not depend on the screen.
The databaseNothing that reads or writes history.A hard failure. Do not fall back to a cache and present it as current.

Before you change a boundary

Write down which part owns the new behavior, which store it writes, and what the client says when that part is down. If you cannot answer those three, the feature is not ready to build. If the answer is “the client will write the row directly,” the feature is wrong.

Update the project record for the files you touch. That procedure is Project records for coding tools.