84 Commits

Author SHA1 Message Date
Gitead
ba2882957a feat: Users AI Chat multi-step workflows with CDT lookup and alias management
- Add eligibility_by_id and check_and_claim intents to internal chat
- New cdt-lookup.ts: keyword search against fee schedule JSON (no LLM)
- New internal-chat-workflow.ts: deterministic orchestration — patient
  resolution, insurance siteKey derivation, CDT code mapping
- Custom CDT aliases stored per-user in DB (TwilioSettings JSON blob)
  with GET/PUT /api/ai/cdt-aliases endpoints
- Chatbot UI: new steps for eligibility-id-ready, check-and-claim-ready,
  and need-insurance-clarification with insurance picker
- Settings UI: CDT Aliases CRUD table with built-in alias reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 17:44:19 -04:00
ff
ddcc49b72c feat: add in-browser dial pad with Twilio Voice SDK
- New DialPad component on Patient Connection page: clickable keypad,
  call/hangup/mute buttons, duration timer, keyboard input support
- Backend: POST /api/twilio/voice-token issues Access Token for browser
  Device; POST /api/twilio/webhook/voice-browser is the TwiML webhook
  Twilio calls to bridge the browser to the patient's phone
- TwiML App SID field added to Twilio Settings (stored in templates JSON)
- README: one-time Twilio Console setup instructions for the dial pad

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:24:53 -04:00
ff
be90966f6e feat: add internal AI chat assistant and AI Input Agent page
- Add Gemini-powered internal staff chatbot (free-text input in the
  upper-right bot panel): type "check MARIA GONZALES" to search patient
  and pre-fill eligibility, or "open claims" to navigate directly
- Add /api/ai/internal-chat endpoint with LangGraph + Google Gemini
  classifier (intent: check_eligibility, find_patient, navigate_*)
- Add Users AI Chat settings section in Settings > Advanced > AI Chat
  to configure a custom system prompt for the internal assistant
- Store internal chat system prompt in existing twilioSettings JSON
  blob (no DB migration needed)
- Add AI Input Agent sidebar entry and placeholder page describing
  planned keyboard-automation typing into Open Dental / Eaglesoft

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 00:44:05 -04:00
ff
3ac185b0ec fix: BCBS MA — identify patient by member ID + DOB, prevent overwriting subscriber
- Added getPatientByInsuranceIdAndDob to storage
- Processor uses insuranceId + DOB as unique key instead of insuranceId alone
- Dependent with same subscriber ID but different DOB gets a new patient record
  (bypasses createOrUpdatePatientByInsuranceId which would overwrite subscriber)
- Name extraction anchored to "Relationship:" to scope Patient Info column only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 23:51:11 -04:00
ff
87d7ce9ed9 fix: BCBS MA eligibility — name extraction, tab switching, DOB input, button color
- Extract patient first/last name from Patient Information DOM section
  (scoped to avoid duplicate Subscriber Information column values)
- Switch to latest tab at start of step2 (Eligibility Identifier opens in new tab)
- DOB: double-click + ActionChains.send_keys (no pyperclip, avoids Chrome crash)
- BCBS MA button changed to variant="default" to match nearby buttons
- Backend processor uses extracted names from selenium result

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 01:18:20 -04:00
ff
e644d21cee feat: add BCBS MA eligibility check with OTP flow
- New Selenium worker (fresh Chrome per run, no persistent session)
  login → OTP modal → eTools → ConnectCenter → Verification →
  New Eligibility Request → fill form (NPI, member ID, DOB) →
  Expand All → CDP PDF back to app
- Backend route fetches BCBS_MA credentials + provider NPI from settings
- Frontend OTP modal with 6-digit code entry
- BCBS MA added to insurance credentials dropdown in settings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 00:36:11 -04:00
ff
535619c286 feat: make claim number editable in Edit Claim Status modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 23:44:55 -04:00
ff
9d0cfe5dba feat: appointment type inference, procedure codes on cards, claim attachment fixes
- Add appointment type categories matching insurance claim form (recall, filling, pedo, dentures, implant, endo, crown, perio, extraction, ortho, consultation, emergency, other)
- Auto-infer appointment type from CDT codes with priority rules (endo > implant > crown > ...)
- typeLocked flag prevents auto-overwrite when user manually sets type
- Show appointment type label and procedure codes on schedule cards
- Background sync on /day route retroactively fixes stale appointment types
- Fix PUT /api/claims/:id to save claimFiles (previously silently dropped)
- Auto-link AppointmentFile records to ClaimFile when claim is created or updated
- Fix D5750 (denture reline) CDT range to map correctly to dentures category
- Fix typeLocked Zod rejection in appointment update route

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 14:18:10 -04:00
ff
b20dc8e976 fix: D0140 claim sync, schedule column prefill, multi-appt, DentaQuest OTP session
- Fix Express route ordering in appointments-procedures so /prefill-from-appointment
  is matched before /:id (D0140 and other codes now always reach the claim)
