WebDAV server now serves the Backend root directory. Receiver pulls
backups/, chat-history/, and uploads/ individually so all data is
synced between PCs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds autoImportEnabled/autoImportHour to rclone config. A separate
hourly cron finds the latest .zip in backups/ and restores it to the
database (drop schema, psql restore, apply migrations). Frontend shows
toggle + time picker + Import Now button in the Receiver PC section.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded 8 PM / 9 PM backup schedules with user-selectable
hour dropdowns. Adds autoBackupHour and usbBackupHour fields to User
model. Cron jobs now check every hour against the configured time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Source PC serves backups/ folder via rclone WebDAV server (auto-starts with app).
Receiver PC pulls backups on schedule using rclone sync.
Network Backup UI now has two tabs: Rclone and API Key.
Rclone installed automatically via postinstall script.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces arrow-wrapper click (which hit the "Type to search" placeholder) with
find_element(By.ID, "treatmentLocation") + click, mirroring the paymentGroupId
approach. Looks for "Summit Dental Care" first, falls back to first available option.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Requests from outside 10.x, 192.168.x, 172.16-31.x, 127.x are rejected
with 403 before the API key is even checked. This prevents the database
dump endpoint from being reachable from the internet even if the key leaked.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The /network-backup and /network-backup-files routes use their own
X-Network-Backup-Key authentication. Mounting them behind authenticateJWT
blocked all receiver sync requests before they could be validated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Side effects inside queryFn caused the enabled toggle and other fields to
reset on refetch because SyncStatus shares the same query key with a
different queryFn, making formLoaded unreliable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy-paste often adds trailing whitespace that breaks the API key comparison.
Updated placeholder and description to show the correct URL format (no port number).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add parseMultiPaCode: "4PA #3#14#19#30" expands to D0220 + 3× D0230 with tooth numbers
- Add "3rd pa"–"6th pa" direct aliases → D0230 as fallback
- Tighten LLM prompt to always use "2nd pa" for all additional PAs, never "3rd pa" etc.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- appointments-page: save full queue from current patient on confirm so that
cancelling the claim form resumes at the same patient instead of skipping it
- claims-page: advance ai_claim_queue only after successful submission (CCA,
MH selenium PDF download, or direct non-draft submit) via new advanceAiClaimQueue()
- cdt-lookup: fix extractToothSurface regex to allow space between # and digit
(e.g. "# 32") so tooth number is correctly captured
- cdt-lookup: silently skip bare tooth-number tokens ("# 32", "#32") that the
LLM may emit as standalone items, preventing false "unrecognized procedure" errors
- internal-chat-graph: add explicit rule that a CDT code followed by # NN
(e.g. "D7210 # 32") must stay as one entry and not spread to other procedures
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add batch_eligibility_by_name intent so "check Mary and Sinthia" resolves multiple names
- Add "Check All & Appointment Today" button to batch eligibility UI — creates appointment for each patient after their eligibility check completes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add batch_eligibility, batch_claim, and batch_check_and_claim intents
to AI classifier so multiple patients can be processed one by one
- Add queue processing on insurance-status and claims pages to auto-start
the next patient after each check/claim completes
- Make patient schema firstName, lastName, phone optional so patients can
be created with just member ID + DOB from eligibility checks
- Cancel buttons now preserve chat history instead of clearing it
- Patient-found card shows Check Eligibility, Eligibility & Appointment
Today, and Cancel buttons
- Claim service date asks user to pick between latest appointment and
today when they differ
- Login page subtitle styled with animated gradient
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Chat history was stored only in sessionStorage, causing member ID and DOB
to be lost when the session expired or corrupted — requiring logout/login.
Now history is saved to a per-user JSON file on the backend and loaded on
mount, so the LLM always has full conversation context.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract patient name from search results row instead of failing on detail page
- Return dateOfBirth from input data (no need to scrape from webpage)
- Wait for search page to fully load before provider dropdown selection
- Add 3s wait after search results appear for row content to render
- Backend: fallback to update existing patient DOB instead of creating duplicate
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The chatbot-extracted DOB was stored in chatbot_claim_codes but never
forwarded to chatbot_claim_prefill, leaving the claim form DOB empty
when the patient DB record lacked it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add public /api/greeting endpoint that generates a daily AI greeting (cached per day)
- Replace static hero text with dynamic AI greeting (ChatGPT/Claude style)
- Add Stripe-style animated gradient blobs with 14 daily-rotating color palettes
- Use Plus Jakarta Sans font and Sparkles icon for modern AI look
- Update subtitle to "Driven by multiple AI agents"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claims no longer auto-create a schedule appointment when submitted — appointmentId is now optional.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add preauth intent to AI chatbot (classifier, workflow, frontend UI card)
- Auto-prefill preauth form with CDT codes, service date, and mapped prices
- Auto-trigger preauth Selenium handler by insurance siteKey (MH/Tufts/CCA/UnitedDH)
- Default tentative service date to today+3 for preauth (user didn't pick a date)
- Fix #number always means tooth number, distributes to all procedures in comma list
- Fix bare "post"/"pos" → D2954 (was matching D2955 via keyword scorer)
- UnitedDH pre-auth: fill procedure date with Ctrl+A to overwrite prefilled value
- UnitedDH pre-auth: select Location "Summit Dental Care" in step1 (same as billing entity)
- UnitedDH pre-auth: remove page refresh in step9 to preserve pre-auth number
- UnitedDH pre-auth: wait for table rows before extracting pre-auth number
- UnitedDH pre-auth/claim: explicit wait for Submit button after file upload (no sleep)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pre-auth step9: scan all table cells alphanumeric-first (A0260616190876 format),
URL extraction, body scan fallback with debug logging
- Pre-auth route: save service lines (totalBilled) when creating PREAUTH claim record
so claim page shows correct billed amount after selecting patient
- Pre-auth processor: read pdf_path fallback alongside pdf_url from Selenium result
- UnitedDH/SCO workers: billing entity selection via direct paymentGroupId click,
Summit Dental Care first with fallback, Escape to close dropdown
- Pre-auth form: remove Other Insurance step (not present on pre-auth page),
file upload direct to hidden input without button click
- Pre-auth step8: JS click + Submit Authorization in XPath, Continue via [last()] + JS click
- RCT combo buttons added (pre-auth form only): RCT Ant/Post/Crown, PreM/Post/Crown,
Mol/Post/Crown; claim form excludes these three combos
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Frontend: upload attachments to disk before sending pre-auth payload (same pattern as claims)
- cloud-storage: finalizeFileUpload returns diskPath so Python workers get real file paths
- upload-to-cloud route: return diskPath instead of API URL
- TuftsSCO preAuth worker: skip 'Add a file' button click; send_keys directly to hidden react-aria-Input
- TuftsSCO preAuth worker: JS focus() on tooth field to bypass warning-banner overlay
- TuftsSCO preAuth worker: 1.5s wait after procedure code for layout shift to settle
- TuftsSCO preAuth worker: step8 waits for 'thank' in page_source then extracts via 'submitted pre-authorization' regex
- helpers_tuftssco_preauth: convert pdf_path → pdf_url (http://localhost:5002/downloads/...)
- tuftsSCOPreAuthProcessor: use pdf_url (not pdf_path), save preAuthNumber to preAuthNumber field
- unitedDHPreAuthProcessor: save preAuthNumber to preAuthNumber field (not claimNumber)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- claims-page: after auto-submit closes the form, automatically navigate
back to /appointments when an AI claim queue is pending resume, eliminating
the manual navigation delay between appointments
- internal-chat-workflow: warn and block claim when D1120 (child prophy) is
requested for a patient aged 14+ — recommend D1110 (adult prophy) instead,
and advise manual claim if user insists on D1120
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- parseSrpCode: recognize "D4341 UL" / "4341 LR" etc., store quadrant in quad field
- matchOne: auto-prefix D for 4-digit inputs like "0120" → D0120
- LLM prompt: keep SRP code and quadrant together as one procedureName entry
- CdtMatch / CdtResult: add quad field, thread through matchedCodes action data
- claim-form.tsx: include quad in chatbot_claim_prefill type and spread to service line
- selenium_claimSubmitWorker.py: pass quad to fill_service_line, select quadrant
dropdown by index (UR=1, UL=2, LL=3, LR=4) matching MassHealth form structure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pass the user's primary NPI provider name through the eligibility and
claim routes so the Selenium workers click the matching option in the
DDMA member-search provider dropdown (data-testid=member-search_provider_select-btn)
rather than always falling back to the first entry.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AI chat extracts 'with provider <name>' and routes claim to that provider
- Claim form reads provider from sessionStorage before any async effects run,
preventing saved claim/procedure data from overriding the chatbot selection
- NPI provider settings table shows Provider #1 / #2 labels with up/down
reorder buttons; Provider #1 is always the default for claims
- Default provider now uses sortOrder instead of hardcoded 'Mary Scannell'
- Added sortOrder column to NpiProvider schema with migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Claim file uploads (chatbot or manual) now save to both the Cloud
Storage patient folder and the Documents page via new
POST /api/claims/upload-to-cloud endpoint
- MH submit flow now calls uploadAttachmentsToLocalFolder (same as
DDMA/United/Tufts) so chatbot-attached X-rays are persisted
- Removed old /upload-attachments disk route and attachmentDiskStorage
multer config; deleted uploads/patients/ folder
- uploadAttachmentsToLocalFolder now points to /upload-to-cloud and
sends patientId so the backend can create the patient folder
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
UI-only stub — logic to be defined. Mirrors the existing Claim for
Column section with its own column checkboxes and loading state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The original migration only created the table with id/userId/apiKey.
All provider keys, models, toggles, and feature flags were in the
schema but never added to the database, causing every AI settings
save to fail with a Prisma column-not-found error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove auto-appending of "Appointment with [staff name]" to notes on
save, and preserve existing notes when dragging an appointment to a
new slot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add "Eligibility & Appointment" button to chatbot eligibility-id-ready card
- For known patients: creates today's appointment immediately, then opens eligibility page
- For unknown patients: navigates to eligibility page; after Selenium creates the patient,
auto-creates appointment via tryAppointmentFromChatbot on the insurance-status page
- Update MH Eligibility & Appointment button to create a today's schedule slot instead of
navigating to the appointments page; shows PDF preview on completion
- createAppointmentToday falls back from Column A to Column B when Column A is full;
returns column label in response so UI can display it
- Set AI-scheduled appointment duration to 15 minutes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Daily sync and Sync Now both pull database + uploads in one operation.
PC1 streams uploads/ as a zip via GET /network-backup-files (archiver).
PC2 clears cloud-storage, patients, and patient-documents then extracts
the fresh copy before resolving. Timeout extended to 5 min for large files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PC2 can now automatically pull and restore a fresh copy of PC1's database
on a daily schedule. Config and API key are stored in local JSON files so
they survive database restores.
- New networkSyncConfigService: file-based config (network-backup-key.json,
network-sync-config.json) that persists through DB restores
- New networkSyncService: streams live pg_dump from source PC over HTTP and
pipes into psql, then reconnects Prisma and applies missing migrations
- 6 new endpoints: get/regenerate API key, serve backup stream (key-auth
only), get/save sync config, trigger immediate sync
- Hourly cron job that fires only when current hour matches configured syncHour
- NetworkBackupManager component: shows this machine's key (show/copy/regen)
and receiver config (enable toggle, hour picker 0-23, source URL + key,
Save + Sync Now, last sync status)
- README setup guide for both PCs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
"United Healthcare SCO" does not contain the substring "united sco" so
deriveSiteKey was falling through to the MH default. Add exact and prefix
aliases so any United Healthcare variant maps to UNITED_SCO.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
extractToothSurface now handles A-T primary tooth letters in addition to
numeric #1-32. strippedCleaned strips both formats so "D7111 # H" reduces
to "D7111" for the CDT pass-through. Pass-through no longer returns null
for codes not in the fee schedule JSON.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Chatbot: add paperclip button to attach X-ray/PDF files to claim submissions;
files flow through chatbotFileStore into claim-form uploadedFiles for Selenium
- CDT lookup: auto-select D3310/D3320/D3330 by tooth number for RCT; strip #NN
from procedure names before alias lookup so "1 pa, #3" → D0220 tooth 3;
add "1 pa" alias for D0220; expand multi-PA notation via AI prompt rule
- AI classifier: add navigate_eligibility intent ("check mh" → /insurance-status);
fix duplicate intent entry; add RCT and multi-PA prompt rules
- Check+claim flow: pass serviceDate through check_and_claim_ready actionData;
tryClaimFromChatbot skips PDF preview and navigates straight to claims with
memberId fallback lookup; wired into all provider onPdfReady callbacks
- Claims table: add Service Date column between Patient Name and Submission Date
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
siteKeyToAutoCheck now accepts an optional dob parameter. When siteKey is MH
and the patient is under 21 years old, returns "cmsp" so the AI chat triggers
the CMSP eligibility & history & remaining button instead of the adult MH one.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>