Delivered remotely for a business based in Doha, Qatar. Names withheld by agreement.
Project Overview
Industry: Healthcare — remote and virtual care delivery.
Type of solution: A server-rendered web platform with two distinct audiences: a patient-facing booking and consultation journey, and an administrative back office for the care provider. Delivered as a progressive web application rather than native mobile apps.
Business context: A care provider wanting to offer remote consultations has to solve several unglamorous problems before the first video call can happen. Patients need to be triaged before clinical time is committed. Prior records — scans, reports, letters — arrive by email, which is neither private nor organised. Availability has to be offered without someone re-keying a diary. The consultation itself has to happen without asking a patient to install software or sign up with a video vendor. Payment has to be taken. And at the moment the visit starts, the clinician needs the intake answers, the documents and the meeting link in one place, not in three inboxes.
General users: Patients booking and attending consultations, and administrative and clinical staff who manage patients, appointments, intake content and the consultations themselves.
General purpose: To turn a remote consultation from a chain of emails, phone calls and separate vendor links into a single guided flow that ends with a clinician and a patient in a video call, with the clinical context already in front of them.
The Business Challenge
Patient information is scattered before it is ever clinical. Symptoms come in a phone call, documents come by email, availability comes from a diary and payment comes separately. Each handoff is a place where information is lost or exposed.
Medical documents cannot be handled casually. Uploaded scans and reports need to be private by default, visible to the right patient and the right clinician, and never sitting on an application server or behind a guessable public link.
Triage has to happen before clinical time is spent. A structured intake questionnaire is the cheapest way to do that — but the questions change as the practice learns, and a clinical team cannot be waiting on a software release to change them.
Patients will not install anything. The moment a remote consultation requires a download, an account with a third-party video vendor, or a passcode typed from an email, a proportion of patients simply do not attend.
The consultation experience has to feel like one product. Scheduling and video are best delegated to specialist providers, but the patient must not feel handed off between three different websites.
Appointment times have to be right, every time. Slot times move between the scheduling provider's representation and the clinic's local time, across daylight-saving boundaries. In most software an off-by-one-hour bug is an annoyance; here it is a missed consultation.
Everything the platform touches is sensitive. Intake answers, uploaded documents, identity, appointment records and notification messages are all protected health information, and every boundary the data crosses has to be a deliberate decision.
Our Approach
Model the whole journey, not the video call. We built the product as one continuous flow — intake, documents, scheduling, payment, consultation, record — because the value is in the sequence being unbroken, not in any single step.
Keep medical documents off the application server. Patient uploads are written directly to private cloud object storage. Nothing is publicly addressable. When a document needs to be viewed, the platform generates a short-lived signed link scoped to that single object, which expires shortly after it is issued. Orphaned uploads from an abandoned intake are cleaned up automatically rather than accumulating.
Make the clinical questionnaire data, not code. Question text, question type, answer options and ordering all live in the database with a drag-to-reorder administrative interface. The patient-facing flow is generated from that data, so the clinical team can change intake without a deployment.
Present intake one question at a time, and make it resumable. Answers are preserved as the patient moves forward and back through the sequence, and only become part of the immutable appointment record at the point of booking.
Delegate scheduling and video, but keep the frame. Both are specialist problems with mature hosted providers, and neither is where a care provider's software budget should go. Both are embedded inside the platform's own pages so the patient never appears to leave the product — the scheduling widget in the booking step, the video meeting in a dedicated consultation screen.
Separate the two audiences at the authentication layer. Rather than layering roles on a single session, the platform runs distinct authentication guards for the patient journey and the administrative back office, each with its own middleware and its own controller tree. The audience boundary is structural, not conditional.
Declare every third-party embed explicitly. Running two third-party front ends inside your own pages under a Content Security Policy needs care. We wrote a policy class with a method per integration, so every allowance a vendor requires is declared in one reviewable place with nonce-based handling for inline scripts, rather than accumulating as an opaque header nobody wants to touch.
Handle time explicitly. Appointment times are converted at the model boundary with daylight-saving transitions handled deliberately, so every screen and every message shows the same time.
Ship as a progressive web app. The core interaction is a video call in a browser. Native apps would have added two review cycles and an install step to a product whose main advantage is that there is nothing to install.
The Solution
Guided clinical intake. A sequential, one-question-per-screen questionnaire supporting single-choice, multiple-choice and free-text questions, with answers preserved across navigation and attached permanently to the resulting appointment.
Administrator-managed questionnaire content. Questions, answer options, question type, active state and display order are all editable from the back office, with drag-to-reorder, so clinical intake evolves without engineering involvement.
Private document upload. Patients attach scans, reports and letters, which go directly to private cloud object storage. Files can be renamed or removed before submission, and are read back only through short-lived signed links generated at view time.
Appointment scheduling. Slot selection through an embedded hosted scheduling widget, with the resulting appointment written into the platform's own record and cancellation propagated back to the provider when a patient cancels.
Payment and consultation credits. Card payment through a hosted payment provider, alongside redemption of pre-purchased consultation credits held against the patient's account.
In-browser video consultation. A meeting is created programmatically at booking time and joined through an embedded meeting SDK inside the platform's own pages, so neither patient nor clinician installs anything or signs in with a video vendor.
Appointment lifecycle tracking. Appointments move through scheduled, cancelled, in-progress and completed states, driven by real meeting entry and exit rather than manual status updates.
Consultation context in one place. When a clinician opens a consultation, the patient's intake answers and uploaded documents are on the same screen as the meeting.
Patient account area. Upcoming and past appointments, each with its intake answers and documents, plus self-service email change, password change, password recovery and cancellation.
Notifications. SMS and email confirmations at booking, and onward notification when a patient cancels, so the practice is not relying on someone noticing a calendar change.
Administrative back office. Patient directory with per-patient appointment history, an appointment register split into upcoming and past, questionnaire management, CMS pages for terms and privacy content, branding and service settings, administrative user management, and application log inspection.
Progressive web app delivery. Installable, with an offline fallback page, and no app store dependency.
Key Features
Data-driven clinical intake questionnaire Question text, type, options, ordering and active state are administrative data, so the patient-facing triage flow changes without a code release.
Resumable multi-step intake One question per screen with answers preserved across forward and back navigation, committed to the appointment record only at booking.
Private medical document handling Uploads written directly to private cloud object storage, never publicly addressable, served through short-lived signed links generated per view, with automatic clean-up of abandoned uploads.
Embedded scheduling with propagated cancellation Slot selection through a hosted scheduling widget inside the platform's own page, with patient-initiated cancellation pushed back to the provider and reflected in the platform's records.
In-platform video consultation Meetings created server-side at booking and joined through an embedded browser SDK, so patients attend without installing software or holding an account with a video vendor.
Consultation context at the point of care Intake answers and uploaded documents presented alongside the consultation itself, rather than retrieved from separate systems before a visit.
Dual payment paths Card payment through a hosted payment provider, or redemption of pre-purchased consultation credits held on the patient account.
Separated patient and administrative authentication Two distinct authentication guards with their own middleware and controller trees, making the audience boundary structural rather than conditional.
Per-integration Content Security Policy A bespoke policy class declaring each third-party embed's requirements in one reviewable place, with nonce-based inline script handling.
Progressive web app delivery Installable web delivery with an offline fallback, avoiding an install step in a product whose advantage is that there is nothing to install.
Technical Architecture
Presentation layer. Server-rendered templates with two distinct themes — a patient theme and an administrative theme — injected by shared base controllers, over a component-based CSS framework with a build pipeline for stylesheets and scripts. Progressive web app manifest, service worker and offline page sit alongside.
Application layer. A framework monolith with controllers partitioned into patient, administrative and authentication trees over shared base controllers, a global helper layer for cross-cutting functions, and per-audience middleware guarding each route group.
Authentication layer. Two session guards over a shared user store, separated by role and enforced by distinct middleware, with password hashing, login attempt throttling, cross-site request forgery protection and encrypted, host-scoped session cookies.
Data layer. A relational database holding patients, appointments with their intake answers, uploaded document references, questionnaire definitions, content pages and platform settings, with indexes and referential constraints added as the schema matured, soft deletes on content entities, and model-level caching on the reference data read on nearly every request.
Storage layer. Patient documents held in private cloud object storage, never on the application tier, with time-limited pre-signed URLs generated at view time as the only read path.
Integration layer. A hosted scheduling provider embedded as an iframe and called over REST for cancellation; a hosted meeting provider with server-side meeting creation and a browser SDK for attendance; a hosted payment provider; an SMS provider; and SMTP email.
Policy layer. A bespoke Content Security Policy class with a method per integration and nonce-based inline script allowance, applied globally.
Delivery layer. Deployment as code — migration, cache clearing, dependency installation, process restart and permission normalisation defined as tasks and invoked from a hosted continuous integration pipeline against a staged environment. Static analysis and dependency vulnerability scanning are available in the development toolchain.
Flow: Patient (progressive web app) → Guided intake → Private document upload to cloud object storage → Embedded scheduling provider → Payment or credit redemption → Appointment record + programmatic meeting creation → SMS and email confirmation → In-platform video consultation with intake and documents on screen → Administrative back office
Technology Stack
| Category | Technology |
|---|---|
| Backend language | PHP |
| Backend framework | Laravel |
| Templating | Blade server-rendered views |
| Database | MySQL with Doctrine DBAL and migration-managed schema |
| Authentication | Dual session guards with per-audience middleware; OAuth2 and token packages configured |
| Query caching | Model-level caching on reference data |
| Document storage | AWS S3 via Flysystem, private objects with time-limited pre-signed URLs |
| Payments | Stripe |
| SMS notification | Twilio |
| Email delivery | SMTP transactional mail |
| Scheduling | Hosted appointment scheduling provider (embedded widget plus REST API) |
| Video consultation | Hosted meeting provider (server-side creation plus browser Web SDK) |
| Security headers | Content Security Policy with a bespoke per-integration policy class and nonce generation |
| Web delivery | Progressive Web App with manifest, service worker and offline page |
| Admin UI | Data tables, form helpers and a component-based CSS framework |
| Frontend build | Webpack-based asset pipeline with Sass and HTTP client library |
| Operations | Application log inspection, static analysis and dependency vulnerability scanning |
| Deployment | Deployment-as-code tasks driven from a hosted CI pipeline |
Technical Challenges & Solutions
| Challenge | Our Approach |
|---|---|
| Medical documents that must be private but viewable by the right people | Uploads written directly to private cloud object storage, never to the application tier and never publicly addressable. Read access is granted only through short-lived pre-signed links generated at view time and scoped to a single object, with abandoned uploads cleaned up automatically rather than left behind. |
| Clinical intake that has to change without a software release | The questionnaire is data: question text, type, answer options, active state and display order all live in the database with a drag-to-reorder administrative interface, and the patient-facing flow is generated from it. |
| A multi-step intake that must survive back-navigation and restarts | Answers are preserved as the patient moves through the sequence and only become part of the immutable appointment record at the point of booking, so a patient can revise earlier answers without losing progress or corrupting a submitted record. |
| Two third-party front ends running inside policy-restricted pages | A bespoke Content Security Policy class with a method per integration, declaring each vendor's required allowances in one reviewable place with nonce-based inline script handling, rather than accumulating an opaque header over time. |
| Patients who will not install software to attend a consultation | Meetings created server-side at booking time and joined through an embedded browser SDK inside the platform's own pages, so attendance requires no download, no vendor account and no passcode typed from an email. |
| Appointment times crossing representations and daylight-saving boundaries | Conversion handled explicitly at the model boundary with daylight-saving transitions treated as a case rather than an assumption, so every screen and every notification shows the same time. |
| Two distinct audiences on one platform with very different data access | Separate authentication guards with their own middleware and controller trees, making the boundary between the patient journey and the administrative back office structural rather than a conditional inside shared code. |
| Reference data read on nearly every request | Model-level caching on the questionnaire, content and settings data — read constantly, changed rarely — keeping repeated reads off the database on the hot path. |
| Deployment of a healthcare product without manual server steps | Migration, cache clearing, dependency installation, process restart and permission normalisation defined as deployment tasks and invoked from a continuous integration pipeline, so a release is reproducible rather than remembered. |
Security & Reliability
Audience separation at the authentication layer. Patient and administrative sessions run on distinct guards with distinct middleware and distinct controller trees, so the two audiences are separated structurally rather than by conditionals in shared code.
Private-by-default document storage. Patient-uploaded medical documents are never publicly addressable and never stored on the application tier. The only read path is a pre-signed link that is generated at view time, scoped to a single object, and expires within minutes of being issued.
Credential handling. Passwords are hashed, login attempts are throttled below the framework default, and password recovery, email change and password change flows all require the account's current credentials or a mailed recovery step.
Browser-side hardening. A Content Security Policy is applied with nonce-based handling for inline scripts, and each third-party embed's allowances are declared explicitly in a dedicated policy class rather than accumulating implicitly. Cross-site request forgery protection, encrypted cookies, HTTP-only cookies and secure, host-scoped session cookie configuration are all in place.
Data retention. Content entities use soft deletes, so administrative removal is reversible rather than destructive, and appointment records retain their intake answers and document associations for later reference.
Referential integrity. Indexes and foreign key constraints were added to the appointment and document tables as the schema matured, keeping the link between a patient, their appointment and their documents enforced by the database.
Operational visibility. Application log inspection is available to administrators, and static analysis and dependency vulnerability scanning are wired into the development toolchain so known-vulnerable dependencies surface during development rather than in production.
Delegated specialist infrastructure. Video and scheduling run on established hosted providers rather than self-operated infrastructure, so their reliability, patching and scaling are handled by teams that do only that.
Scalability & Performance
Reference data cached at the model layer. The questionnaire, content pages and platform settings are read on nearly every request and change rarely — the textbook case for caching, and it keeps the constant reads off the database.
Binary data off the application tier. Medical documents go straight to cloud object storage and are delivered directly from it rather than proxied through the application, so document size and volume never consume application memory or bandwidth.
Specialist workloads delegated. Video consultation and scheduling availability are handled entirely by hosted providers, so the two most resource-intensive parts of the product scale independently of the platform.
Indexed access paths. Indexes and referential constraints on the appointment and document relationships keep the queries behind the patient account view and the administrative register on indexed paths.
Stateless-friendly design. With documents externalised and session and cache drivers configurable, the application tier is positioned to move to shared session and cache backing when the practice's volume warrants it.
Progressive web app delivery. A service worker and offline page mean repeat visits are served from cache, and the product remains installable without the weight of a native application.
Business Outcomes
- A remote consultation is now one continuous flow, from intake through to the video call, rather than a chain of emails, phone calls and separate vendor links.
- Clinical context is present at the point of care, with intake answers and uploaded documents on the same screen as the consultation.
- Triage happens before clinical time is committed, through a structured questionnaire completed as part of booking.
- Intake content is owned by the practice, not the release cycle, because questions, options and ordering are administrative data.
- Medical documents are handled privately by design, held in private storage and released only through short-lived, single-object links.
- Patients attend without installing anything, because the consultation runs inside the platform's own pages in a browser.
- The practice has a single administrative view of patients, appointments and consultation history, replacing diary entries and inboxes.
- Scheduling and video reliability are not the practice's problem, having been delegated to established hosted providers.
Why it worked
Healthcare software is judged differently. A marketplace with a rough edge loses a sale; a consultation platform with a rough edge means a patient does not attend, or a document ends up somewhere it should not be. The constraints are not features you add at the end — they shape where data is allowed to live from the first design decision.
Our team builds with that in mind. We kept patient documents off the application tier entirely and made expiring, single-object links the only way to read them, because the storage decision is the one you cannot retrofit. We made the clinical questionnaire data rather than code, because a practice that has to file a change request to reword a triage question will stop using the questionnaire. We separated the patient and administrative audiences at the authentication layer rather than with conditionals, because that boundary is the one that matters most and it should be visible in the structure of the codebase. And we declared every third-party embed's requirements explicitly in a policy class, because running other people's front ends inside your own pages is exactly where security policy quietly erodes.
We also know which problems not to solve. Availability management and real-time video are mature, well-served categories, and a care provider's budget is better spent on the journey around them than on rebuilding them. Our teams work across Laravel and modern PHP, secure file handling and cloud storage, third-party integration under strict browser security policy, payment and messaging providers, and deployment automation — with the judgement to know which parts of a regulated workflow have to be modelled faithfully and which should be delegated.
Final Summary
Offering remote consultations sounds like a video problem. It is not. The video call is the easy part — the hard part is everything that has to be true before it starts: the patient triaged, their records collected privately, a slot chosen against real availability, payment taken, the clinician holding the clinical context, and the whole thing happening without asking a patient to install software or hold an account with a vendor they have never heard of.
Our team built a telehealth platform that treats that whole sequence as the product. Patients complete a guided, administrator-configurable clinical intake questionnaire one question at a time, attach scans and reports that go straight into private cloud storage, choose an appointment through an embedded scheduling widget, and pay by card or by redeeming a pre-purchased consultation credit. A meeting is created programmatically at booking, confirmations go out by SMS and email, and when the time comes both parties join a video consultation inside the platform's own pages — with the intake answers and uploaded documents on screen alongside it.
Underneath sit the decisions that matter in a healthcare product. Documents never touch the application server and are readable only through short-lived links scoped to a single object. The patient and administrative audiences are separated at the authentication layer, not by conditionals. Every third-party embed's browser requirements are declared explicitly in one reviewable policy. Appointment times are converted deliberately, daylight saving included, because an hour's error here is a missed consultation. And the specialist problems — availability and real-time video — are delegated to providers who do nothing else, so the engineering effort went where it was actually needed: into the journey that makes a remote consultation work.