- claim-form: always fetch AppointmentProcedure records when an existing claim loads
  so post-save procedure edits (e.g. adding D0140) are reflected immediately
- appointments-page: replace sessionStorage with React state (newApptPrefill) for
  slot-click prefill so columns B-F correctly carry their staffId into the form
- add-appointment-modal / appointment-form: thread prefillData prop; add
  NewAppointmentPrefill interface; useEffect applies values via setValue
- appointments upsert: remove per-patient dedup so the same patient can have
  multiple appointments on the same day in the same column
- DentaQuest / TuftsSCO: navigate to about:blank and minimize instead of
  quit_driver after each run — session cookie stays in memory so OTP is only
  required once per app startup, not on every eligibility or claim check

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 15:39:36 -04:00
ff
3e61bdec36 feat: route batch-column claims by insurance type, fix eligibility UX
- claims.ts: batch-column now routes each patient to the correct portal
  (MH/CCA/DDMA/TuftsSCO/UnitedSCO) based on patient.insuranceProvider
- appointments-page.tsx: eligibility badge falls back to patientStatus
  for all insurance types, not just MassHealth
- unitedDHClaimProcessor/ddmaClaimProcessor/tuftsSCOClaimProcessor:
  auto-save claim PDF when no socketId (batch-column path)
- unitedSCOEligibilityProcessor: unknown eligibility no longer stored as INACTIVE
- queues.ts: add tuftssco-claim-submit and uniteddh-claim-submit to SeleniumJobType
- selenium_UnitedSCO_eligibilityCheckWorker.py:
  - step1: add Select Insurance OK click with staleness wait; Provider &
    Location page just clicks Continue; skip first/last name input
  - step2: extract name from eligibility details tab (ALL CAPS → title case);
    skip "not available" guard; fix name regex to match only all-caps words
- .gitignore: ignore all chrome_profile_* directories

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 23:07:42 -04:00
ff
080b0c65b8 fix: correct license key part count validation (5 not 6)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 21:50:30 -04:00
ff
070752380d feat: add license activation system with feature gates
- License key generator tool at ~/Desktop/LicenseGenerator
- Backend validator route (GET /api/license/status, POST /api/license/activate)
- Activation page in sidebar with status, key input, and free/premium feature list
- useLicense hook for frontend license state
- Feature gates: premium eligibility buttons (DDMA, DeltaIns, Tufts, United, CCA) disabled without license
- Feature gates: premium claim buttons (CCA, Delta MA, United, Tufts) and all PreAuth buttons disabled without license
- Free features always active: MassHealth eligibility/claim, Documents, Payments, Backups, Reports
- README: license key generator usage instructions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 21:22:34 -04:00
ff
816d9e0ee7 feat: make Cloudflare host configurable per office via env
Each office sets VITE_CLOUDFLARE_HOST and CLOUDFLARE_HOST in their
local .env files instead of hardcoding the subdomain in source code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 11:55:28 -04:00
Gitead
fcb049273a feat: add missing backend route and frontend utility/config files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 22:26:58 -04:00
Gitead
adb5801023 feat: add missing selenium CCA preauth and UnitedDH claim client services
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 22:26:03 -04:00
Gitead
3534ecb3c9 feat: Tufts SCO claim automation, Claim All button, fee schedule updates
- Add full Tufts SCO claim Selenium worker (steps 1-8): login with OTP
  support, member search, Create Claim, fill form, attach files, submit,
  extract claim number and save confirmation PDF
- Fix DentaQuest browser manager to preserve device trust token on startup
  (only clear cookies, not LocalStorage/IndexedDB) so OTP is only needed
  once for both eligibility and Tufts claim
