Add OpenAI, Claude AI, and DentalManagement AI sections to the AI API
Setting page, each with a masked API key input and an on/off toggle
(defaulting to off). Rename sidebar label from "Google AI Settings" to
"AI API Setting". Add provider-key and provider-enabled backend endpoints
and extend the AiSettings schema with 6 new fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Internal AI chat: schedule_appointment intent books earliest available
slot in Column A using office hours; claim_only intent looks up latest
past appointment for service date, asks user when two appointments are
within 7 days, auto-triggers correct Selenium worker with mapped prices
- Gemini model updated to gemini-flash-latest; conversation history (15
messages) passed for pronoun/reference resolution; history trimmed to
start with user turn so Gemini doesn't reject the context
- Insurance alias file (insuranceAliases.json) replaces hardcoded siteKey
matching; "tufs" now resolves to TUFTS_SCO
- DOB format normalized (MM/DD/YYYY → YYYY-MM-DD) before parseLocalDate;
autoCheck now fires for all insurance types, not just MH/CMSP
- Claim form auto-submit: all handlers (MH, CCA, DDMA, UnitedDH, Tufts)
accept formToUse and receive fee-schedule-priced form; prefillDone set
after chatbot code prefill so autoSubmit gate opens correctly
- Chatbot: chat history persisted in sessionStorage, cleared on logout
and auto-logout; Clear button writes fresh state synchronously; message
history window increased to 15
- DentaQuest/TuftsSCO Selenium: "Remember me" checkbox clicked before
sign-in to persist OTP trust cookie across sessions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tracks user activity events (mouse, keyboard, scroll, touch) and resets
a 60-minute idle timer on each event. Shows a warning toast at 55 minutes,
then calls logoutMutation at 60 minutes to clear the session.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use appear-then-disappear pattern: briefly wait for spinner to show up
(so we don't pass through before it starts), then wait for it to clear.
Prevents element click interception on Find Provider button in step2.
Also restores element_to_be_clickable for New Eligibility Request (step1).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
- 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>
- 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>
- 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>
- 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>
- Move Select Procedures above Check Eligibility in appointment right-click menu
- Show 3 blank service lines by default when opening Select Procedures with no saved procedures
- Fix serviceLines not being preserved when API returns empty procedures list
- CDT combo buttons no longer auto-fill price (only fill codes); user maps price via Map Price button
- Overlap detection in schedule: shorten earlier appointment display span when a later one starts within its range
- Procedures dialog: replace single manual-add row with 3 pre-filled blank rows grid + Add Line / Save Lines buttons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rewrote UnitedDH claim worker to navigate via eligibility page → Selected Patient → Submit Claim button flow
- Updated helpers_uniteddh_claim.py step names to match new 9-step workflow
- Changed payer selection in both eligibility and claim workers to type + Enter
- Updated patient table column header from 'DOB / Gender' to 'DOB'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Using paymentGroupId label as the page-load wait caused TimeoutException when
the claim flow's page structure differed, returning ERROR and triggering
_minimize_browser (about:blank + minimize). Now waits for the btn-primary
Continue button (original safe indicator) and wraps both dropdown selections
in try/except so the step never fails due to a missed dropdown.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors the same Provider & Location page pattern from the eligibility worker:
- wait for paymentGroupId label visibility before interacting
- Treatment Location: ng-arrow-wrapper click + ARROW_DOWN/ENTER
- Billing Entity: ng-arrow-wrapper click + ARROW_DOWN/ENTER
- re-find Continue button after selections to avoid stale element
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- United SCO eligibility: add Treatment Location step before Billing Entity
on Provider & Location page; both use ng-arrow-wrapper ActionChains click
+ ARROW_DOWN/ENTER keyboard selection to handle upward-opening panels
- Use visibility_of_element_located for Billing Entity label wait so code
waits for page to fully render after Select Insurance modal closes
- DOB (and all dates) now display as MM/DD/YYYY instead of Mon DD, YYYY
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DentaQuest stores its MFA trust as a persistent cookie, not in
LocalStorage like DDMA/Azure B2C. Deleting the Cookies file on startup
wiped that trust token, forcing OTP on every app restart. Now only the
credentials tracking file is reset on startup; if credentials change,
_force_logout() still calls delete_all_cookies() for a full reset.
Covers both eligibility and claim flows (both share the same
DentaQuestBrowserManager singleton).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
- 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>
- 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>
Adds stop-app.sh to kill all services by port (5000-5003, 3000/3001)
and updates setup-desktop-shortcut.sh to create both Start and Stop
desktop shortcuts in a single run. README Step 13 updated accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
- 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>
- Route DDMA eligibility through InProcessQueue (concurrency=1) so it
queues behind other selenium jobs instead of running concurrently
- New ddmaEligibilityProcessor: starts Python session, polls for OTP/
completion via socket events, saves PDF and updates patient DB
- Frontend ddma-buton-modal now uses shared app socket + job:update
pattern (drops private socket connection)
- SeleniumService: upgrade ddma_browser_manager with credential hash
tracking, anti-detection options, and startup session clearing;
upgrade DDMA worker with firstName/lastName support, PDF via
printToPDF, force-logout on credential change; upgrade helpers with
dual OTP strategy (app API + browser polling); add /clear-ddma-session
endpoint; reduce fixed sleeps with smart WebDriverWait
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Reset public schema before psql restore so existing tables don't
block CREATE TABLE statements (pg_dump without --clean has no DROPs)
- Disconnect Prisma connection pool after restore so next request
gets fresh connections against the restored data
- Auto-create the USB backup subfolder if it doesn't exist instead
of failing; only fail if the destination drive itself is missing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds ordered setup steps (Node.js, Python, Chrome, PostgreSQL, Redis,
pip dependencies) so a fresh machine can be fully configured from
git clone to running the app without guessing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>