Lighthouse iScript (Pty) Ltd collects health data under POPIA for care delivery. Consultations are telehealth and not a substitute for emergency care.

PrivacyTerms
iScript

Platform Review & Changelog

Internal — last reviewed 2026-05-23

Honest Assessment — May 2026

May 2026 — EMR v2 shipped. The platform has matured significantly. The core patient loop (assessment → Paystack payment → Zoom confirmation → tiered reminders → join call) works end-to-end. The new integrated EMR (IScriptEMRPatientRecord) now hosts 17 clinical tool panels — SOAP, Vitals, Diagnosis+ICD10, EnhancedPrescription, LabRequest, Radiology, Referral, SickNote, Medicus Opus, ZoomDock, AI CDS, MedAid, Billing, Close Visit, Docs, Audit — all within a single unified workspace. Visit lifecycle (Open → Active → Closed) is enforced at the database level.

Genuinely working, end-to-end: Assessment engine (8 verticals), booking wizard with availability-aware slot picker, Paystack payment, finalisePaidAppointment (atomic invoice/receipt), doctor confirm/reject, Zoom meeting creation, ZoomDock in-EMR call, tiered reminder chain, patient prescriptions (via EnhancedPrescription), lab requests, visit lifecycle, Medicus Opus AI wizard.

2 real P0 gaps remaining: (1) No automated Paystack refund when a doctor declines — critical legal risk. (2) EMR BillingSection "Submit Billing" is still a setTimeout mock — doctor post-consult charges are silently lost.

MediKredit deferred: Excluded from this review cycle. Will be addressed separately as Path 5.

Overall Health

81%

Working

34

of 51 items

Partial

15

of 51 items

Fix Needed

2

of 51 items

Planned

0

of 51 items

Working

Clinical Assessment Engine (8 verticals)

All 8 assessments functional with AI analysis. Anonymous → user linking on login works via anonId in localStorage. Assessment drafts stored in per-vertical entities.

Partial

Account creation / login flow after assessment

CreateAccount page exists. linkAnonAssessmentToUser backend runs on dashboard load. Fragile: if user closes between assessment and login, GLP-1 anon_id is cleared but other vertical drafts may not be linked if the correct vertical entity is not queried.

Working

In-Dashboard Booking Wizard (5-step)

Vertical → Assessment → Doctor selection (with vertical keyword filter + fallback) → Date/Time → Payment (Paystack or PayFast gateway selector) all wired end-to-end.

Partial

Doctor calendar slot availability

DateTimePicker checks DoctorProfile.availability (synced from Google Calendar via syncDoctorCalendarAvailability). If availability is set, ONLY those slots show and days with no slots are greyed out. If NOT set, all 08:00–16:30 Mon-Fri slots show with a warning banner. Partial: Google Calendar sync exists but doctors must actively connect it to protect against double-booking.

Working

Paystack payment (primary gateway) — LIVE ✅

Paystack Inline.js integrated. initializePaystackTransaction + finalisePaidAppointment (idempotent). Webhook fallback via paystackWebhook. ZAR card, bank transfer, EFT. Reference stored on Appointment.

Partial

PayFast payment (secondary gateway)

PayFast checkout component exists and calls finalisePaidAppointment on success. Race condition risk: PayFast ITN webhook and frontend callback may collide. No deduplication on PayFast path. Consider removing now Paystack is live.

Working

Post-payment dashboard redirect & polling

?payment=ok&ref= redirect handled. Green banner shown. Auto-refresh polls every 3s until appointment appears (up to ~30s). postPaymentWarning localStorage fallback if finalisation fails silently.

Working

Patient Dashboard — Upcoming Appointments

AppointmentCard shows status, Join Now (unlocks 10 min before), Add to Calendar (Google/Outlook/.ics), PDF summary download, and doctor profile block. Rebook flow for declined appointments fully wired.

Partial

Patient Dashboard — Prescriptions tab

Prescriptions tab reads from the Prescription entity and renders download links. HOWEVER — the EMR EnhancedPrescription component does write to the Prescription entity, so prescriptions DO appear here for consults done through the new EMR. Old SimplePrescription path was PDF-only and did not save to entity.

Working

Patient Profile & Intake Form

PatientIntakeForm: SA ID Luhn validation, DoB auto-derived and locked, phone mandatory with red-border error, OSM Nominatim address autocomplete, AI allergy/medication suggestions. Accessible from both profile tab and EMR provider view.

Partial

Patient Medical Aid Tab

MedicalAidTab UI complete — shows scheme, number, plan, dependent code. MediKredit eligibility lookup is deferred (mTLS blocker). Currently displays saved data only with no live verification.

Working

Billing Tab — Invoices & Receipts

AccountsBillingTab shows invoices, receipts, and incomplete payment recovery. PDF links attached from finalisePaidAppointment. Invoice + Receipt entities populated atomically.

Partial

Assessment draft resume (Incomplete Assessments)

IncompleteAppointments fetches all 8 draft entity types. Resume passes draft into InDashboardBooking wizard starting at step 1. Edge case: if vertical field is missing on draft, step starts at 0.

Partial

Patient receives prescription / results after consult

Prescriptions entity is written by EnhancedPrescription. Patient-facing prescriptions tab reads it. However: no push notification or email to patient saying "your prescription is ready". Patient must check the tab themselves.

Partial

Post-consultation follow-up (7-day thread)

Booking confirmation email mentions "7-day follow-up message thread" as an included feature. The PatientCommunicationTab exists and shows communication logs, but there is no automated post-consult message sent to open a follow-up thread with the doctor.

Working

Doctor registration & role assignment

setDoctorRole backend function assigns role="doctor". ChooseRole page guides new users. DoctorProfile auto-created.

Working

Onboarding wizard (photo, bio, practice details)

OnboardingWizard 4-step modal: photo upload + AI enhance, AI bio writer, SA ID + phone, practice details. confetti on complete. Progress tracked via onboarding_step.

Partial

Independent Contractor Agreement signing

ContractorAgreementSigning renders full agreement text. E-signature supports drawn (canvas), typed name, and upload. Canvas-drawn signature stored as base64 URL — not legally DocuSign-grade. Signed PDF URL stored on DoctorProfile.

Working

Admin approval of doctor profile

approveDoctorProfile backend sets status="approved" + profile_complete=true. Admin has DoctorProfileEditor, approval toggle, and email notification. Doctor unlocks booking availability post-approval.

Working

Doctor public profile page

/doctors/:doctorId renders full profile, languages, specialties, bio, reviews, Google rating. Book Now button links to booking wizard pre-filtered to this doctor.

Partial

Google Calendar sync for availability

CalendarSyncManager + iScript Doctor Calendar OAuth connector + syncDoctorCalendarAvailability function all built. Syncs busy events to DoctorProfile.availability. DateTimePicker reads this. Gap: doctors must actively connect their calendar — no prompt to remind them.

Working

Doctor dashboard — Awaiting Consultations tab

AwaitingConsultationTab shows confirmed appointments grouped by date with date filters. AI clinical summary expand/collapse per patient, PDF download. "Start Consultation" opens CreateVisitModal. All wired.

Working

Doctor dashboard — EMR

Full IScriptEMRPatientRecord: 17 tool panels (SOAP, Vitals, Diagnosis+ICD10, EnhancedPrescription, LabRequest, Radiology, Referral, SickNote, Medicus Opus, AI Report, CDS, MedAid, Billing, Close Visit, Docs, Audit). VisitBanner and ZoomDock integrated.

Working

Visit lifecycle (Open → Close)

CreateVisitModal creates ClinicalRecord with visit_status=open. VisitBanner tracks status. updateVisitStatus backend enforces guards. VisitClosePanel handles close with reason. Read-only lock on closed visits.

Partial

Doctor notifications for new pending bookings

Confirmation email sent via finalisePaidAppointment. No in-app push notification or real-time subscription. Doctor must manually refresh to see new bookings in queue.

Partial

Doctor earnings / financial overview

DoctorDashboard Overview tab shows appointment stats and estimated earnings based on consultation fees. Not connected to actual Invoice/Receipt entities — uses appointment.consultation_fee × count as an estimate only.

Working

Appointment creation on payment

finalisePaidAppointment atomically creates: Appointment + ClinicalRecord + Invoice + Receipt. Idempotency guard via payment_reference lookup prevents duplicates. Paystack webhook as fallback path.

Working

Doctor confirm / reject workflow

doctorConfirmAppointment: confirm → Zoom meeting created → emails to both parties + WhatsApp. Reject → status=declined + patient email. Awaiting Consultation tab shows pending queue with Confirm/Decline actions.

Working

Zoom meeting auto-creation on doctor confirm

S2S Zoom OAuth, 20-min scheduled meeting, waiting room ON, cloud recording ON, Africa/Johannesburg timezone. Zoom credentials stored on both Appointment and ClinicalRecord.

Working

Patient joins Zoom via AppointmentCard

AppointmentCard Join Now button unlocks 10 min before. Uses teleconsult_link (zoom_join_url). Works on mobile. Calendar export (.ics, Google, Outlook) also available.

Working

Doctor starts Zoom call (ZoomDock in EMR)

VisitBanner "Start Zoom Call" button triggers createZoomMeetingForVisit (idempotent). ZoomDock renders as persistent bottom-right panel within EMR. Doctor never leaves the EMR to take the call.

Working

Appointment reminder chain (tiered)

sendAppointmentReminders: immediate confirmation, 8am day-before, 6am day-of, 1h before, 10min before. Flags on Appointment entity prevent double-sends. Scheduler automation runs every 5 min.