- Fix Tufts SCO claim route credential lookup key (TUFTS_SCO not TuftsSCO)
- Add Tufts SCO and United/DentalHub entries to fee schedule update route
- Add "Claim All" button that auto-routes to the correct claim handler
  based on the Insurance Type dropdown value
- Add fee schedule JSON files for DDMA, Tufts SCO, and United/DentalHub

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 20:22:26 -04:00
Gitead
1e581c193c feat: United/DentalHub claim submission automation and patient list sync
- Add full Selenium automation for United/DentalHub claim submission
  (steps 1-8: login, OTP, patient search, practitioner page, code entry,
  other coverage No, attachments, submit, Status & History PDF)
- Consolidate UnitedDH siteKey to UNITED_SCO throughout app
- Fix procedure date overwrite with Ctrl+A+Delete before typing service date
- Fix OTP popup reliability: emit every poll (no throttle)
- Fix Chrome session persistence: only clear cookies on startup
- Add touchPatient() to storage: claim submission now pushes patient to
  top of list across eligibility, claims, and documents pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 00:29:04 -04:00
Gitead
cd1381e9c6 feat: DDMA claim submission with OTP, PDF, claim number extraction
- Add full DDMA claim Selenium flow (steps 1-8): search patient, open
  member page, create claim, fill form, attach files, next, submit,
  extract claim number and save confirmation PDF
- Add fee schedule price-mismatch dialog for all claim buttons (MH,
  CCA, DDMA, United, Tufts, Save) with optional price update to JSON
- Add OTP modal for DDMA claim when session expires, mirroring
  eligibility OTP flow
- Close Chrome after claim submission via quit_driver() (session
  preserved in profile)
- Move Map Price button between Direct Submission and procedure table,
  right-aligned above Billed Amount column
- Add fee-schedule update-price backend route
- Add DDMA claim processor with claimNumber/pdf_url result handling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 13:35:04 -04:00
Gitead
5ceecbeb7f feat: improve CCA preauth cell filling, implants category, preauth no recording
- Selenium: bulletproof Wait→Click→Clear→Type→Verify for tooth, billed amt cells
- Selenium: fix billed amt to click td[23] (correct column) to trigger edit mode
- Selenium: skip tentative date (auto-filled by page after tooth entry)
- Frontend: add Implants category with Implant/Abut/Crown, Fixture, Abutment, Crown buttons (D6010/D6057/D6058)
- Frontend: pdf-preview-modal renders PNG screenshots as <img> instead of PDF iframe
- Backend: CCA preauth route creates claim record if none exists
- Backend: CCA preauth processor saves authNumber into claimNumber column after submission

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 22:01:52 -04:00
Gitead
0e664e4813 feat: add CCA claim submission with Selenium automation
- Add CCA claim submit Selenium worker (login, fill form, attach docs, submit, capture dashboard PDF)
- Add CCA fee schedule (procedureCodesMH.json renamed, procedureCodesCCA.json added with D6010)
- Add backend route /api/claims/cca-claim, processor, and Selenium client
- Wire CCA claim handler in claims-page with job tracking and PDF preview popup
- Add insurance type dropdown in claim form (same options as eligibility page)
- Auto-populate insurance type from patient.insuranceProvider in claim form and patient edit form
- Map fee schedule by insurance type in Map Price button and combo buttons
- Fix CCA login speed (remove fixed sleeps, use readyState check)
- Fix CCA claim DOB format bug (was sending MM-DD-YYYY, now sends YYYY-MM-DD)
- Fix npiProviderId not saved for CCA claims
- Change Add Service → CCA Claim button (blue), MH → MH Claim

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 13:34:03 -04:00
Gitead
8e6ada87d6 fix: set empty VITE_API_BASE_URL_BACKEND and add HTTPS origin to CORS
External browsers were hitting localhost:5000 instead of going through
nginx. VITE_API_BASE_URL_BACKEND is now empty so all API calls use
relative /api/ paths that nginx proxies to the backend. Also adds
https://communitydentistsoflowell.mydentalofficemanagement.com to
FRONTEND_URLS for CORS. Updated .env.example to match so setup from
template doesn't silently revert this fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 22:35:53 -04:00
ff
de995de2ad fix: allow deleting users by reassigning their records to admin first
Deleting users with patients/appointments/claims was blocked by FK
constraints. Now reassigns those records to the requesting admin before
deletion, and cleans up user-specific data (backups, cloud files).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:06:36 -04:00
ff
8cab823d60 feat: share patients across all users
Removed per-user patient filtering so all staff accounts see the same
patient pool. Previously each user only saw patients they created.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:04:26 -04:00
ff
b148c0de30 fix: apply missing migrations directly after DB restore
Replace the prisma migrate deploy subprocess with a custom
applyMissingMigrations() that reads each migration SQL file and runs it
via prisma.$executeRawUnsafe. This avoids the Prisma CLI aborting when
the restored _prisma_migrations table contains orphaned entries (migration
names that no longer have a corresponding file in the migrations folder).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 22:36:35 -04:00
ff
5508a90d28 fix: auto-migrate after DB restore and force re-login
- After importing a backup, run prisma migrate deploy so any schema
  migrations the backup is missing are applied automatically. This
  prevents pages from failing due to missing tables/columns when the
  backup was taken on an older version of the app.
