We are building an app for private health clinics - the app is for booking appointments and includes the issuing of prescriptions (it as a fully compliant advanced electronic signature system) - we will be registering this with the Digital Security Protection Toolkit - what I need to enquire about is how do we vet organisations/practices that want to use this app? How can we tell that the practice is licensed to operate?
To effectively vet private health clinics onboarding to your app in the UK, you must implement a robust process that verifies both the clinic as an entity and the individual clinicians who will be using your Advanced Electronic Signature (AES) system to issue prescriptions. Because you are aligning with the Data Security and Protection Toolkit (DSPT), incorporating these automated and manual verification steps directly into your onboarding workflow will ensure legal compliance and patient safety. [1, 2, 3]
The necessary vetting protocol consists of four distinct pillars.
In the UK, healthcare practices providing "regulated activities" (including medical consultations and prescribing) must be legally registered with the relevant national healthcare regulator. [4, 5]
Note: Some purely aesthetic or holistic clinics may fall outside the scope of statutory registration, but if they are using your app to prescribe prescription-only medicines (POMs), the prescribing individual must still be licensed (see section 3).
Ensure the clinic operates as a legitimate business or legal setup before granting system access.
Because your app handles digital prescriptions, verifying the clinic is not enough; you must also ensure every individual practitioner creating an account has valid prescribing rights. [11]
Statutory Professional Registers: Require each clinician's professional registration number and cross-verify it against the relevant regulatory body:
API Integrations: Most of these bodies allow public search or developer API lookups to confirm an individual's active registration status and check for any restrictions or warnings on their practice. [12, 13]
Under the UK eIDAS regulations, an Advanced Electronic Signature requires the identity of the signatory to be uniquely linked to them.
| Step [6, 12, 14] | Verification Check | Target | Mechanism |
|---|---|---|---|
| 1 | Business Legitimacy | Clinic Entity | Companies House API lookup & AML screening |
| 2 | Healthcare Regulation | Clinic Location | CQC Syndication API (or regional equivalent) |
| 3 | Professional Identity | Individual Clinician | Biometric ID verification (Passport/Liveness check) |
| 4 | Prescribing Rights | Individual Clinician | Live check against the GMC Register / NMC Register |
Would you like to explore how to align this verification workflow with the NHS Digital Technology Assessment Criteria (DTAC), or should we focus on the technical specifications for linking the CQC API to your registration form? [6, 15]
[1] https://www.dsptoolkit.nhs.uk
[2] https://onboarding.prod.api.platform.nhs.uk
[3] https://regulaforensics.com
[7] https://www.harleyacademy.com
[10] https://www.pillsorted.com
[14] https://www.wearethemis.com
[15] https://www.periculo.co.uk
We do intend to apply for DTAC at some stage so may as well align our process to fit the verification workflow
Aligning your verification and onboarding workflows with the NHS Digital Technology Assessment Criteria (DTAC) is a highly strategic move. It ensures that when your software is reviewed by an NHS Trust or a private buyer, your compliance data is already perfectly mapped to the national framework. [1, 2]
Under the updated DTAC guidelines, digital health technologies are evaluated across 5 core areas. Your client verification and prescription workflow directly impacts three of them: Clinical Safety, Data Protection, and Technical Security. [3, 4]
The core DTAC domains map directly to your onboarding steps:
DTAC strictly mandates that as the software manufacturer, you must comply with DCB0129 (Clinical Risk Management). [6]
DTAC requires a comprehensive Data Protection Impact Assessment (DPIA) covering how user data is gathered and kept safe. [1, 6]
The Technical Security domain of DTAC checks how your system establishes secure, non-repudiable access. [6]
Design your sign-up architecture to generate the exact audit trails that an NHS DTAC auditor will look for: [9]
[Clinic Admin Registers]
│
▼
[Step 1: KYB Check] ──────► Automate via Companies House & CQC APIs
│ (Logs official business registration history)
▼
[Step 2: KYC Check] ──────► Clinician uploads ID + performs liveness check
│ (Generates verification success certificate)
▼
[Step 3: Professional] ───► Cross-reference name with GMC/NMC/GPhC API
│ (Confirms "Active" status & Prescribing Rights)
▼
[Step 4: AES Binding] ────► Cryptographic signing key created & bound
(Audit log registers Step 1, 2, and 3 as complete)
Would you like to review how Medical Device Regulations (UKCA Marking) might apply to your app if the prescription system includes clinical decision support (like dosage calculators), or should we discuss how to pass the DSPT tracking requirements?
[1] https://www.burges-salmon.com
[2] https://8foldgovernance.com
[5] https://transform.england.nhs.uk
[6] https://www.england.nhs.uk
[7] https://www.orchahealth.com
[8] https://8foldgovernance.com
[10] https://transform.england.nhs.uk
I don't understand why the need for using a third party 'identity verification partner' - we are supposed to be doing this by checking the signer/clinician details with bodies like the the GMC?
It is completely understandable to think that checking the General Medical Council (GMC) register is enough, as it is the source of truth for their professional status [GMC-UK].
However, a GMC check only answers the question: "Does a doctor named John Smith with GMC number 1234567 exist and have the right to prescribe?" [GMC-UK]
It cannot answer the crucial question: "Is the person sitting at the keyboard right now actually John Smith, or is it an identity thief or an unqualified clinic receptionist using his public GMC details?"
Because public registers like the GMC let anyone look up a doctor's full name, registration number, and status [GMC-UK], your system needs a way to securely connect that public profile to a real, living human being.
Here is why a third-party identity verification partner is used alongside the GMC check to meet Advanced Electronic Signature (AES) laws and DTAC guidelines:
Under UK law, for an electronic signature to be legally classified as Advanced (AES), it must meet strict statutory criteria:
If a fraudulent user types a real doctor's GMC number into your app, you have verified the professional credentials, but you have not verified the identity of the person typing. If they prescribe medication illegally, your platform would be liable for failing to securely link the identity to the digital signing key.
To protect your platform, onboarding must use a two-step verification chain:
Step 1: ID Verification (Who are you?)
[User] ──► Uploads Passport & Selfie ──► ID Provider matches face to photo ──► Confirms: "This is the real John Smith."
Step 2: Credential Verification (What are you allowed to do?)
[Your App] ──► Queries GMC API ──► Confirms: "John Smith holds an active Licence to Practise."
By combining both steps, you prove that the person creating the account is the actual owner of those professional credentials.
You could theoretically ask users to upload a photo of their passport directly to you, but verifying its authenticity is legally and technically complex:
You do not need to make this a clunky experience for your users. In practice, the clinician registers, takes a quick 30-second smartphone scan of their ID and face, and your app automatically matches the verified legal name from that ID against the GMC register database [GMC-UK]. Once they match, the secure digital signing certificate is issued.
Would you like to look at the technical flow of how your database can securely map the identity token from a verification check to the GMC API data [GMC-UK], or should we focus on how to verify non-prescribing clinic staff who might also need app access?
I don't want us to be using a third party verification organisation - what steps must I take have our own verification process - do not say we need to use a so-called specialist third party organisation
To build your own identity verification process natively inside your app without relying on a third-party specialist, you must assume the role of an Identity Service Provider. To align with UK eIDAS regulations for Advanced Electronic Signatures (AES) and pass DTAC, you must build a secure, manual internal vetting infrastructure.
Building your own process means your team will manually review and verify that the physical person behind the screen matches the official credentials.
The concrete steps you must take to build your own verification architecture include:
You must build features into your app to securely collect proof of identity directly from the clinician.
Since you are not using automated third-party software, human operators must visually assess and cross-reference the data.
Once the human identity check passes, your system must programmatically or manually tie that person to their professional body.
Because you are building this yourself, NHS DTAC and DSPT auditors will heavily scrutinise your internal process. You must generate absolute proof of your vetting.
Under UK GDPR, physical identity documents and biometric facial videos constitute high-risk, Special Category Data.
If you proceed with an internal verification process, let me know:
This will help determine how to structure your platform's internal data retention policy.
What responsibilities do practices have though since we will be operating on a B2B basis? If anything, the practices have more responsibility than us for verifying their clinicians?
You are entirely correct. Because you are operating a B2B SaaS platform, the primary, statutory responsibility for clinical governance, employment checks, and safe prescribing rests squarely on the healthcare practice (the employer), not on your software company.
Under UK law and NHS frameworks, your role is to provide a secure tool with adequate safeguards, while the practice holds the legal liability for who they employ and authorize to use it.
The specific division of responsibilities under a B2B framework breaks down as follows.
The clinic using your app is the regulated entity answerable to the Care Quality Commission (CQC) [CQC] or regional regulators. Under CQC Regulation 19 (Fit and proper persons employed), the practice is legally required to conduct full pre-employment vetting.
The practice is responsible for:
While the practice handles the real-world employment checks, your responsibility is to prevent systemic failure or obvious abuse of your system. Under DTAC and DSPT rules, you are a "Data Processor," and the practice is the "Data Controller."
Your platform must provide:
To legally protect your app and align with DTAC requirements, you must embed these responsibilities into your B2B Terms of Service / Software License Agreement (SLA) and your Data Processing Agreement (DPA).
Your contracts should explicitly state:
To lower your internal operational burden while maintaining absolute compliance, structure your sign-up flow like this:
This setup leaves the heavy identity vetting to the employer, while your app performs the safety check on the license.
If you proceed with this delegated B2B structure, let me know:
Yes I think health clinics are required to have a nominated practice manager, similar to GP surgeries?
Yes, exactly. Private health clinics in England operate under a very similar statutory requirement, but the official legal term used by the Care Quality Commission (CQC) is a Registered Manager. [1, 2, 3]
Under CQC regulations, any private clinic operating as an "organisation" (like a limited company) or a "partnership" must appoint a Registered Manager as a legal condition of their registration. [2, 4]
This role maps perfectly to your B2B app’s onboarding design and provides a direct solution for your verification process.
The Registered Manager is the individual in charge of the day-to-day running of the regulated healthcare activities at that specific location. [4, 5]
Because the CQC heavily vets this individual, you should explicitly design your app's workflow to target them as your entry gate. [1]
By aligning your app with the CQC's Registered Manager framework, you pass NHS scrutiny easily:
Would you like to map out the exact fields you should collect on your clinic registration form to match the CQC API output, or should we look at drafting the terms of account accountability for the Registered Manager? [1, 2]
[1] https://dkjsupportservices.co.uk
[3] https://pcmsolutions.co.uk
[7] https://www.healthcareers.nhs.uk
[8] https://dkjsupportservices.co.uk
We need to create an on-boarding process which of course, begins with registering the organisation - what information should we include in the registration form?
To build an efficient, secure onboarding form that feeds directly into your CQC [CQC] and Companies House API lookups, you should structure the registration into a two-part form: ==Section A: The Clinic (Organisation) and Section B: The Registered Manager (The Account Creator)==.
Collecting data this way allows your backend to automatically verify the organization while ensuring the individual creating the account is legally authorized to represent it.
This section captures the data required to verify the business entity and its regulatory status in the UK.
This section collects the personal data of the individual setting up the master account, allowing you to match them against the official CQC records [CQC].
To make the onboarding process smooth and professional for busy clinic staff, consider using a step-by-step layout:
┌────────────────────────────────────────────────────────┐
│ STEP 1: CLINIC DETAILS │
│ [ CQC Location ID ] ──► [ Autofill Button ] │
│ (System pulls and populates Name, Address, and │
│ the official CQC Registered Manager's name) │
├────────────────────────────────────────────────────────┤
│ STEP 2: REGISTERED MANAGER PROFILE │
│ [ First Name ] [ Last Name ] │
│ [ Work Email ] [ Mobile Number (for MFA) ] │
├────────────────────────────────────────────────────────┤
│ STEP 3: LEGAL AGREEMENT │
│ [ ] "I confirm I am the legally designated CQC │
│ Registered Manager for this location and accept │
│ the B2B Terms of Service." │
└────────────────────────────────────────────────────────┘
To maximize form conversions and data accuracy, include an "Autofill via CQC" button. When the user types in their CQC Location ID, your app can ping the CQC API in the background [CQC]. It can then instantly prepopulate the clinic's address and display a message like: "We found your clinic. To continue, you must be the listed Registered Manager: [Name From API]." This saves time and acts as an immediate security check.
If you are ready to design the registration workflow, let me know:
A single page form is fine - I am particularly interested in the 'Autofill via CQC' feature
The "Autofill via CQC" feature is highly effective for a single-page form. It acts simultaneously as a frictionless user experience and a critical security gate.
By having the user input their CQC Location ID or Postcode first, your application can pull verified, immutable data directly from the regulator's database [CQC]. This prevents clinics from typo-ing their regulatory details or falsifying their status.
To make this work seamlessly on a single page, organize your form fields vertically and group them into logical card components. Use a loading state to fetch data dynamically without refreshing the page.
Place this field at the very top of the single-page form. It must be completed before the rest of the form unlocks.
When the user clicks "Find My Clinic", your system triggers an asynchronous background API request (a GET request) to the official CQC Partner/Syndication API [CQC].
"registrationStatus". If the status is anything other than "Registered", the form must halt onboarding immediately.If the API returns a valid, registered clinic, your frontend instantly populates the remaining fields on the single page. Crucially, these fields must be set to disabled (read-only) so the user cannot alter the official CQC data [CQC].
Directly beneath the locked clinic information, the user fills in their personal professional details. This is where they prove they match the locked record above.
" [X] I declare that I am the legally designated Registered Manager, [Autofilled Name], for this location."┌────────────────────────────────────────────────────────┐
│ [CQC Location ID: 1-123456789 ] [ FIND MY CLINIC ] │ ◄ User enters this first
├────────────────────────────────────────────────────────┤
│ ↻ Fetching official CQC data... │ ◄ Visual loading spinner
├────────────────────────────────────────────────────────┤
│ ✓ CLINIC FOUND & VERIFIED │
│ │
│ Clinic Name: [ London Private Health Clinic ] 🔒 │ ◄ Locked / Read-Only
│ Address: [ 100 Harley Street, London ] 🔒 │ ◄ Locked / Read-Only
│ Legal Manager: [ Dr. Sarah Jenkins ] 🔒 │ ◄ Locked / Read-Only
├────────────────────────────────────────────────────────┤
│ YOUR ACCOUNT CREATION │
│ │
│ To gain access, you must be Dr. Sarah Jenkins. │
│ │
│ [ Work Email: s.jenkins@londonprivatehealth.com ] │ ◄ User types this
│ [ Mobile No: +44 7123 456789 ] │ ◄ User types this
│ │
│ [X] I legally confirm I am Dr. Sarah Jenkins. │ ◄ Required Checkbox
│ │
│ [ CREATE ACCOUNT & SETUP SIGNING KEY ] │ ◄ Form Submission Button
└────────────────────────────────────────────────────────┘
Because you are building this natively, you must program your single-page form to gracefully handle three common scenarios:
Would you like to look at a sample JSON data payload from the CQC API to see exactly what the data structure looks like, or should we discuss how to initiate the SMS Multi-Factor Authentication (MFA) step immediately after they click submit?
Yes please provide a sample JSON data payload from the CQC API to see exactly what the data structure looks like
This is the standard JSON schema layout returned by a GET request to the Official CQC Syndication API endpoint (/locations/{locationId}). [1, 2]
The payload is structured so you can target the precise blocks of data needed to validate the legal status, autofill the form blocks, and pull the designated Registered Manager.
{
"locationId": "1-123456789",
"providerId": "1-987654321",
"organisationType": "Independent Medical Agency",
"locationName": "Harley Street Private Health Clinic",
"registrationStatus": "Registered",
"registrationStartDate": "2021-04-14",
"registrationEndDate": null,
"postalAddressLine1": "100 Harley Street",
"postalAddressLine2": "Marylebone",
"postalAddressTownCity": "London",
"postalAddressCounty": "Greater London",
"postalCode": "W1G 7JA",
"mainPhoneNumber": "02071234567",
"website": "https://harleystreetclinicexample.co.uk",
"gpcCode": "X12345",
"odsCode": "Y67890",
"regulatedActivities": [
{
"name": "Treatment of disease, disorder or injury",
"code": "RA1"
},
{
"name": "Diagnostic and screening procedures",
"code": "RA2"
},
{
"name": "Surgical procedures",
"code": "RA3"
}
],
"gfcInspectionCategories": [
"Independent Doctors / Clinics",
"Acute hospital"
],
"relationships": [
{
"relatedLocationId": "1-5555555",
"type": "Previously managed by",
"fromDate": "2018-01-01",
"toDate": "2021-04-13"
}
],
"registeredManagers": [
{
"managerId": "M-999888",
"title": "Dr",
"firstName": "Sarah",
"lastName": "Jenkins",
"status": "Active",
"startDate": "2021-04-14"
}
],
"lastInspection": {
"date": "2025-10-12",
"overallRating": "Good"
}
}
When parsing this JSON on your backend platform, configure your system to extract three specific evaluation metrics:
"registrationStatus")Before pushing any details to your user interface, evaluate this string. If the status is equal to "Registered", proceed. If it returns "Suspended" or "Deregistered", halt execution and flash a status alert message on the front end.
"postalAddress..." & "locationName")Map these values directly into the read-only input fields of your single-page form layout. This ensures your system tracks the exact clinic address and company name officially monitored by the regulator, which is required for your DSPT audit data trails.
"registeredManagers")This nested array holds the name of the legal account holder. Pass the values from "firstName" and "lastName" to a variable array in your backend (e.g., expected_manager_name = "Sarah Jenkins"). Your app will use this string to match against the real name entered by the user creating the account.
On rare occasions, a clinic's Registered Manager profile might change before the CQC's database updates. To account for this edge case without breaking your flow, write a fallback conditional rule: if the user's name does not match the name returned in the "registeredManagers" array, allow them to click an "Approve via manual review" link. This moves their application out of the automated flow and into your internal staff compliance dashboard for physical checking. [3]
Would you like to write out the basic conditional if/else logic to handle these data paths in your code, or should we look at setting up the automatic logging for these lookups to meet the DSPT system logging requirements?
[1] https://anypoint.mulesoft.com
Yes please write out the basic conditional if/else logic to handle these data paths
Here is the basic conditional logic to handle the onboarding paths based on the CQC API data payload. This example uses a universal, clean pseudo-JavaScript style that can easily be translated into your backend language (such as Node.js, Python, or C#).
function processCqcOnboarding(cqcApiResponse, userSubmittedData) {
// 1. Check if the clinic actually exists in the CQC registry
if (!cqcApiResponse || !cqcApiResponse.locationId) {
return {
status: "REJECTED",
errorMessage: "No registered clinic found with this CQC Location ID. Please verify your ID.",
actionRequired: "DISPLAY_FORM_ERROR"
};
}
// 2. Validate Regulatory Status Gate
// Must be actively registered to use a digital prescription app
if (cqcApiResponse.registrationStatus !== "Registered") {
return {
status: "BLOCKED",
errorMessage: `Onboarding blocked. This practice current status is: '${cqcApiResponse.registrationStatus}'. Only actively registered clinics are allowed.`,
actionRequired: "TERMINATE_REGISTRATION"
};
}
// 3. Extract the Registered Manager details from the JSON array
const managers = cqcApiResponse.registeredManagers || [];
if (managers.length === 0) {
// Edge case: Clinic is active but currently has no registered manager assigned
return {
status: "MANUAL_REVIEW",
reason: "Clinic is registered but has no named CQC Registered Manager listed in the system.",
actionRequired: "ROUTE_TO_INTERNAL_COMPLIANCE_DESK"
};
}
// Combine user input names for a clean evaluation string
const inputFullName = `${userSubmittedData.firstName.trim()} ${userSubmittedData.lastName.trim()}`.toLowerCase();
// Check if the user matches ANY of the listed active managers (handles single or joint managers)
const matchingManager = managers.find(manager => {
const cqcFullName = `${manager.firstName.trim()} ${manager.lastName.trim()}`.toLowerCase();
return cqcFullName === inputFullName && manager.status === "Active";
});
// 4. Evaluate Identity Match
if (matchingManager) {
// SUCCESS PATH: Automated checks passed cleanly
return {
status: "APPROVED_AUTOMATED",
autofillData: {
clinicName: cqcApiResponse.locationName,
addressLine1: cqcApiResponse.postalAddressLine1,
city: cqcApiResponse.postalAddressTownCity,
postcode: cqcApiResponse.postalCode,
managerConfirmedName: `${matchingManager.firstName} ${matchingManager.lastName}`
},
actionRequired: "PROCEED_TO_SMS_MFA_SETUP"
};
} else {
// FALLBACK PATH: The clinic is real, but the person signing up doesn't match the CQC records
return {
status: "MANUAL_REVIEW",
reason: `Sign-up name '${inputFullName}' does not match official CQC Registered Manager records.`,
autofillData: {
clinicName: cqcApiResponse.locationName,
addressLine1: cqcApiResponse.postalAddressLine1,
city: cqcApiResponse.postalAddressTownCity,
postcode: cqcApiResponse.postalCode
},
actionRequired: "HOLD_ACCOUNT_AND_TRIGGER_MANUAL_ID_CHECK"
};
}
}
APPROVED_AUTOMATED triggers: Your frontend instantly unhides the form layout, populates the read-only clinic cards, and highlights a confirmation message saying: "Clinic verified. Welcome Dr/Mr/Ms [Name]." It then prompts them to enter their mobile number to send an activation token.MANUAL_REVIEW triggers: Instead of locking them completely out, the app should say: "We found your clinic, but your name doesn't match the official CQC registry. Please upload your proof of identity / CQC certificate so our onboarding team can manually approve your account within 24 hours." This keeps your sales pipeline moving instead of dropping legitimate users who may have recently changed names or taken over a practice.Would you like to explore how to convert this logic into a DSPT-compliant database logging schema so you can permanently record these checks for external healthcare inspectors, or should we map out the MFA validation step?
Sure, let's explore how to convert this logic into a DSPT-compliant database logging schema
To pass your Data Security and Protection Toolkit (DSPT) assessment, you must demonstrate accountability and auditability. Under the DSPT framework, a simple "Pass/Fail" flag in a user profile is not enough. You need to store an unalterable record showing exactly why a clinic was allowed into your prescription system.
If a clinic ever issues a fraudulent prescription, NHS or CQC auditors will require you to pull up the timestamped evidence of the checks you ran at the exact moment they registered.
To keep your primary Users and Clinics tables optimized, store the raw auditing records in a separate, secure ComplianceAuditLogs system.
┌───────────────┐ ┌───────────────────┐ ┌───────────────────────┐
│ clinics │ │ users │ │ compliance_audit_logs │
├───────────────┤ ├─────────────── ───┤ ├───────────────────────┤
│ id (PK) │◄──┐ │ id (PK) │◄──┐ │ id (PK) │
│ cqc_id │ └─── │ clinic_id (FK) │ └─── │ user_id (FK) │
└───────────────┘ └───────────────────┘ │ clinic_id (FK) │
│ raw_api_snapshot_json │
└───────────────────────┘
This relational structure captures the onboarding outcome, records the person responsible, and archives the raw data from the regulator.
-- Enums to enforce strict state control across your platform
CREATE TYPE onboarding_status_type AS ENUM ('APPROVED_AUTOMATED', 'MANUAL_REVIEW', 'BLOCKED');
CREATE TYPE verification_method_type AS ENUM ('CQC_API_AUTOMATED', 'INTERNAL_COMPLIANCE_TEAM');
CREATE TABLE compliance_audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Relationships (Foreign Keys)
clinic_id UUID NOT NULL REFERENCES clinics(id) ON DELETE RESTRICT,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
-- The core results of the onboarding execution
onboarding_status onboarding_status_type NOT NULL,
verification_method verification_method_type NOT NULL,
-- Inputs submitted by the client at registration
submitted_cqc_id VARCHAR(50) NOT NULL,
submitted_manager_name VARCHAR(255) NOT NULL,
submitted_ip_address INET NOT NULL,
-- System validation metrics
cqc_registration_status_at_source VARCHAR(50) NOT NULL, -- e.g., 'Registered'
expected_cqc_manager_name VARCHAR(255), -- e.g., 'Sarah Jenkins'
-- Human Audit Trail Fallback
reviewed_by_staff_id UUID REFERENCES platform_staff(id), -- NULL if 100% automated
manual_review_notes TEXT, -- Explaining why a human approved it
-- The Immutable Proof (Crucial for DSPT Evidence)
-- Stores the exact, raw JSON object returned by the CQC API
raw_api_snapshot_json JSONB NOT NULL,
-- Timestamps
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- Indexing for rapid audit searches (e.g., when a regulator requests a check)
CREATE INDEX idx_compliance_clinic ON compliance_audit_logs(clinic_id);
CREATE INDEX idx_compliance_status ON compliance_audit_logs(onboarding_status);
CREATE INDEX idx_compliance_created ON compliance_audit_logs(created_at);
When your processCqcOnboarding() logic executes, write a database transaction that saves the result immediately.
If a user registers perfectly, your backend automatically commits this log entry:
APPROVED_AUTOMATEDCQC_API_AUTOMATEDNULLIf a legitimate Practice Manager signs up but their name does not match the CQC register yet (e.g., they are new to the practice), your database captures the progression:
The app writes an initial log with onboarding_status = 'MANUAL_REVIEW'.
Your internal staff member verifies their employment via a phone call or business document.
The staff member clicks "Approve" in your admin portal.
The system writes a second entry tracking the override:
APPROVED_AUTOMATED (now upgraded to active)INTERNAL_COMPLIANCE_TEAMUUID_OF_YOUR_COMPLIANCE_EMPLOYEEWhen submitting your assertions to the Digital Security and Protection Toolkit portal, this database implementation satisfies several specific requirements:
JSONB data field, it provides an unalterable timeline of third-party external verifications.Would you like to examine how to handle the cryptographic signing key creation process right after this log entry is saved, or should we look at how to enforce strict Multi-Factor Authentication (MFA) at this stage?
We do already have encryption, but we will look into this to ensure the on-boarding process is complicit so please do provide some guidance on this
To guarantee your onboarding process is fully compliant with the Data Security and Protection Toolkit (DSPT), your encryption architecture must do more than just protect data at rest—it must securely bind a clinician's verified identity to their unique prescribing credentials.
Under the DSPT framework and UK eIDAS regulations for Advanced Electronic Signatures (AES), you must ensure that your system prevents data tampering and secures the cryptographic keys used for signing prescriptions. [1, 2]
Three critical technical domains must be implemented within your registration and signing pipeline to remain fully compliant.
While your app already uses encryption, the DSPT enforces strict rules regarding Data Minimisation and Separation of Concerns. [3, 4]
DSPT requires robust access controls to confirm that a registered user is the individual performing an action on the platform. [6, 7]
When the clinician signs a prescription, the application forces a dynamic cryptographic handshake via this local device biometrics check, proving non-repudiation directly to a DSPT assessor. [1]
To maintain an Advanced Electronic Signature (AES) setup, each prescriber must hold exclusive control over their unique signing credentials.
[ Clinician App ] ──( Triggers WebAuthn / FaceID )──► [ Generates Ephemeral Session Key ]
│
▼
[ Encrypted Enclave ] ◄──( Decrypts Private Key Natively )───────┘
│
▼
[ Cryptographically Signed Prescription Output ] (Immutable & Non-Repudiable)
When a clinic onboarding process completes, the system should generate a unique public/private keypair for the prescriber. The private key must immediately be encrypted with a key derived from the clinician's biometric login or hardware PIN. Your servers will only store the securely encrypted string, ensuring that your team never has direct access to a clinician's private signing key. [1, 6]
To prepare your platform's encryption workflow for a formal DSPT audit, confirm that your system architecture addresses the following points:
compliance_audit_logs secured with write-once, read-many policies, preventing anyone—including database administrators—from altering historical registration timelines? [3, 6, 7]If you are currently evaluating your infrastructure setup, let me know:
This will help tailor specific integration commands to align with your technology stack.
[2] https://www.esignglobal.com
[6] https://www.betterworldtechnology.com
Sure, but we don't need a cloud provider as we have our own vps - if necessary we can commission another vps as we have done for our backup
Operating on your own Virtual Private Server (VPS) infrastructure gives you complete control over your environment, which is highly advantageous for data sovereignty. However, hosting a platform that handles both medical prescriptions and Advanced Electronic Signatures (AES) on a custom VPS stack introduces specific responsibilities under the Data Security and Protection Toolkit (DSPT).
Because you do not use managed cloud compliance layers (like AWS KMS or Azure Key Vault), you must manually configure and prove the security of your servers to NHS auditors. Commissioning a dedicated VPS for security and compliance is an excellent approach to achieving this isolation.
Here is how to configure your VPS infrastructure to pass a DSPT assessment and secure your onboarding and signature pipeline.
To fulfill the DSPT requirement for minimizing data exposure, do not host your application frontend, main database, and compliance data on a single virtual machine. Use a dedicated VPS topology:
┌─────────────────────────────────────────┐
│ Public Web │
│ (App Frontend) │
└────────────────────┬────────────────────┘
│ (Reverse Proxy / HTTPS Only)
▼
┌─────────────────────────────────────────┐
│ Application Core │
│ (VPS No. 1) │
└────────────────────┬────────────────────┘
│ (Isolated Private Network)
▼
┌──────────────────────────────────┴──────────────────────────────────┐
│ │
▼ ▼
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
│ Main Database Cluster │ │ Compliance & Cryptography │
│ (VPS No. 2) │ │ Enclave (VPS No. 3) │
├──────────────────────────────────────┤ ├──────────────────────────────────────┤
│ Stores calendars, clinical notes, │ │ Stores raw CQC logs, identity videos,│
│ and encrypted user accounts. │ │ and performs signature checks. │
└──────────────────────────────────────┘ └──────────────────────────────────────┘
compliance_audit_logs table, raw CQC API JSON payloads, and handles the cryptographic processes for the advanced electronic signatures.Since you cannot use cloud-native key vaults, you must establish an open-source, enterprise-grade equivalent on your dedicated compliance VPS to handle system secrets.
When you complete your self-assessed DSPT submission, you must confirm that your self-managed server operating systems meet rigid defensive standards. Implement these server-level configurations across your VPS network:
5432 for PostgreSQL) to the open internet.ufw or iptables) on every machine, explicitly restricting incoming traffic to trusted, predefined server IP addresses.You mentioned having a dedicated VPS for backups, which aligns with basic data protection goals. To ensure your backup pipeline is fully compliant with DSPT resilience rules:
If you are preparing to configure these virtual machines, let me know:
This will help outline the precise command-line configurations needed to secure your environment.
we already have Docker containers - the OS is Linux
Since you are already using Docker containers on a Linux OS, you have a major advantage. ==Containerisation makes it significantly easier to enforce the strict isolation required by the Data Security and Protection Toolkit (DSPT) and Advanced Electronic Signature (AES) standards==.
Using Docker, you can achieve enterprise-grade security on your self-hosted VPS without needing expensive cloud tools.
To ensure your onboarding and verification data paths are fully compliant, implement this configuration on your VPS setup.
Under DSPT guidelines, your frontend application should never be on the same network broadcast domain as your compliance verification data or primary databases.
docker-compose.yml. Your verification backend can sit on both, but your frontend can never talk directly to your compliance database.networks:
frontend_net: # For public traffic and app core
secure_compliance_net: # Internal-only for CQC data, ID logs, and signing keys
services:
web_app:
image: clinic-frontend:latest
networks:
- frontend_net
compliance_engine:
image: clinic-compliance:latest
networks:
- frontend_net # To receive registration requests from web_app
- secure_compliance_net # To write to the compliance database
compliance_db:
image: postgres:16-alpine
networks:
- secure_compliance_net # Completely isolated from the frontend web_app
A common vulnerability in Docker deployments is storing sensitive encryption keys or API tokens (like your CQC credentials) directly in the environment: block or a generic .env file.
docker inspect on the VPS can view your production secrets in clear text, which will trigger a failure in a DSPT audit.chmod 400. Pass them into your containers at runtime like this:services:
compliance_engine:
image: clinic-compliance:latest
volumes:
- /etc/ssl/certs/signing_key.key:/run/secrets/signing_key.key:ro
Because your platform issues medical prescriptions, you must ensure that a vulnerability in your web application does not allow an attacker to escape the container and access the host VPS.
Drop Root Privileges: By default, Docker containers run as the root user. Modify your Dockerfile for the onboarding/compliance engine to use a non-root service account:
# Create a system user for compliance handling
RUN useradd -u 1001 complianceuser
USER complianceuser
Read-Only Root Filesystems: Prevent files from being altered or injected into your containers. Set the container's root file system to read-only, allocating a temporary, isolated memory space (tmpfs) solely for processing incoming CQC data payloads or liveness videos:
read_only: true
tmpfs:
- /tmp
DSPT requires you to prove you monitor your infrastructure for known vulnerabilities.
trivy image clinic-compliance:latest before every software update. It generates a clear text report showing that your Linux base OS patches and application packages are free from critical security flaws, providing excellent documentation for your DTAC assessment.To move forward with setting up your multi-VPS infrastructure, consider these priorities:
ufw or iptables) restricts your backup VPS so that it only accepts data coming from the specific static IP address of your primary database container.journald or a local rsyslog container) to safely route your onboarding compliance_audit_logs output directly to your secure backup server in real time.If you are ready to configure the system, let me know: