Features Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.
Goal: Revamp reception AI nudges with structured JSON context + lab/inventory/payment nudges + deep links; wire discount policies to treatment plan creation; add A4 landscape audit log PDF export; support separate light/dark clinic logos with PDFs always using the light variant.
Architecture: Extend existing appointment-nudges agent (not replace it), add schema columns via schema-ensure migration, reuse existing @react-pdf/renderer PDF pattern, add logo upload field to clinic settings.
Tech Stack: Hono, Drizzle ORM, Cloudflare Workers, React, @react-pdf/renderer, Langfuse API, Sonner
File Map
| File | Change |
|---|---|
server/src/lib/ai/agents/appointment-nudges.ts | Add lab/inventory queries, switch to JSON context, fix deep link overrides |
server/src/lib/ai/prompts.ts | Update appointmentNudges system prompt — new types, JSON input, deep link rule |
ui/src/components/appointments/AppointmentNudgesPanel.tsx | Add icons/badge colors for new nudge types |
server/src/lib/validation.ts | Add discountAmount + discountPolicyLabel to treatmentPlanCreateSchema |
server/src/schema/treatment_plans.ts | Add discountAmount + discountPolicyLabel fields |
server/src/lib/schema-ensure.ts | Add ALTER TABLE migrations for new TP columns |
server/src/routes/treatment-plans.ts | Pass through discount fields on create/update/select |
ui/src/components/doctor/TreatmentPlanning.tsx | Add discount policy picker, update total calculation |
server/src/routes/audit-logs.ts | Add GET /export endpoint returning PDF |
server/src/pdf/AuditLogPdf.tsx | New — A4 landscape PDF for audit log export |
server/src/schema/clinics.ts | Add logoDarkUrl + logoDarkR2Key fields |
server/src/lib/schema-ensure.ts | Add migrations for dark logo columns (combined with TP migration) |
server/src/routes/clinics.ts | Accept + store logoDarkUrl/logoDarkR2Key on update; include in GET responses |
ui/src/components/settings/ClinicProfileSettings.tsx | Add dark logo upload section |
ui/src/components/layout/AppLayout.tsx (or wherever clinic logo is displayed) | Use dark logo in dark mode with fallback |
Task 1: Reception AI Revamp
Files:- Modify:
server/src/lib/ai/agents/appointment-nudges.ts - Modify:
server/src/lib/ai/prompts.ts - Modify:
ui/src/components/appointments/AppointmentNudgesPanel.tsx
Background
The current nudge agent (generateAppointmentNudges) builds a plain-text context string and sends it to the LLM. The actionUrl is overridden server-side after the LLM responds — but only with two generic routes. The goal is:
- Switch to structured JSON context (LLM gets richer, typed data)
- Add 3 new data modules: lab cases (overdue/due-soon), inventory (low/expiring), and ensure overdue invoices already have per-patient invoice IDs for deep links
- Deep links: server-side override uses real entity IDs — single-item buckets get entity-specific URL; multi-item buckets get module URL
- Update Langfuse prompt to match new JSON input + new nudge types
New nudge types added to interface
- Step 1: Read appointment-nudges.ts fully
server/src/lib/ai/agents/appointment-nudges.ts in full (it’s ~560 lines). Note the exact shape of the existing Promise.all queries, the context string builder, and the URL override switch block.
- Step 2: Update
AppointmentNudgeinterface and add new query imports
appointment-nudges.ts, update the AppointmentNudge interface type field and add imports for labCases, inventoryItems, inventoryAlerts:
- Step 3: Add lab case and inventory queries to the Promise.all block
Promise.all([...]) block, add:
- Step 4: Switch context from string to JSON object
contextParts string builder with a structured JSON object. Keep all the existing data — just restructure it:
- Step 5: Update URL override block
- Step 6: Update Langfuse prompt in
prompts.ts
appointmentNudges in server/src/lib/ai/prompts.ts (line ~293) and replace with the updated prompt:
- Step 7: Push updated prompt to Langfuse
prompts.ts, push the new prompt to Langfuse. Read the full prompt string from server/src/lib/ai/prompts.ts appointmentNudges key, then run:
server/scripts/push-langfuse-prompts.ts (existing script) after adding the appointmentNudges prompt to its list.
Expected response: {"id": "...", "name": "appointment-nudges", ...} with HTTP 201.
- Step 8: Update
AppointmentNudgesPanel.tsxfor new nudge types
ui/src/components/appointments/AppointmentNudgesPanel.tsx. Find the switch/map that assigns colors or icons to nudge types. Add entries for the new types:
import { FlaskConical, Package, ClipboardList } from 'lucide-react';
- Step 9: Commit
Task 2: Discount Policies — Wire to Treatment Plans
Files:- Modify:
server/src/schema/treatment_plans.ts - Modify:
server/src/lib/schema-ensure.ts - Modify:
server/src/lib/validation.ts - Modify:
server/src/routes/treatment-plans.ts - Modify:
ui/src/components/doctor/TreatmentPlanning.tsx
Background
DiscountPoliciesSettings.tsx already saves discountPolicies (JSONB) to the clinic record via updateClinic. The schema column exists. The settings UI is complete. What’s missing:
- Treatment plan schema has no discount fields
- Treatment plan create form has no discount picker
- The calculated total doesn’t apply any discount
Data flow
- Admin configures discount policies in Settings
- When creating a treatment plan, doctor/receptionist selects a policy from the clinic’s active list
- The selected policy’s percentage is applied to
estimatedCostto compute the discounted total discountAmount(PKR) anddiscountPolicyLabel(e.g. “Senior Citizen”) are stored on the plan
- Step 1: Add fields to treatment plan schema
server/src/schema/treatment_plans.ts, add two fields after estimatedCost:
- Step 2: Add migration to schema-ensure.ts
server/src/lib/schema-ensure.ts, find the section with ALTER TABLE app.clinics ADD COLUMN IF NOT EXISTS discount_policies and add new migrations nearby:
- Step 3: Update validation schema
server/src/lib/validation.ts, find treatmentPlanCreateSchema (~line 191) and add:
- Step 4: Update treatment plans route
server/src/routes/treatment-plans.ts:
a) Add discountAmount and discountPolicyLabel to treatmentPlanColumns:
estimatedCost: planData.estimatedCost?.toString() is set and add:
- Step 5: Update
TreatmentPlanning.tsx— add discount policy picker
ui/src/components/doctor/TreatmentPlanning.tsx fully first.
Add to the form state:
useEffect or a new one), load the clinic’s discount policies:
calculateTotalCost()):
- Step 6: Commit
Task 3: Audit Log Export — A4 Landscape PDF
Files:- Create:
server/src/pdf/AuditLogPdf.tsx - Modify:
server/src/routes/audit-logs.ts
Background
The existing PDF infrastructure uses@react-pdf/renderer (see PatientInvoicePdf.tsx). Audit logs are queried via GET with filters. The export endpoint will accept the same filters, render a PDF, and return it as application/pdf.
- Step 1: Create
AuditLogPdf.tsx
- Step 2: Add export endpoint to
audit-logs.ts
server/src/routes/audit-logs.ts to see the existing imports and GET handler. Add a new GET /export route before export default auditLogsRoute:
- Step 3: Add export button to audit log UI
ui/src/components/admin/ or similar. Add an “Export PDF” button that hits the export endpoint:
<Button onClick={handleExportPdf}>Export PDF</Button> near the existing filter controls.
- Step 4: Commit
Task 4: Clinic Logo — Light/Dark Mode Support + PDFs Always Light
Files:- Modify:
server/src/schema/clinics.ts - Modify:
server/src/lib/schema-ensure.ts - Modify:
server/src/routes/clinics.ts - Modify:
ui/src/components/settings/ClinicProfileSettings.tsx(or equivalent logo upload component) - Modify: wherever clinic logo is displayed in the app UI
Background
Currently the clinic has onelogoUrl column. The user wants to upload a second logo for dark mode. PDFs always use the light (primary) logo. The UI should switch to the dark logo when dark mode is active, falling back to the light logo if no dark variant is uploaded.
- Step 1: Add dark logo columns to clinic schema
server/src/schema/clinics.ts, after logoR2Key, add:
- Step 2: Add migration
server/src/lib/schema-ensure.ts, add alongside the treatment plan migration:
- Step 3: Update clinic route
server/src/routes/clinics.ts:
a) In GET responses, include logoDarkUrl in selected columns.
b) In the PATCH (update) body type (~line 650), add:
healBrandingUrls() (~line 1145), add dark logo URL healing:
logo-dark):
- Step 4: Add dark logo upload to clinic settings UI
ui/src/components/settings/ClinicProfileSettings.tsx (or wherever logo upload lives). Add a second upload section:
handleDarkLogoUpload to upload to the dark logo endpoint (copy pattern from existing logo upload handler).
- Step 5: Use dark logo in app UI
logoUrl (light) — no change needed there.
- Step 6: Commit