- Force logout and redirect to login after a successful restore so the
  JWT is refreshed against the restored database (prevents userId
  mismatch causing user-scoped queries to return empty results).
- Fix getTotalPatientCount() in /status route to pass userId so it
  counts only the current user's patients instead of all patients.
- Add prisma.$connect() after $disconnect() to ensure a clean reconnect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 22:31:12 -04:00
Gitead
e34140c2b1 feat: add AI Dental Shopping section with sidebar nav and Login Info page
- Add AI Dental Shopping to sidebar with Search/Tag and Login Info sub-pages
- Build full-stack Login Info CRUD: save vendor name, website, username, password per user
- Add ShoppingVendor Prisma model, run db push, regenerate client and Zod schemas
- Add storage layer, REST API at /api/shopping-vendors/, and frontend table with add/edit/delete modal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 00:35:38 -04:00
Gitead
cf85750d90 feat: add PreAuth tab, preauth selenium flow, and PreAuth No column
- Insurance Forms modal: split into Insurance Claim / PreAuth tabs
- PreAuth tab: same patient info + service lines, no toggle/direct combos
- Excluded Recalls & New Patients, Composite Fillings (Front/Back), Pedo from PreAuth combos
- Extractions: replaced Simple/Surg/Baby Teeth EXT with Full Bony EXT (D7240)
- MH PreAuth button: rewritten selenium worker to use masshealth-dental.org,
  selects Dental Prior Authorization (2nd option), skips Date of Service field
- agent.py: convert pdf_path to pdf_url for /claim-pre-auth endpoint
- nginx + Express: raise body size limit to 50mb (fix 413 errors)
- DB schema: appointmentId optional on Claim, add preAuthNumber field, add PREAUTH status
- Backend: create PREAUTH claim record on preauth submit, save preAuthNumber on completion
- Claims table: add PreAuth No column (blue) next to Claim No

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 22:53:41 -04:00
Gitead
7360b1930b feat: add provider column, commission tracking, and report provider filter
- 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>
2026-05-15 23:51:39 -04:00
Gitead
a485396a96 fix: add HTTP polling fallback for selenium job results through Cloudflare
Socket.IO reconnects through Cloudflare proxy get a new socket.id, causing
the backend to emit job:update to a stale socket that no longer exists. The
PDF viewer modal never opened even though PDFs were saved successfully.

Adds a GET /api/insurance-status/job-status/:jobId endpoint backed by
InProcessQueue.getJob(), and a waitForSeleniumJob() helper on the frontend
that races socket events against HTTP polling every 3s. Whichever resolves
first wins, so local (socket) and external (Cloudflare) both work reliably.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 09:33:46 -04:00
Gitead
c71624f7e7 feat: enhance new-patient AI chat flow with full scheduling and eligibility
- 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>
2026-05-15 00:00:56 -04:00
Gitead
4f2cbc2c60 fix: prevent double self-introduction in reschedule MSG 2
- reminder-graph: add stripIntroFromFallback() to remove 'Hi! My name is Lisa...'
  from any saved rescheduleGreeting template before using it as the MSG 2 fallback
