- Claims & Payments: save npiProviderId when submitting MH claim; sync between claim and payment on update
- Claims table: add Provider column showing rendering provider name
- Payments table: add Provider column + purple Commissioned badge on status
- Claim edit modal: add Rendering Provider dropdown (defaults to Mary Scannell)
- Payment edit modal: add Rendering Provider dropdown + Commissioned metadata display
- Reports page: add Provider filter dropdown (dynamic from NPI providers settings)
- Reports page: remove Collections by Doctor report type and Select Doctor dropdown
- Commission section: new section in reports page with date range + provider filter, shows eligible paid claims/payments per provider, multi-select checkboxes, Pay Commission modal with print + save, marks payments as commissioned so they are excluded from future cycles
- DB: add CommissionBatch and CommissionBatchItem tables; backfill Payment.npiProviderId from linked claims
- Backend: PATCH /api/payments/:id/provider syncs to linked claim; PUT /api/claims/:id syncs to linked payment; new /api/commissions routes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 3-message intro (self-intro → empathetic ack → new/existing question) via single TwiML response to guarantee delivery order
- Detect reschedule intent from first message; look up existing appointment date
- New patient flow: ask insurance type → MassHealth consent → member ID + DOB → Selenium eligibility check
- Post-eligibility: active → ask appointment date/time with office-hours validation; inactive → ask other insurance or collect contact info
- Date/time collection mirrors reschedule flow: check office day open, ask time, validate against office hours
- Auto-create appointment in schedule for known patients on confirmation; use first available staff member
- Add openPhoneReply toggle (Settings → AI Chat) to respond to any number at any time
- Add 5-minute inactivity timeout: reset conversation to initial stage and clear pending state
- Normalize MassHealth DOB to zero-padded MM/DD/YYYY before Selenium submission
- Expand isExistingPatient classifier to recognize "old patient", "old", "previous", "prior"
- Existing patient confirmation message now acknowledges patient type before asking about insurance
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add streetAddress/city/state/zipCode fields to OfficeContact (schema + storage + UI)
- Support {officeAddress} variable in batch reminder SMS
- Replace single SMS template field with full CRUD template list (add/rename/edit/delete)
- Store SMS template list under _sms_template_list; first template synced to batch reminder
- Hardcode all AI chat template defaults into codebase (reminder SMS, greetings, fallback)
- Add seed-templates.ts that auto-seeds default templates for all users on server boot
- Update README: note that templates are auto-configured on first boot
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add movedByAi boolean column to Appointment table (default false)
- reschedule-graph: set movedByAi=true when AI moves an appointment
- PATCH /api/appointments/:id/confirm endpoint clears the movedByAi flag
- Schedule grid: show teal AI badge on appointment cards where movedByAi=true
- Right-click context menu: 'Manually Confirmed' removes the AI badge via the confirm endpoint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace in-memory Maps in aiHandoffStore with DB-backed async functions
using new patient_conversation table (stage + aiHandoff per patient)
- Add afterHoursEnabled to ai_settings table (persists across restarts)
- Fix runtime crash in reschedule-graph: mon/tue/wed variables were out
of scope in the next-week fallback branch (ReferenceError)
- Wire rescheduleGreeting and generalFallback chat templates through to
LangGraph nodes so user-configured messages take effect
- Add otherNode to reminder-graph to handle unclassified patient replies
(e.g. "I want another appointment") and route to booking flow
- Fetch chatTemplates once per webhook request instead of per stage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add floating chat window Hand-off to AI toggle (per-patient) and after-hours AI toggle (global)
- Add LangGraph-powered appointment reminder flow: AI introduces itself, classifies YES/NO, handles confirmation with appointment date/time
- Add multi-step rescheduling flow: ASAP vs next week, tomorrow offer, Mon/Tue/Wed picker, morning/afternoon time slot — automatically updates appointment in DB
- Add new patient / after-hours flow: new vs existing patient, dental insurance check, MassHealth Selenium eligibility check (auto-uses saved member ID + DOB for existing patients), self-pay fallback
- Add AI Chat Settings page (Settings → Advanced) with editable greeting templates and LangGraph flow diagrams for both reminder and new-patient flows
- Add Schedule a New Patient template option in chat window, starts new-patient conversation flow
- Add GET/PUT endpoints for AI handoff, after-hours handoff, and AI chat templates
- Add multilingual support (7 languages) across all AI reply nodes with LLM generation and hardcoded fallbacks
- Add pending reschedule in-memory store and conversation stage tracking across all flows
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Upload Payment Documents section with Extract & Download (Excel)
and Extract & Import (database) buttons
- PDF extractor (pdfplumber) parses MassHealth RA PDFs: two-pass
strategy joins summary-page ICN/patient map with detail-page
procedure data (CDT code, paid code, tooth, date, allowed amount)
- RA cover-page summary (Payee ID, RA #, Payment Amount, etc.)
included as separate Excel sheet; numeric values written as numbers
- Backend PDF import route groups rows by Member #, finds/creates
patient, creates Payment + ServiceLines with ICN per procedure
- Add icn, paidCode, allowedAmount fields to ServiceLine schema
- Payments table: status simplified to Paid in Full / Balance;
adjustment auto-computed on mhPaidAmount/copayment change;
Paid in Full and Revert buttons with confirmation dialogs
- Edit Payment modal: shows ICN, Paid Code, Allowed Amount per line
- PDF Import badge distinguishes from OCR imports in payments table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Added copayment and adjustment fields (Decimal, default 0) to Payment
model in schema and directly to DB via ALTER TABLE
- Added PATCH /api/payments/:id/copayment and /adjustment routes
- Added inline-editable Copayment and Adjustment columns after MH Paid
with same click-to-edit format; Copayment in blue, Adjustment in orange
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add selenium_MHPaymentCheckWorker.py: logs into MassHealth portal, navigates to Search Claims, enters claim number, extracts totalPaidAmount from results table
- Register /mh-payment-check endpoint in Selenium agent
- Add mhPaidAmount field to Payment model with migration
- Add PATCH /api/payments/:id/mh-payment-check backend route: fetches MH credentials, calls selenium, stores result
- Add Claim No. column (MassHealth claim number) as first data column in payments table
- Move Payment ID and Claim ID columns to end of table
- Add MH Paid column showing mhPaidAmount in green
- Wire Check MH Payment button to call API for each selected payment and refresh table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Settings > Advanced > Procedure Duration/Time Slot page with three sections:
1. Procedure Duration: CDT codes with durations (editable table, save per section)
2. Doctor Time Slot: drag-to-block visual grid (A/B/C columns, 8 AM–9 PM, edit/delete slots)
3. Hygienist Time Slot: procedure descriptions with durations
- Backend: ProcedureTimeslot Prisma model, storage, and GET/PUT /api/procedure-timeslot route
- DB migration: procedure_timeslot table
- Appointment form: when type is "Other", show a free-text input for custom description; saved as other:<description> and decoded for display on the schedule card
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Schedule columns default to labels A–F (localStorage, per-browser, click to rename)
- Settings → Advanced → Office Hours: configure Doctors (A-C) and Hygienists (D-F) AM/PM hours per weekday
- Gray out schedule slots outside office hours; override dialog for manual exceptions
- Override Office Hours toggle: select specific dates where all slots are open
- Fix appointment move: send only real DB fields to avoid Zod strict-mode rejection of computed fields (hasProcedures, hasClaimWithNumber)
- Fix backend PUT /appointments: safe error logging to prevent Prisma error crashing Node inspect
- Add OfficeHours Prisma model and GET/PUT /api/office-hours route
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix dateOfBirth default from empty string to null (caused Invalid date error)
- Add noValidate to form to prevent browser native email validation blocking submit
- Reset form when switching from edit to add mode
- Export API_BASE_URL from queryClient; switch patient table to raw fetch (prevents token wipe on 401)
- Add Authorization header forwarding in Vite proxy (was stripped by nginx Connection:upgrade)
- Make only firstName, lastName, dateOfBirth, phone required; gender optional
- Add +1 prefix to phone number input (stores as 1XXXXXXXXXX)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Filter patient list by userId so each user sees only their own patients
- Sort patients by updatedAt DESC so recently checked patients appear first
- Add updatedAt field to Patient model (DB migration via raw SQL + db:generate)
- Fix DDMA name extraction: read from detail page "Name:" label, not search
results row text which included appended dates
- Fix PDF capture: use driver.get() instead of click() to avoid race condition
that was saving the search results page instead of the patient detail page
- Strip trailing bare dates from extracted names (e.g. "Rodriguez 04/27/2026")
- Handle "Last, First" comma format and single-word last names in splitName
- Normalize insuranceId consistently in createOrUpdatePatientByInsuranceId
- Fix OTP persistent session: stop clearing LocalStorage/IndexedDB on startup
(these hold the DDMA device trust token that skips OTP on subsequent logins)
- Increase post-navigation wait time for full page render before PDF generation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 'Select Procedures' right-click option on appointment page (separate from Claims/PreAuth)
- Select Procedures form saves CDT codes + NPI provider to AppointmentProcedure storage
- Remove Save button from insurance claim form; Claims/PreAuth opens for insurance submission only
- Claims/PreAuth auto-prefills from saved procedures including NPI provider
- Batch-column: procedures npiProviderId takes priority over stale claim npiProviderId
- Batch-column: auto-save PDF to patient Documents after successful submission (no socket needed)
- Add npiProviderId column to AppointmentProcedure table (prisma db push)
- Fix 'invalid db creation invocation': guard staffId, npiProviderId, procedureDate as Date object, totalBilled NaN guard
- Add full error logging to batch-column catch block
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix status enum in browser.ts (uppercase → lowercase values)
- Fix date validation (z.string → z.coerce.date) so form accepts Date objects
- Add missing type/userId/title fields to browser.ts appointment schema
- Replace nested PatientSearch Select with simple inline Input to fix patient selection
- Fix mutationFn to throw on non-ok responses so backend errors surface correctly
- Connect socket.io directly to backend (port 5000) instead of Vite proxy to fix AggregateError on startup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add PLAN_NOT_ACCEPTED to PatientStatus enum (prisma schema + db push)
- Selenium: return "plan not accepted" eligibility text instead of collapsing to inactive
- Backend processor: map "plan not accepted" → PLAN_NOT_ACCEPTED, fix insuranceProvider label
- _shared.ts: save DOB for existing patients when field is currently empty
- Frontend: show amber "Plan Not Accepted" badge in patient table and detail panel
- patient-form.tsx: display "Plan Not Accepted" label in status dropdown
- BullMQ: set attempts=1 (no retry on selenium failure)
- DDMA: remove first/last name from search (member ID + DOB only)
- patient-types.ts: allow alphanumeric insurance IDs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use useAuth() in CredentialTable instead of a separate /api/users/ fetch
that was failing silently and hiding the entire credentials section
- Add migration for autoBackupEnabled/usbBackupEnabled columns on User
that were in the Prisma schema but missing from the database, causing
a 500 error on login
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>