Document reference: VP-SIAAS-TS-2026-V3.0 · Status: technical foundation for the specimen Service Agreement between
VeriPath (the service provider) and the client (the data owner — a GP practice, dental practice or pharmacy).
Supersedes V2.0 ("Framework Blueprint"). Alignment: NHS DSPT (Category 3) and DTAC — this document describes the
technical controls the DSPT assertions rest on.
Measured: every IS item was verified on the deployed infrastructure on 2026-10-17, by inspection of the running
servers, not inferred from design.
Two jobs, in this order:
It is not a contract and not a sales document. Where the infrastructure and the model differ, the difference is recorded.
No credential, key, private address or account identifier appears here, by design.
These are the words the specimen agreement should use, defined once.
| Term | Meaning |
|---|---|
| Service provider | VeriPath — supplies and operates the application: code, runtimes, user interface, background workers, updates. |
| Client | The data owner — the GP practice, dental practice or pharmacy that holds the account for its own infrastructure and owns the records in it. |
| client-vps | The virtual private server, held under the client's own hosting account, that carries that client's PostgreSQL database, object store and medical-image store. One client-vps per client; one or more clients may share one where agreed and recorded. |
| Primary server | The service provider's central host: TLS edge/reverse proxy, identity provider, central database and tenant register, operator tooling. |
| App engine | The service provider's application host: the application runtimes for the three sectors, their workers and queues, and the connection pooler. |
| Tenant | One client's logical instance inside the application — the unit that routing, identity and data separation key on. |
| client tunnel | The outbound connection the client-vps itself opens to the primary server, carrying database protocol only. |
| Maintenance agent | The software installed on the client-vps during the build visit that runs updates on the client-vps's own timers and reports results outward. |
| Central reference data | Platform-wide data held by the service provider and containing no client records — clinical terminology (SNOMED CT), medicines reference (dm+d), tariffs. |
| Maintenance record | The entry written each time the maintenance agent runs, which the client can read and export. |
| Development estate | The provider's own test client-vps instances, used to develop the client-side software and as the canary for every patch and image refresh before it reaches a client. |
| Example-model client-vps | A provider-owned client-vps installed and then handed into the no-login posture, kept as the standing demonstration of what a client receives. |
| Production client-vps | A client's own client-vps, handed over with no login held by the service provider. |
client's browser
│ TLS
▼
PRIMARY SERVER ....... identity provider · TLS edge · central database & tenant register
│
▼
APP ENGINE ........... application runtime · workers/queues · connection pooler
│
│ database protocol, over the tunnel the client-vps opened
▼
CLIENT-VPS ........... PostgreSQL (the client's records)
object store (documents, dental radiographs)
image server (DICOM) · maintenance agent
The application is remote from the data. The only path between them is one the client-vps opens outbound, and it carries
the database protocol — not a shell.
Carries the TLS edge and reverse proxy, the identity provider, the central database (tenant register, platform
configuration, audit and session state) and operator tooling. It is also the endpoint the client-vps tunnels terminate
on, and those endpoints are bound to loopback, so they are not reachable from the network.
IS: every client-tunnel endpoint on the primary server listens on its loopback interface only, verified by
listening-socket inspection.
Runs the applications for the three sectors as separate runtimes with their own workers and queues, and the connection
pooler in front of the tenant databases. The application resolves the tenant from the request host, binds the session to
that host, and routes each database query to that tenant's database.
IS: the connection pooler holds each tenant's server credentials itself and carries a separate administrative
credential from the one the web process authenticates with — so the web process cannot pause or reconfigure the pooler.
Per-connection logging is enabled, which is the record an auditor asks for.
IS: a session is bound to the tenant host it was created on. Replayed on another tenant's host it is treated as
anonymous; measured before and after the fix — 200 as the other tenant's user of the same primary key before,
302/anonymous after.
Holds, under the client's own hosting account:
IS: on the dental client-vps, PostgreSQL, the object store and the image server all listen on loopback only;
nothing is published to the public interface, and an external TCP probe of the database port from outside the hosting
network is dropped.
IS: the client-vps's firewall default-denies inbound; the database port is permitted only from a private range; SSH is
key-only.
An SSH reverse tunnel per tenant, opened by the client-vps, terminating on the primary server's loopback; the
application reaches the tenant database through a loopback-bound local port. The client-vps's tunnels run under the
client's own service units.
IS: the tenant-database path is SSH reverse tunnels; the client-vps holds the keys for its own outbound tunnels.
Not yet uniform: one client-vps in the development estate also runs a WireGuard interface alongside the two SSH tunnel
units. The tenant data path is the SSH tunnels; the WireGuard route is a second, unused transport and should be removed or
adopted deliberately (§7).
| Sector | Records on the client-vps | Anything on the provider side? |
|---|---|---|
| GP | patient records, appointments, clinical notes, prescriptions, documents | No client records — the application relays |
| Dental | as GP, plus radiographs in the object store and the DICOM image server | No client records |
| Pharmacy | patient and dispensing records, stock and supply data for that client | No client records; medicines reference data (dm+d) is platform data |
Central reference data is not client data. Clinical terminology (SNOMED CT) and medicines reference (dm+d) are held
once, centrally, on the provider side, because every tenant searches the same corpus. They contain no patient
information.
Because the production posture holds no login, maintenance has one shape: it runs on the client-vps and reports
outward.
| What is updated | Cadence | Who acts |
|---|---|---|
| Security fixes to the operating system | continuously, by the client-vps's own update service | nobody |
| The rest of the operating system (full run) | monthly, on the client-vps's own timer, in its own quiet slot | nobody |
| Packaged software — database engine, and for dental the radiograph store | quarterly, planned and staggered | nobody at the time |
IS — measured on a client-vps: four timers — a poll every 30 minutes, inventory and reboot daily in that
client-vps's own slot, and the monthly patch run on the 1st — each reporting outbound; the run's outcome becomes a
maintenance record.
The standing rules — stagger slots, the 7-day / 30-day restart rules, never a silent restart — are in
Patching & maintenance — how it works and
what we promise.
IS: a read-only maintenance view in the client's own application — the runs against their client-vps, result and
outcome, outstanding packages, the cadence in words ("patched monthly on the 1st; security updates applied
continuously") rather than a promised date, and two CSV exports for an auditor. Verified live: five real records and
both exports on a client tenant.
Extraction is by ownership. The client holds the database credentials and the server, so a complete extract is a
pg_dump run on their own client-vps plus a copy of the object and image stores from the same machine. Nothing in that
depends on the service provider being available, cooperative or still trading.
| Service provider | Client | |
|---|---|---|
| Hosting account for the client-vps | procures only if asked; never holds the account | holds it |
| Database credentials on the client-vps | not held in the production posture; rotated to the client at handover | holds them |
| The records | relays them in transit only | owns and holds them |
| Application code, configuration, updates | holds | — |
| Platform reference data (terminology, tariffs) | holds — contains no client records | — |
| Session, audit and maintenance state about the client's service | holds (metadata about the service, not its records) | can read and export the maintenance records |
| Break-glass access to the client-vps | none in the production posture | holds it |
| Data extraction | none required | performs it themselves |
The no-login promise is a property of a handed-over client-vps, not of every client-vps that exists. Three postures
are recognised and must be distinguished in the agreement:
| Posture | Whose | Our login | Purpose |
|---|---|---|---|
| Development / canary | service provider | present | develop the client-side software; prove every patch and image refresh before it reaches a client |
| Example model | service provider | removed after installation | the standing demonstration of what a client receives; where the pre-contract checks are shown |
| Production client | client | none from handover | the client's live service |
IS, 2026-10-17: both client-vps instances in the development estate are in the development/canary posture — our
estate key is accepted as root on each, and SSH is reachable from the internet on each (password authentication refused;
the key is the way in). No client-vps is yet in the no-login posture. By ruling (Matthew, 2026-10-17) the development
estate keeps its login while the client-side applications are being built, and example-model client-vps instances are
to be provisioned to carry the no-login posture. A production client-vps is never handed over in development posture.
The account model (ruling, Matthew, 2026-10-17). The service provider procures the client-vps on the client's behalf
and installs the software; the client is the account holder from the outset and the service provider holds the initial
credentials only for as long as it takes to build the machine. At handover the client is given the account credentials and
changes them, after which no value the service provider ever held will work. This is the model the agreement should
describe, and it is the easiest for both parties because the client never has to build anything and never shares
ownership of the account.
The handover sequence — each step producing evidence the client can keep:
After step 7 the client-vps is a production client-vps. From that point the only thing that connects us to it is the
tunnel it opens itself, carrying the database protocol. If the client later wants us to do on-machine work, that is a new,
separately agreed and time-limited access grant — not a standing one.
What the client can do alone, from that day: log in to their own account, see and control the server and its
tunnels, extract their data, and terminate the service without asking us for anything.
May rely on (measured): the records live on the client-vps; the database is not reachable from the public internet
(external probe dropped); the client-vps's stores are loopback-bound on the dental client-vps; tunnel endpoints on the
primary server are loopback-bound; the tunnel is opened by the client-vps and runs under the client's own units; the
pooler holds the tenant credentials and cannot be reconfigured by the web process; sessions are host-bound; maintenance
runs unattended and produces records the client can export; extraction is possible without the provider.
May not rely on yet:
| # | Point | What closes it |
|---|---|---|
| 1 | No client-vps is in the no-login posture (§5). | Provision example-model client-vps instances: install, remove our key, close or restrict port 22, verify by a failed login attempt. |
| 2 | The GP client-vps binds PostgreSQL to all interfaces. | Rebind to loopback at the next build visit; make the firewall the second line, not the only one. |
| 3 | Residual firewall rules on the GP client-vps — a WireGuard listener port and a private-range database allowance — with no WireGuard interface present. | Remove them, or adopt WireGuard deliberately. |
| 4 | Two transports coexist (§3.5). | Rule which one is the client tunnel and state it in the agreement. SSH carries tenant data today. |
| 5 | No in-application bulk export (§3.8, §6). | Build it, or contract extraction-by-ownership and drop the promise. |
| 6 | DICOMweb availability unconfirmed on the dental client-vps's image server. | Verify before any document promises "standard clinical export profiles". |
| 7 | Transient uploads and log content on the provider side are unchecked against "no client records are held". | Review the import staging path and log retention; tighten if either can hold patient data. |
| 8 | Credential-inventory cleanup is outstanding: client-admin database credentials for two development tenants, a plaintext handover document, provisioning files with embedded secrets, one unexplained password file. | Clear before any production client is onboarded. |
In order, and each depending on this one: