Prescriptions Module Redesign
Date: 2026-04-25Status: Approved
Overview
Four improvements to the prescriptions module:- Dedicated medication catalog (seeded with Pakistan drugs + clinic-extensible)
- 3-step wizard modal UI (replacing the current flat form)
- Signature Center integration (signature ID saved on prescription record)
- Clinic letterhead DOCX template support → PDF export
1. Database Changes
New: medications table
- System drugs (
clinic_id IS NULL) visible to all clinics - Clinic custom drugs visible only to that clinic
- Clinics can add, but not edit or delete system drugs
Updated: prescriptions table
Updated: prescription_items table
Updated: clinics table
2. Medication Catalog — Routes
{ id, name, genericName, category, dosageForms, commonDosages, commonFrequencies, isSystem }.
Search implementation: name ILIKE '%q%' OR generic_name ILIKE '%q%' — simple substring match, sufficient for a ~500 row table.
Clinic-scoped: queries always filter clinic_id IS NULL OR clinic_id = req.clinicId.
3. Prescription Wizard UI
Replaces the current flat dialog with a 3-step modal using the existingcustom-modal.tsx + Radix UI components + Tailwind, consistent with the rest of the app.
Step 1 — Patient & Details
Fields:- Patient — pre-filled if opened from patient profile, otherwise searchable select
- Doctor — defaults to logged-in user, selectable from clinic staff
- Date — defaults to today
- Status — Active / Completed / Cancelled
- Diagnosis — textarea
- Notes — textarea
Step 2 — Medications
- Drug search input — queries
GET /medications?q=with debounce (300ms). Autocomplete dropdown shows: name, generic name, category badge, dosage forms. - “Add as custom drug” option at bottom of dropdown if no exact match — opens inline mini-form to add the drug to clinic catalog and immediately add it to the prescription.
- Medication card (once added): name + category badge, four compact inputs — Dosage (text with suggestions from
commonDosages), Frequency (select with suggestions fromcommonFrequencies: OD/BD/TDS/QID/SOS/Custom), Duration (text, e.g. “5 days”), Qty (number), Instructions (optional text). Card is collapsible. Remove button. - Multiple medications supported; list grows below.
Step 3 — Sign & Export
- Signature block — fetches
GET /signatures/activefor the prescribing doctor’s role. Shows signature image preview, upload date. “Change” link opens signature selector (existing Signature Center UI). SelectedsignatureIdstored in wizard state. - Template toggle — two options: “Clinic Letterhead” (shown only if
prescriptionImageKeyexists on clinic) and “Default Template”. Defaults to letterhead if available. - Summary strip — patient name, medication count, Rx number (generated on save).
- Actions:
- Save — saves prescription with
status: active, no PDF export - Save & Export PDF — saves then triggers PDF download
- Save — saves prescription with
Note: there is no separate draft status in the schema. “Save” creates an active prescription without exporting.
4. DOCX Template — Upload & Storage
Upload flow (one-time, in Clinic Settings)
- Clinic admin uploads
.docxfile via settings page (new “Prescription Template” card in Clinic Settings). - Server receives file, validates it is a valid DOCX (check magic bytes / content-type).
- Store raw DOCX in R2 under key
clinics/{clinicId}/prescription-template.docx. - Convert DOCX → PNG:
- Use
mammoth.jsto extract DOCX → HTML string. - Invoke a lightweight rendering step: POST the HTML to a dedicated Cloudflare Worker that uses
@cloudflare/puppeteer(Browser Rendering API) to screenshot at A4 dimensions (794×1123px @96dpi), returning a PNG buffer. Requires Cloudflare Workers Paid plan (Browser Rendering API is not on Free tier). - Store PNG in R2 under key
clinics/{clinicId}/prescription-template.png.
- Use
- Update
prescription_image_keyandprescription_docx_keyon the clinic record. - Return a signed R2 URL for the PNG so the settings page can show a preview.
Template routes
DOCX content guidance (documented for clinics)
The DOCX should have the clinic’s letterhead in the header and footer. The body area should be left blank or contain a placeholder line{{PRESCRIPTION_CONTENT}} — this is where the prescription content will be visually overlaid. No programmatic DOCX manipulation at export time; the PNG is used as a background layer.
5. PDF Generation — Updated Pipeline
With clinic letterhead (template_type = 'letterhead')
- Fetch letterhead PNG from R2 (cached in memory for the request).
- In
@react-pdf/renderer, render an A4<Page>with:<Image src={letterheadPng} style={{ position:'absolute', top:0, left:0, width:'100%', height:'100%' }} />— full-page background.- Content zone: absolute positioned block, top: 180pt, left: 60pt, right: 60pt, bottom: 120pt (leaves room for letterhead header/footer — these are sensible defaults for A4 letterheads; clinics with unusual layouts may need adjustment). Contains:
- Rx number + date (top right)
- Patient name + DOB
- Diagnosis
- Medications table (name, dosage, frequency, duration, qty, instructions)
- Notes
- Signature zone: bottom right of content area — doctor name + signature image.
- Export as PDF, trigger download.
Without letterhead (template_type = 'default')
Existing PrescriptionPdf.tsx template unchanged, continues to work as-is.
6. Module Constant Update
Addmedications as a route within the prescriptions module. No new module needed — medication catalog is a sub-feature of the existing prescriptions module (already Pro tier).
7. Clinic Settings UI Addition
New card in Clinic Settings (under a “Prescriptions” section):- Prescription Template — “Upload your clinic’s letterhead (DOCX)” with a drag-and-drop zone.
- Shows PNG preview thumbnail if template is uploaded.
- “Remove” button to delete the template.
8. Error Handling & Edge Cases
- If signature is not set up: Step 3 shows a warning banner “No active signature found — export will have no signature” with a link to Signature Center. Export still allowed.
- If DOCX → PNG conversion fails: show error in settings, keep clinic on default template. Retry allowed.
prescription_items.medication_idis nullable — old prescriptions with free-text medication names remain valid and render correctly.- Deleting a system medication is blocked at API level (403). Deleting a clinic medication that is referenced in existing prescription items is soft-blocked with a warning.
9. Out of Scope
- Drug interaction checks
- Prescription refill tracking
- Per-doctor letterhead templates (clinic-level only)
- Expiration dates on prescriptions
- External formulary API integration

