Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Instructions for use

These are FerroFED’s instructions for use under Regulation (EU) 2025/327 on the European Health Data Space (the EHDS Regulation). Art 30(1)(d) has every EHR system accompanied, free of charge, by “clear and complete instructions for use”; Art 32(2)(d) has them cover “its maintenance, in accessible formats”; and Annex III, point 1(j), puts “the instructions for use for the user and, where applicable, installation instructions” in the technical documentation. Annex II, point 1.2, asks that the system “can be supplied and installed, taking into account the instructions and information provided by the manufacturer, without adversely affecting its characteristics and performance during its intended use”.

This page is the entry point. It says what to do in order and links the reference page that holds each detail. The information sheet names the manufacturer, the version, the intended purpose, the data categories and the standards. Every quotation is from the Official Journal text, vendored at docs/specs/eu-ehds/reg-eu-2025-327-en.xhtml.

Who reads which part

You areRead
The operator who installs and runs a deploymentevery section below
The developer of a client application clinicians useIntended use, Reading an answer safely, Limitations, and The client contract
A deployment’s data protection officer or counselConfiguration for a deployment in the EU, Limitations, Data protection and Regulatory status

Intended use

FerroFED is used by healthcare providers, through the client applications their health professionals use in patient care, to read and write a patient’s openEHR records across the clinical data repositories (CDRs) of a federation. It answers an ordinary AQL query with one result set that names the CDR each row came from, and routes follow-up reads and writes to the CDR that holds the record (Intended purpose).

Use it only for that. FerroFED computes no score, flags no finding and recommends nothing. A client application, a stored query an operator publishes, or a change to FerroFED’s code can bring a purpose of its own, which is outside the manufacturer’s intended purpose and is assessed on its own (The medical device question).

Before you install

  1. Check the platform. FerroFED runs on Linux, x86_64 or aarch64, as a container image or a static binary; nothing is built for Windows (Supported platforms). The gateway holds little in memory: about 2 MiB at rest in the measurement on Memory footprint. Each concurrent query holds its members’ answers, up to federation.max_node_answer_bytes each (The answer bound), so size memory from the sizing below.
  2. Gather the services it consumes: two or more openEHR CDRs that serve ITS-REST 1.1.0, an identity provider for your callers, a PIX Manager, and an Audit Record Repository with the FHIR Feed of ITI-20 (What you need).
  3. Agree the conditions of membership with each CDR’s operator: a unique system_id, version-4 UUID ehr_ids never reused or adopted, each ehr_id fed to the PIX Manager, and consent enforced at the CDR (Prepare each CDR).

Installation

Follow A production deployment in order. Its steps are the installation instructions:

  1. Verify the image or binary against its attestation and pin it by digest (Install).
  2. Write the registry with every endpoint suspended (The registry).
  3. Trust your callers’ issuer (Client authentication).
  4. Give each member its onward credential and make the signing key (Onward credentials).
  5. Configure identity resolution (Identity resolution).
  6. Send the access records to your Audit Record Repository (The access log).
  7. Put TLS in front of the gateway, or on its listener (TLS and the public address).
  8. Run config check, start the gateway, and admit each member with ferrofed admission check before you take its endpoint out of suspension (Check, start and admit).
  9. Send a first query and read its meta.federation (The first federated query).

ferrofed config check reads the configuration exactly as serve does and exits 78, naming the key, on anything it refuses. Run it before every start and every upgrade. Work through the hardening checklist before the gateway reaches real patient data.

Configuration for a deployment in the EU

Four settings decide whether a deployment meets the EHDS Regulation where the gateway can meet it. Add them to the configuration of the production guide:

# ferrofed.toml
[federation.consent]
disclose = false               # Art 8: a restriction is never shown to a provider

[[auth.issuer]]                # the issuer of the production guide's step 4
issuer = "https://idp.example.org/realms/ferrofed"
jwks_uri = "https://idp.example.org/realms/ferrofed/protocol/openid-connect/certs"

[auth.issuer.assurance]
claim = "acr"
minimum = "substantial"        # Annex II 3.1; "high" for cross-border from 26 March 2032
substantial = ["urn:example:loa:substantial"]
high = ["urn:example:loa:high"]