Partial

Zoom recording → transcript → clinical notes

zoomRecordingWebhook + generateTranscriptSummary built and deployed. Not end-to-end validated on a live consult. Zoom cloud recording must be enabled on the account and webhook URL registered in Zoom Developer Console.

Fix Needed

Automated refund on doctor cancellation

CRITICAL P0. When doctor declines/cancels, there is NO automated Paystack refund call. AppointmentCard shows refund_status UI (processed/pending/none) but nothing actually triggers the Paystack refunds API. Must be fixed before first live patient.

Partial

WhatsApp appointment automation

appointmentWhatsappAutomation sends WhatsApp on confirmation, reminders, and cancellation. whatsappSend backend calls Meta API. In-app patient-doctor messaging thread not linked to the appointment confirmation flow.

Partial

Zoom host start_url regeneration

zoom_start_url saved on Appointment/ClinicalRecord. Time-limited (~24-48h). No UI button to regenerate fresh host URL if it expires before the consult. createZoomMeetingForVisit is idempotent — already returns existing meeting data. Doctor could use VisitBanner to re-trigger on the day.

Working

Visit lifecycle management (Open/Close/Lock)

CreateVisitModal opens ClinicalRecord with visit_status=open. VisitBanner tracks state. updateVisitStatus backend enforces: no edits to closed visits, only assigned doctor can update, close_reason required.

Working

Patient profile & problem list in EMR

EMR shows PatientProfile with allergies/medications/chronic conditions. AllergyAlertBanner + MedicationBanner shown at top of profile AND at prescription point. ProblemListPanel, PatientIntakeForm, PatientTimeline all accessible as tabs.

Working

AI pre-consultation report (from assessment)

ClinicalReportCompact renders likely diagnoses, risk flags, urgency level, recommended investigations from ClinicalRecord.ai_analysis.

Working

Medicus Opus wizard (AI clinical workflow)

Full MedicusOpusWizard integrated as EMR panel. History → Diagnosis → Management → Education → Billing. Auto-save via debounced saveToVisit(). read-only when visit is closed. Runs medicusOpusDiagnosis, medicusOpusPrescriptionValidator, medicusOpusBillingCoding backend functions.

Working

SOAP notes (structured, AI-assisted)

SOAP tab with 8 vertical-specific prompt templates. AI assist buttons (Generate SOAP, Suggest Diagnosis, Draft Plan) via Claude Sonnet. Notes saved to ClinicalRecord.

Working

Vitals panel

VitalSignsPanel is a fully wired EMR tab — BP, HR, Temp, SpO2, RR, Weight, Height, BMI, Blood Glucose. Trend graph across past visits. Writes to ClinicalRecord vitals fields.

Working

Diagnosis + ICD-10 autocomplete

ICD10Autocomplete rendered in EMR Diagnosis tab. AI diagnosis recommender with AIDiagnosisRecommender + confidence badge + audit trail for doctor override. AIAuditTrail records AI-generated vs doctor-accepted diagnoses.

Working

E-Prescription (EnhancedPrescription)

EnhancedPrescription writes to Prescription entity with patient/doctor snapshots, medications, ICD10, PDF. AllergyAlertBanner shown at prescribing point. dispatchPrescription backend function for pharmacy dispatch.

Working

Lab request (LabRequestModule)

LabRequestModule is a wired EMR tab — writes to LabRequest entity, sends via sendLabRequest backend. AmpathOrderPanel available for Ampath e-lab orders (sandbox-tested).

Working

Radiology / Imaging requests

RadiologyRequestModule is a wired EMR tab — generates radiology request with modality, body part, clinical indication. AI-suggested imaging based on diagnosis. PDF export.

Working

Referral letter & sick note

ReferralLetterGenerator + SickNoteGenerator both surfaced as EMR tabs. AI-generated content, doctor letterhead, PDF export. Both write to relevant entities.

Working

Clinical decision support (CDS)

ClinicalDecisionSupport tab uses full patient context + SOAP + vertical to suggest diagnoses, red flags, contraindications, prescriptions via Claude Sonnet. CriticalValueAlert for abnormal vitals.

Fix Needed

Post-consultation billing (BillingSection)

P0. BillingSection "Submit Billing" still uses a setTimeout mock — does NOT write to Invoice entity or call any backend. Doctor post-consult charges are lost. Must wire to submitConsultationBilling backend before go-live.

Working

POPIA consent & audit trail

AuditTrail tab in EMR. auditLog backend called on SOAP save. POPIAConsentModal on appointment creation. Consent snapshot stored on Appointment entity.

Working

Document manager (EMRDocumentManager)

Documents tab in EMR. managePatientDocuments backend for upload/list/delete. Supports attachments + lab results array on ClinicalRecord.