- reminder-graph: add explicit 'Do NOT introduce yourself' to rescheduleNode Gemini
  prompt so the AI never adds its own intro to MSG 2
- ai-chat-templates-card: add hasIntroPattern() warning on the Reschedule Patients
  template field — shows an amber alert if the saved template starts with a
  self-introduction, guiding users to remove it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 12:59:43 -04:00
Gitead
0628f9f7fc feat: add member details PDF step to MH history and CMSP flows
After clicking the member ID link, print the member details page via CDP
before navigating to service history. Adds member details as a panel in
the side-by-side PDF viewer: MH History shows 3 panels (eligibility,
member details, service history); CMSP shows 4 panels (eligibility,
member details, service history, accumulator).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:33:02 -04:00
Gitead
06526cd1bc feat: MH eligibility & history, CMSP eligibility & history & remaining
- Add MH Eligibility & History button: runs full MH eligibility flow then
  clicks member ID → service history, prints both PDFs via CDP, opens
  dual side-by-side PDF modal (eligibility auto-downloads, history does not)
- Add CMSP Eligibility & History & Remaining button: same flow plus
  navigates back to member details, clicks View Accumulator, prints
  accumulator PDF via CDP; opens 3-panel side-by-side PDF modal
- Generalize DualPdfPreviewModal to accept panels[] array (works for 2 or 3 PDFs)
- Auto-download eligibility PDF via direct API URL to avoid Chrome Safe
  Browsing pause on blob: URL downloads
- New backend processors, job types, and routes for both flows
- New Python Selenium workers with stable CSS selectors (ng-bind, href*)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 23:29:55 -04:00
Gitead
131733564e feat: reschedule-by-office batch SMS, AI follow-up toggle, date-shortcut fix, combined flow diagram
- Add Reschedule for Column button on schedule page with AI follow-up toggle (default on)
- Add POST /api/twilio/send-reschedule-batch — sends Reschedule by Office template, starts AI reschedule conversation per patient
- Add {officePhone} (office call-in number) and {twilioPhone} (SMS number) variable replacement in both batch endpoints
- Fix broken variable names in Reschedule by Office template ({office phone number) → {officePhone}, {Twilio phone number} → {twilioPhone})
- Fix reschedule-graph: when patient replies with date in same message as YES/NO (e.g. "ok, 5/18"), AI now checks day open and asks for time instead of asking "what day and time?"
- Fix twilio-webhooks: same date-shortcut logic for reminder flow — "no, 5/18" skips "when to reschedule?" and goes straight to day check
- Update LangGraph SVG: rename to Reminder & Reschedule Flow, combine both entry points (Reminder SMS + Reschedule SMS) into one diagram with date-shortcut annotations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 00:36:38 -04:00
Gitead
7929dc6e19 feat: office address, multi-template SMS manager, hardcoded defaults with auto-seed
- 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>
2026-05-11 23:18:04 -04:00
Gitead
3abccf16a9 fix: use exclusive end-time boundary in office hours check
time <= amEnd incorrectly allowed 12:00 when the office closes at 12:00.
Changed to time < amEnd (and time < pmEnd) so the session end time is
treated as a closed boundary — a patient cannot start an appointment at
exactly the time the session ends.

Fixes both the SMS reschedule flow and the schedule grid slot highlighting.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 21:44:41 -04:00
Gitead
5e3cfef52b feat: label AI-rescheduled appointments and add manual confirm option
- 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>
2026-05-11 19:23:36 -04:00
Gitead
1ff843bc79 feat: AI SMS reminder flow with two-message intro, smart reschedule with availability checks
- Reminder flow: send AI self-introduction as message 1 (Twilio REST API), intent response as message 2 (TwiML) so intro always arrives first
- LangGraph reminder graph: classify yes/no/other from patient reply; 'no' now asks 'When would you like to reschedule?' directly
- Reschedule flow: new asked_reschedule_datetime stage replaces multi-step ASAP/next-week flow
  - Date-only reply (e.g. '5/18'): ask for time separately, then confirm
  - Date+time reply (e.g. '5/18 at 10am'): go straight to confirmation
  - new asked_reschedule_time_for_date and asked_reschedule_confirm_datetime stages