[audit]
destination = "repository"     # the access records of Annex II 3.2

[access_log.templates]
"Example Lab Report.v1" = ["Laboratory-Reports"]
"Example Discharge.v1" = ["Discharge-Reports"]

[access_log.retention]
years = 3                      # Art 9(2): at least three years from each access
  • [federation.consent] disclose = false. Art 8 reads: “The fact that a natural person has restricted access … shall not be visible to healthcare providers.” The default, true, reports a member a consent pre-filter excludes as consent-denied, which the Federation Tier requires (N27a). In the EU set false (Withholding consent exclusions).
  • The assurance level, per issuer. Annex II, point 3.1, asks for “reliable mechanisms for the identification and authentication of health professionals”. Set [auth.issuer.assurance] for every issuer whose tokens reach patient data, with minimum = "substantial"; Implementing Regulation (EU) 2026/2099 Art 6(3) raises a cross-border exchange to "high" from 26 March 2032. List the values your issuer writes; no specification says which acr values stand for which level (The assurance level).
  • The access records to a repository. Every access to patient data is recorded with the verified caller, the patient, the categories and the origins, and an access whose record cannot be stored is refused 503 access-unrecorded (The access log).
  • A category map. FerroFED ships none. Author one in [access_log] from the templates your members hold, or every access is recorded ehds-unclassified ([access_log]).
  • The retention periods. Art 9(2) keeps the information on each access “for at least three years from each date of access”. Declare in [access_log.retention] any longer period your national law sets for a category or an origin, and keep each record at your repository until its ehds-retention-ends (How long a record is kept).
  • The patient namespaces. Art 9(1) gives the person information on “any access”. Name in [access_log] patient_namespaces the namespaces your Member State’s access service searches the log by, so the record of a request addressed by ehr_id names the patient (The patient behind an ehr_id).
  • The emergency purposes. Art 11(5) asks that an access to restricted data in the vital interests of the patient be logged “in a clear and understandable format”. FerroFED names no emergency purpose of use. Declare in [[access_log.emergency_purpose]] the codes your issuers put in the token for it, such as the HL7 v3 ActReason code BTG, or no access is marked (Emergency access).
  • The receiving members. Annex II, points 2.2 and 2.3, ask that an EHR system “be able to receive” data in the European exchange format. This release has no receive path, so there is no receiving member to configure; it is planned with a member declared per category (#665).

Keep two defaults, which the claims review assessed against Annex II, point 2.5:

  • Keep [federation] best_effort at its default, true. With false, a client can no longer ask for a partial answer, so one silent member blocks every answer (Completeness).
  • List each member’s consent refusal codes. A member’s consent refusal fails the whole query 424 until its codes are in the registry’s consent_refusal_codes for that endpoint (Consent). Ask each member’s operator for them at admission.

Sizing

The budgets and limits bound how long one request or one slow member can hold the gateway. Set too low, they delay access; set too high, one slow member holds the clinician’s answer. Size them from what you measure:

SettingDefaultHow to size it
federation.per_node_timeout_ms10000above the slowest member’s 99th percentile on ferrofed_node_request_duration_seconds, measured under your load (Metrics)
federation.overall_timeout_ms25000above per_node_timeout_ms plus the resolver’s and the localizer’s time on their duration histograms (Timeouts)
server.request_timeout_ms30000more than one second above overall_timeout_ms; config check refuses less
server.max_concurrent_requests512the queries your members can take at once divided by the number of members each query asks (The concurrency limit)
federation.max_in_flight_per_node64the requests the smallest member can serve at once; past it a member is reported time-out (The per-member cap)
[server.caller_rate]offset only where one caller can crowd out others (The per-caller rate)

After a change, watch ferrofed_overload_refusals_total and the FerroFEDOverloaded, FerroFEDMemberCapSaturated and FerroFEDSlowAnswers alerts (Dashboard and alert rules).

Reading an answer safely

These are the instructions a client application passes on to the clinicians who use it. Each one is a control of the clinical safety risk file.

  • Read meta.federation.complete before the rows. false means a member that may hold the patient’s data contributed nothing: it was not resolved, it was excluded on consent, or, under a partial answer, it did not answer. Show that the answer is incomplete, and name the members that did not contribute; meta.federation.endpoints lists each with its status (What a client gets back).
  • Ask for a partial answer only where an incomplete record is safe to show. By default a member that does not answer fails the query with no rows. openEHR-federation-completeness: partial returns the other members’ rows with complete: false (Completeness).
  • Expect the same fact from two members. Two CDRs can hold the same entry, for example a medication both recorded. The gateway returns both rows, each with its endpoint, unless the client asks for de-duplication by version identity, which removes only copies of one version. Show the origin of each row, and never add up quantities across members without checking for duplicates.
  • Show the origin. The openEHR-federation-endpoint response header names the members that contributed rows, and a query that selects the ENDPOINT attributes gets each row’s origin in the row (Provenance columns). A follow-up read or write goes to the CDR that holds the record.
  • Treat not-resolved as unknown. In a deployment with disclose = false, a member the patient restricted reads exactly as a member that does not know the patient. Neither means the patient has no data there.
  • Read a 503 access-unrecorded after a write as an unknown outcome. The node may have stored the write before the gateway failed to record the access. Read the resource before writing it again (Failing closed).

Maintenance and its frequency

Art 30(1)(k) has the manufacturer inform users “of any mandatory preventive maintenance of the EHR systems and its frequency”. This release sets no maintenance on a fixed calendar. The maintenance it needs is triggered by an event, and its frequency is the event’s:

MaintenanceWhenReference
Upgrade to the newest releaseat each release, and as soon as you can after a security advisory: security fixes go to the latest release onlyUpgrading, SECURITY.md
Run config checkbefore every start, reload and upgradeRunning it
Re-run ferrofed admission check for a memberwhen the member changes its CDR product, its version, its system_id or how it creates ehr_idsAdmitting a node
Update the category mapwhen a member adds or changes a template[access_log]
Watch the alertscontinuously, on the shipped alert rulesDashboard and alert rules
Clear a quarantined audit recordwhen ferrofed_audit_quarantined rises, after reading why the repository refused itThe audit spool
Rotate the signing keyon your key policy’s schedule, and at once when it may have leakedRotating the signing key
Renew TLS certificates and onward credentialsbefore each expiresHardening
Re-read this page and the information sheetat each releasethe changelog

When a release makes maintenance mandatory, the manufacturer says so in its upgrade notes and through the channels of Complaints and incidents.

Limitations

Art 28(b) forbids “failing to inform the professional user of likely limitations related to interoperability or security features of the EHR system in relation to its intended purpose”. The full list is Limitations; the ones a deployment in the EU must plan for are:

  • The European interoperability software component is not served. The gateway produces and receives no document in the European exchange format (Annex II, points 2.1 to 2.3); the component is a library, and its open hazards are in the clinical safety risk file.
  • The logging component is read at your Audit Record Repository. The gateway has no review route of its own: the records are read there with ITI-81, and the repository sets who may read them and keeps each for the period it states (Annex II, points 3.3 and 3.4; Reading the log). A query over many patients’ data names no patient in its record, so a search by the person’s identifier does not find it, and the records carry no label for access rights by origin and category (#797).
  • The professional’s identification and assurance level are not yet in the access record (#742).
  • No EU declaration of conformity has been drawn up, and no release carries the CE marking (Regulatory status).
  • The Federation Tier specification is a release candidate, v0.9.0.

Accessible formats

Recital 37 asks for instructions “in accessible formats for persons with disabilities”. These instructions are HTML text with headings, lists and tables with header rows; no step is carried by an image or by colour alone. The source is plain Markdown, website/book/src/operate/instructions-for-use.md, and the book’s print page renders every page as one document. Ask the single point of contact for another format.

Problems and complaints

When the gateway refuses to start, answers with an error code, or logs a failure, look the symptom up on Troubleshooting: it leads from the status, the code or the log line to the cause and the setting that fixes it.

Report a problem, a complaint or a possible serious incident through the channels on Complaints and incidents. Never send patient data.