feat: clinic-wide AI (analytics/earnings/inventory + invoice-from-file),

real Live card, persistent chat history

Analytics & earnings:
- Analytics now carries real money computed from invoices (billed/paid/
  outstanding + by-month); new Earnings section on the Analysis page drawn with
  the project's Bklit chart components (shared EarningsChart).

AI agent reaches the whole clinic:
- new read tools getClinicInfo / getAnalytics / listInventory render clinic,
  analytics (with a Bklit earnings chart) and inventory cards in chat
- proposeInvoice turns an uploaded purchase/medication list into an invoice
  (new "invoice" action-preview kind → createInvoice); invoices/appointments
  auto-create/link a patient (ensurePatient) so they hit the Patients page

Live card:
- plots real data — patients checked in today — via GET /api/analytics/live
  (polled); value pill clamped and margins widened so nothing spills the card

Persistent AI chat history (Claude-style):
- ai_chat_threads + ai_chat_messages (migration 0016); per-user, org-scoped
  thread CRUD under /api/chat/threads
- chat panel owns a thread id, loads /?thread=<id>, and auto-saves after each
  exchange; sidebar lists past chats (open/delete), "New chat" starts fresh

Verified with backend typecheck + frontend tsc + next build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-14 22:25:15 +03:00
parent b946dc9226
commit 3aa699aefe
27 changed files with 4274 additions and 61 deletions
+36 -3
View File
@@ -646,6 +646,14 @@
"newThisMonth": "New this month",
"active": "Active patients"
},
"earnings": {
"title": "Earnings",
"description": "Billed, paid and outstanding — from invoices",
"billed": "Total billed",
"paid": "Total paid",
"outstanding": "Outstanding",
"byMonth": "Billed vs paid, by month"
},
"appointments": {
"title": "Appointments & schedule",
"description": "Bookings, attendance and what's coming up",
@@ -773,6 +781,12 @@
"thinking": "Thinking…",
"steps": "Steps",
"reasoning": "Reasoning",
"history": {
"title": "Chats",
"untitled": "New chat",
"empty": "No saved chats yet.",
"delete": "Delete chat"
},
"suggestions": {
"schedule": "Show today's schedule",
"tasks": "List open tasks",
@@ -795,12 +809,14 @@
"title": {
"appointment": "Proposed appointment",
"task": "Proposed task",
"prescription": "Proposed prescription"
"prescription": "Proposed prescription",
"invoice": "Proposed invoice"
},
"kind": {
"appointment": "Appointment added.",
"task": "Task added.",
"prescription": "Prescription added."
"prescription": "Prescription added.",
"invoice": "Invoice added."
},
"approve": "Add",
"adding": "Adding…",
@@ -832,7 +848,24 @@
"done": "Done",
"noAppointments": "No appointments.",
"noTasks": "No tasks.",
"noPrescriptions": "No prescriptions."
"noPrescriptions": "No prescriptions.",
"inventory": "Inventory",
"noInventory": "No inventory items."
},
"clinicCard": {
"title": "Clinic",
"since": "Since {{date}}"
},
"analyticsCard": {
"title": "Clinic analytics",
"patients": "Patients",
"appointmentsThisWeek": "Appts this week",
"activePrescriptions": "Active Rx",
"openTasks": "Open tasks",
"billed": "Billed",
"paid": "Paid",
"outstanding": "Outstanding",
"byMonth": "Billed vs paid, by month"
},
"labCard": {
"flags": {