- Date/time parsing: regex handles M/D and am/pm formats first; falls back to Gemini for natural language
- Day-level office hours check: if requested day is closed (e.g. Sunday), reply 'Our office is closed on [date]. Choose another day?'
- Time-level office hours check: if requested time is outside working hours (e.g. 12pm during lunch), reply with actual hours (e.g. '9:00 am – 12:00 pm and 1:00 pm – 5:00 pm')
- Slot availability check: verifies no conflicting appointment for same staff member
- After appointment confirmed: patient thank-you reply triggers warm closing with upcoming appointment time
- Schedule page: office hours summary bar above grid showing today's configured hours with link to settings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:01:23 -04:00
Gitead
585b448b6e feat: schedule page SMS reminders with AI follow-up and reschedule column
- Add Text Reminder for Column button with per-column checkboxes and AI follow-up toggle (default on)
- Batch reminder endpoint resolves {firstName}, {officeName}, {appointmentDate}, {appointmentTime} from AI chat templates
- Add Reschedule for Column UI (logic TBD)
- Move Download Claim PDF for Column below Reschedule for Column
- Add reminderSms template field to AI Chat Settings with variable hints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 23:17:05 -04:00
Gitead
112529155c feat: persist AI conversation state in DB and fix LangGraph flow bugs
- 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>
2026-05-09 15:23:55 -04:00
Gitead
e9296c68f9 feat: auto-populate patient fields from member ID on eligibility page
When a member ID is typed on the insurance eligibility page, debounced
lookup fills in date of birth, first name, and last name if the patient
already exists in the database.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 14:30:29 -04:00
Gitead
9908e5b5fd feat: AI chat system with LangGraph, multi-step patient flows, and appointment rescheduling
- 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>
2026-05-07 23:21:06 -04:00
Gitead
16429320fa feat: chat window, preferred language, insurance contact, and AI call eligibility
- Schedule: right-click Chat option opens floating SMS chat window
- Chat window: SMS template selector with appointment date/time pre-filled
- Chat window: office name and phone pulled from Settings > Office Contact
- Chat window: Preferred Language selector (English, Spanish, Portuguese,
  Mandarin, Cantonese, Arabic, Haitian Creole) with fully translated templates
  and locale-aware date/time formatting
- Patient form: Preferred Language field (add/edit), default English
- Settings > Office Contact: added Dental Office Name field
- Settings > Advanced: Insurance Contact page (CRUD — company name + phone)
- Prisma schema: preferredLanguage on Patient, officeName on OfficeContact,
  new InsuranceContact model
- Patient management: Upload Patient Document moved below Patient Records
- Insurance Eligibility: AI Call Insurance collapsible section; insurance
  company and phone auto-populated from saved Insurance Contacts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 16:42:37 -04:00
Gitead
dd0df4a435 feat: payment PDF extraction, import, and remittance tracking
- 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>
2026-05-07 12:53:50 -04:00
Gitead
e204d30ff6 fix: update per-patient collected in reports to use mhPaidAmount + copayment
All per-patient SQL queries now compute:
  collected = mhPaidAmount + copayment
  balance   = totalBilled - collected - adjustment

Fixes patient rows showing $0 collected while report total was correct.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 21:51:15 -04:00
Gitead
49415bcfc4 feat: wire copayment/adjustment into balance and collected calculations
Balance = totalBilled - mhPaidAmount - copayment - adjustment
Collected = mhPaidAmount + copayment (adjustment is a write-off)

- Frontend breakdown now shows Collected, Adjustment (if >0), and Balance
- Reports: totalCollected and totalOutstanding use the new formula
- Both date-range and staff summary queries updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 21:36:04 -04:00
Gitead
4bd501250d feat: add Copayment and Adjustment columns to payments table
- 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>
2026-05-06 21:14:00 -04:00
Gitead
6f33e416c1 feat: make MH Paid column inline-editable
Add PATCH /api/payments/:id/mh-paid-amount for direct value updates.
Clicking the MH Paid cell opens an input; Enter/blur saves and refreshes,
Escape cancels. Dash placeholder is also clickable to enter a value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 17:50:52 -04:00
Gitead
1196e2afee feat: add Check MH Payment automation and MH Paid column
- 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>
2026-05-06 15:12:56 -04:00
Gitead
4989201c62 feat: add AI settings routes, storage, UI card, and migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 08:58:58 -04:00