elevenlabs-webhook-nodejs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (969) hide show
  1. package/.claude/settings.local.json +27 -0
  2. package/.dockerignore +6 -0
  3. package/.env.example +43 -0
  4. package/BEFORE-PRODUCTION.md +32 -0
  5. package/Dockerfile +23 -0
  6. package/SYSTEM_OVERVIEW.md +942 -0
  7. package/SYSTEM_STATUS.md +332 -0
  8. package/backup_script/main.py +146 -0
  9. package/baileys/.dockerignore +7 -0
  10. package/baileys/Dockerfile +13 -0
  11. package/baileys/README.md +412 -0
  12. package/baileys/index.js +499 -0
  13. package/baileys/package-lock.json +2532 -0
  14. package/baileys/package.json +25 -0
  15. package/baileys/server.js +96 -0
  16. package/baileys/src/config.js +55 -0
  17. package/baileys/src/middleware/api-key.js +16 -0
  18. package/baileys/src/routes/accounts.js +51 -0
  19. package/baileys/src/routes/chats.js +103 -0
  20. package/baileys/src/routes/webhooks.js +34 -0
  21. package/baileys/src/services/account-store.js +259 -0
  22. package/baileys/src/services/webhook-dispatcher.js +161 -0
  23. package/baileys/src/services/worker-manager.js +597 -0
  24. package/baileys/src/utils/jid.js +79 -0
  25. package/baileys/src/utils/logger.js +16 -0
  26. package/baileys/src/utils/use-mongodb-auth-state.js +122 -0
  27. package/baileys/worker.js +721 -0
  28. package/dist/app.d.ts +1 -0
  29. package/dist/app.js +84 -0
  30. package/dist/app.js.map +1 -0
  31. package/dist/config/agentPrompts.json +19 -0
  32. package/dist/config/database.d.ts +1 -0
  33. package/dist/config/database.js +26 -0
  34. package/dist/config/database.js.map +1 -0
  35. package/dist/config/env.d.ts +41 -0
  36. package/dist/config/env.js +81 -0
  37. package/dist/config/env.js.map +1 -0
  38. package/dist/config/index.d.ts +3 -0
  39. package/dist/config/index.js +73 -0
  40. package/dist/config/index.js.map +1 -0
  41. package/dist/controllers/webhook.controller.d.ts +10 -0
  42. package/dist/controllers/webhook.controller.js +128 -0
  43. package/dist/controllers/webhook.controller.js.map +1 -0
  44. package/dist/errors/index.d.ts +4 -0
  45. package/dist/errors/index.js +13 -0
  46. package/dist/errors/index.js.map +1 -0
  47. package/dist/hooks/webhookValidator.d.ts +2 -0
  48. package/dist/hooks/webhookValidator.js +47 -0
  49. package/dist/hooks/webhookValidator.js.map +1 -0
  50. package/dist/index.d.ts +1 -0
  51. package/dist/index.js +55 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/migrations/001_session-architecture.d.ts +3 -0
  54. package/dist/migrations/001_session-architecture.js +119 -0
  55. package/dist/migrations/001_session-architecture.js.map +1 -0
  56. package/dist/migrations/002_agent-ref.d.ts +3 -0
  57. package/dist/migrations/002_agent-ref.js +55 -0
  58. package/dist/migrations/002_agent-ref.js.map +1 -0
  59. package/dist/migrations/003_shift-schedule.d.ts +3 -0
  60. package/dist/migrations/003_shift-schedule.js +48 -0
  61. package/dist/migrations/003_shift-schedule.js.map +1 -0
  62. package/dist/migrations/004_invert-shift-to-clinic-hours.d.ts +3 -0
  63. package/dist/migrations/004_invert-shift-to-clinic-hours.js +27 -0
  64. package/dist/migrations/004_invert-shift-to-clinic-hours.js.map +1 -0
  65. package/dist/migrations/005_composite-baileys-chat-ids.d.ts +3 -0
  66. package/dist/migrations/005_composite-baileys-chat-ids.js +47 -0
  67. package/dist/migrations/005_composite-baileys-chat-ids.js.map +1 -0
  68. package/dist/migrations/migration.model.d.ts +18 -0
  69. package/dist/migrations/migration.model.js +45 -0
  70. package/dist/migrations/migration.model.js.map +1 -0
  71. package/dist/migrations/migration.routes.d.ts +2 -0
  72. package/dist/migrations/migration.routes.js +37 -0
  73. package/dist/migrations/migration.routes.js.map +1 -0
  74. package/dist/migrations/migration.runner.d.ts +19 -0
  75. package/dist/migrations/migration.runner.js +74 -0
  76. package/dist/migrations/migration.runner.js.map +1 -0
  77. package/dist/models/ConversationClaim.d.ts +13 -0
  78. package/dist/models/ConversationClaim.js +44 -0
  79. package/dist/models/ConversationClaim.js.map +1 -0
  80. package/dist/models/ConversationEvaluation.d.ts +23 -0
  81. package/dist/models/ConversationEvaluation.js +92 -0
  82. package/dist/models/ConversationEvaluation.js.map +1 -0
  83. package/dist/models/Summary.d.ts +37 -0
  84. package/dist/models/Summary.js +78 -0
  85. package/dist/models/Summary.js.map +1 -0
  86. package/dist/models/Transcription.d.ts +34 -0
  87. package/dist/models/Transcription.js +71 -0
  88. package/dist/models/Transcription.js.map +1 -0
  89. package/dist/models/WhatsAppRecipient.d.ts +23 -0
  90. package/dist/models/WhatsAppRecipient.js +53 -0
  91. package/dist/models/WhatsAppRecipient.js.map +1 -0
  92. package/dist/modules/admin/admin.routes.d.ts +2 -0
  93. package/dist/modules/admin/admin.routes.js +1966 -0
  94. package/dist/modules/admin/admin.routes.js.map +1 -0
  95. package/dist/modules/admin/elevenlabs-test-chat.routes.d.ts +2 -0
  96. package/dist/modules/admin/elevenlabs-test-chat.routes.js +158 -0
  97. package/dist/modules/admin/elevenlabs-test-chat.routes.js.map +1 -0
  98. package/dist/modules/admin/whatsapp-test-chat.routes.d.ts +2 -0
  99. package/dist/modules/admin/whatsapp-test-chat.routes.js +204 -0
  100. package/dist/modules/admin/whatsapp-test-chat.routes.js.map +1 -0
  101. package/dist/modules/agents/agent.model.d.ts +38 -0
  102. package/dist/modules/agents/agent.model.js +92 -0
  103. package/dist/modules/agents/agent.model.js.map +1 -0
  104. package/dist/modules/agents/agent.routes.d.ts +2 -0
  105. package/dist/modules/agents/agent.routes.js +61 -0
  106. package/dist/modules/agents/agent.routes.js.map +1 -0
  107. package/dist/modules/appointment-validation/appointment-validation.model.d.ts +76 -0
  108. package/dist/modules/appointment-validation/appointment-validation.model.js +118 -0
  109. package/dist/modules/appointment-validation/appointment-validation.model.js.map +1 -0
  110. package/dist/modules/appointment-validation/appointment-validation.routes.d.ts +2 -0
  111. package/dist/modules/appointment-validation/appointment-validation.routes.js +202 -0
  112. package/dist/modules/appointment-validation/appointment-validation.routes.js.map +1 -0
  113. package/dist/modules/appointment-validation/appointment-validation.service.d.ts +53 -0
  114. package/dist/modules/appointment-validation/appointment-validation.service.js +827 -0
  115. package/dist/modules/appointment-validation/appointment-validation.service.js.map +1 -0
  116. package/dist/modules/auth/auth.model.d.ts +17 -0
  117. package/dist/modules/auth/auth.model.js +64 -0
  118. package/dist/modules/auth/auth.model.js.map +1 -0
  119. package/dist/modules/auth/auth.routes.d.ts +2 -0
  120. package/dist/modules/auth/auth.routes.js +202 -0
  121. package/dist/modules/auth/auth.routes.js.map +1 -0
  122. package/dist/modules/auth/auth.service.d.ts +28 -0
  123. package/dist/modules/auth/auth.service.js +183 -0
  124. package/dist/modules/auth/auth.service.js.map +1 -0
  125. package/dist/modules/auth/refresh-token.model.d.ts +13 -0
  126. package/dist/modules/auth/refresh-token.model.js +52 -0
  127. package/dist/modules/auth/refresh-token.model.js.map +1 -0
  128. package/dist/modules/billing/billing-alert.model.d.ts +16 -0
  129. package/dist/modules/billing/billing-alert.model.js +47 -0
  130. package/dist/modules/billing/billing-alert.model.js.map +1 -0
  131. package/dist/modules/billing/billing-period-snapshot.model.d.ts +35 -0
  132. package/dist/modules/billing/billing-period-snapshot.model.js +68 -0
  133. package/dist/modules/billing/billing-period-snapshot.model.js.map +1 -0
  134. package/dist/modules/billing/billing.model.d.ts +18 -0
  135. package/dist/modules/billing/billing.model.js +62 -0
  136. package/dist/modules/billing/billing.model.js.map +1 -0
  137. package/dist/modules/billing/billing.routes.d.ts +2 -0
  138. package/dist/modules/billing/billing.routes.js +63 -0
  139. package/dist/modules/billing/billing.routes.js.map +1 -0
  140. package/dist/modules/billing/billing.service.d.ts +69 -0
  141. package/dist/modules/billing/billing.service.js +498 -0
  142. package/dist/modules/billing/billing.service.js.map +1 -0
  143. package/dist/modules/billing/payment.model.d.ts +24 -0
  144. package/dist/modules/billing/payment.model.js +57 -0
  145. package/dist/modules/billing/payment.model.js.map +1 -0
  146. package/dist/modules/calls/call.model.d.ts +41 -0
  147. package/dist/modules/calls/call.model.js +97 -0
  148. package/dist/modules/calls/call.model.js.map +1 -0
  149. package/dist/modules/calls/call.routes.d.ts +2 -0
  150. package/dist/modules/calls/call.routes.js +103 -0
  151. package/dist/modules/calls/call.routes.js.map +1 -0
  152. package/dist/modules/campaigns/campaign.model.d.ts +45 -0
  153. package/dist/modules/campaigns/campaign.model.js +98 -0
  154. package/dist/modules/campaigns/campaign.model.js.map +1 -0
  155. package/dist/modules/campaigns/campaign.routes.d.ts +2 -0
  156. package/dist/modules/campaigns/campaign.routes.js +323 -0
  157. package/dist/modules/campaigns/campaign.routes.js.map +1 -0
  158. package/dist/modules/campaigns/campaign.service.d.ts +11 -0
  159. package/dist/modules/campaigns/campaign.service.js +86 -0
  160. package/dist/modules/campaigns/campaign.service.js.map +1 -0
  161. package/dist/modules/google-calendar/google-calendar.routes.d.ts +2 -0
  162. package/dist/modules/google-calendar/google-calendar.routes.js +32 -0
  163. package/dist/modules/google-calendar/google-calendar.routes.js.map +1 -0
  164. package/dist/modules/inbound-call/inbound-call-config.model.d.ts +20 -0
  165. package/dist/modules/inbound-call/inbound-call-config.model.js +68 -0
  166. package/dist/modules/inbound-call/inbound-call-config.model.js.map +1 -0
  167. package/dist/modules/inbound-call/inbound-call.routes.d.ts +2 -0
  168. package/dist/modules/inbound-call/inbound-call.routes.js +243 -0
  169. package/dist/modules/inbound-call/inbound-call.routes.js.map +1 -0
  170. package/dist/modules/leads/lead.model.d.ts +24 -0
  171. package/dist/modules/leads/lead.model.js +54 -0
  172. package/dist/modules/leads/lead.model.js.map +1 -0
  173. package/dist/modules/leads/lead.routes.d.ts +2 -0
  174. package/dist/modules/leads/lead.routes.js +201 -0
  175. package/dist/modules/leads/lead.routes.js.map +1 -0
  176. package/dist/modules/plans/plan.model.d.ts +25 -0
  177. package/dist/modules/plans/plan.model.js +59 -0
  178. package/dist/modules/plans/plan.model.js.map +1 -0
  179. package/dist/modules/surveys/survey.model.d.ts +30 -0
  180. package/dist/modules/surveys/survey.model.js +75 -0
  181. package/dist/modules/surveys/survey.model.js.map +1 -0
  182. package/dist/modules/surveys/survey.routes.d.ts +2 -0
  183. package/dist/modules/surveys/survey.routes.js +153 -0
  184. package/dist/modules/surveys/survey.routes.js.map +1 -0
  185. package/dist/modules/tenants/tenant.model.d.ts +86 -0
  186. package/dist/modules/tenants/tenant.model.js +127 -0
  187. package/dist/modules/tenants/tenant.model.js.map +1 -0
  188. package/dist/modules/tenants/tenant.routes.d.ts +2 -0
  189. package/dist/modules/tenants/tenant.routes.js +65 -0
  190. package/dist/modules/tenants/tenant.routes.js.map +1 -0
  191. package/dist/modules/users/user.routes.d.ts +2 -0
  192. package/dist/modules/users/user.routes.js +106 -0
  193. package/dist/modules/users/user.routes.js.map +1 -0
  194. package/dist/modules/webhooks/elevenlabs-tool.routes.d.ts +20 -0
  195. package/dist/modules/webhooks/elevenlabs-tool.routes.js +85 -0
  196. package/dist/modules/webhooks/elevenlabs-tool.routes.js.map +1 -0
  197. package/dist/modules/webhooks/elevenlabs-tool.service.d.ts +11 -0
  198. package/dist/modules/webhooks/elevenlabs-tool.service.js +360 -0
  199. package/dist/modules/webhooks/elevenlabs-tool.service.js.map +1 -0
  200. package/dist/modules/webhooks/elevenlabs.routes.d.ts +2 -0
  201. package/dist/modules/webhooks/elevenlabs.routes.js +34 -0
  202. package/dist/modules/webhooks/elevenlabs.routes.js.map +1 -0
  203. package/dist/modules/webhooks/elevenlabs.service.d.ts +6 -0
  204. package/dist/modules/webhooks/elevenlabs.service.js +512 -0
  205. package/dist/modules/webhooks/elevenlabs.service.js.map +1 -0
  206. package/dist/modules/webhooks/unipile.routes.d.ts +2 -0
  207. package/dist/modules/webhooks/unipile.routes.js +780 -0
  208. package/dist/modules/webhooks/unipile.routes.js.map +1 -0
  209. package/dist/modules/whatsapp/appointment.model.d.ts +27 -0
  210. package/dist/modules/whatsapp/appointment.model.js +58 -0
  211. package/dist/modules/whatsapp/appointment.model.js.map +1 -0
  212. package/dist/modules/whatsapp/operator-request.model.d.ts +29 -0
  213. package/dist/modules/whatsapp/operator-request.model.js +65 -0
  214. package/dist/modules/whatsapp/operator-request.model.js.map +1 -0
  215. package/dist/modules/whatsapp/stt-usage.model.d.ts +16 -0
  216. package/dist/modules/whatsapp/stt-usage.model.js +53 -0
  217. package/dist/modules/whatsapp/stt-usage.model.js.map +1 -0
  218. package/dist/modules/whatsapp/whatsapp-chat.model.d.ts +23 -0
  219. package/dist/modules/whatsapp/whatsapp-chat.model.js +55 -0
  220. package/dist/modules/whatsapp/whatsapp-chat.model.js.map +1 -0
  221. package/dist/modules/whatsapp/whatsapp-contact-profile.model.d.ts +23 -0
  222. package/dist/modules/whatsapp/whatsapp-contact-profile.model.js +54 -0
  223. package/dist/modules/whatsapp/whatsapp-contact-profile.model.js.map +1 -0
  224. package/dist/modules/whatsapp/whatsapp-message.model.d.ts +30 -0
  225. package/dist/modules/whatsapp/whatsapp-message.model.js +52 -0
  226. package/dist/modules/whatsapp/whatsapp-message.model.js.map +1 -0
  227. package/dist/modules/whatsapp/whatsapp-session.model.d.ts +33 -0
  228. package/dist/modules/whatsapp/whatsapp-session.model.js +65 -0
  229. package/dist/modules/whatsapp/whatsapp-session.model.js.map +1 -0
  230. package/dist/modules/whatsapp/whatsapp.routes.d.ts +2 -0
  231. package/dist/modules/whatsapp/whatsapp.routes.js +1237 -0
  232. package/dist/modules/whatsapp/whatsapp.routes.js.map +1 -0
  233. package/dist/plugins/cors.d.ts +3 -0
  234. package/dist/plugins/cors.js +11 -0
  235. package/dist/plugins/cors.js.map +1 -0
  236. package/dist/plugins/jwt.d.ts +3 -0
  237. package/dist/plugins/jwt.js +22 -0
  238. package/dist/plugins/jwt.js.map +1 -0
  239. package/dist/plugins/rawBody.d.ts +3 -0
  240. package/dist/plugins/rawBody.js +16 -0
  241. package/dist/plugins/rawBody.js.map +1 -0
  242. package/dist/plugins/rbac.d.ts +5 -0
  243. package/dist/plugins/rbac.js +29 -0
  244. package/dist/plugins/rbac.js.map +1 -0
  245. package/dist/routes/admin.routes.d.ts +2 -0
  246. package/dist/routes/admin.routes.js +169 -0
  247. package/dist/routes/admin.routes.js.map +1 -0
  248. package/dist/routes/health.routes.d.ts +2 -0
  249. package/dist/routes/health.routes.js +16 -0
  250. package/dist/routes/health.routes.js.map +1 -0
  251. package/dist/routes/webhook.routes.d.ts +2 -0
  252. package/dist/routes/webhook.routes.js +17 -0
  253. package/dist/routes/webhook.routes.js.map +1 -0
  254. package/dist/services/ai/base.ai.d.ts +19 -0
  255. package/dist/services/ai/base.ai.js +120 -0
  256. package/dist/services/ai/base.ai.js.map +1 -0
  257. package/dist/services/ai/gemini.service.d.ts +11 -0
  258. package/dist/services/ai/gemini.service.js +43 -0
  259. package/dist/services/ai/gemini.service.js.map +1 -0
  260. package/dist/services/ai/index.d.ts +2 -0
  261. package/dist/services/ai/index.js +26 -0
  262. package/dist/services/ai/index.js.map +1 -0
  263. package/dist/services/ai/openai.service.d.ts +11 -0
  264. package/dist/services/ai/openai.service.js +50 -0
  265. package/dist/services/ai/openai.service.js.map +1 -0
  266. package/dist/services/elevenlabs.service.d.ts +52 -0
  267. package/dist/services/elevenlabs.service.js +447 -0
  268. package/dist/services/elevenlabs.service.js.map +1 -0
  269. package/dist/services/google-calendar.service.d.ts +60 -0
  270. package/dist/services/google-calendar.service.js +494 -0
  271. package/dist/services/google-calendar.service.js.map +1 -0
  272. package/dist/services/inbound-call-schedule.service.d.ts +11 -0
  273. package/dist/services/inbound-call-schedule.service.js +162 -0
  274. package/dist/services/inbound-call-schedule.service.js.map +1 -0
  275. package/dist/services/netgsm.service.d.ts +41 -0
  276. package/dist/services/netgsm.service.js +89 -0
  277. package/dist/services/netgsm.service.js.map +1 -0
  278. package/dist/services/unipile.service.d.ts +41 -0
  279. package/dist/services/unipile.service.js +149 -0
  280. package/dist/services/unipile.service.js.map +1 -0
  281. package/dist/services/whatsapp-agent.service.d.ts +139 -0
  282. package/dist/services/whatsapp-agent.service.js +2055 -0
  283. package/dist/services/whatsapp-agent.service.js.map +1 -0
  284. package/dist/services/whatsapp.service.d.ts +26 -0
  285. package/dist/services/whatsapp.service.js +206 -0
  286. package/dist/services/whatsapp.service.js.map +1 -0
  287. package/dist/templates/index.d.ts +39 -0
  288. package/dist/templates/index.js +35 -0
  289. package/dist/templates/index.js.map +1 -0
  290. package/dist/templates/receptionist.d.ts +2 -0
  291. package/dist/templates/receptionist.js +39 -0
  292. package/dist/templates/receptionist.js.map +1 -0
  293. package/dist/templates/survey.d.ts +2 -0
  294. package/dist/templates/survey.js +41 -0
  295. package/dist/templates/survey.js.map +1 -0
  296. package/dist/types/index.d.ts +173 -0
  297. package/dist/types/index.js +3 -0
  298. package/dist/types/index.js.map +1 -0
  299. package/dist/utils/logger.d.ts +3 -0
  300. package/dist/utils/logger.js +105 -0
  301. package/dist/utils/logger.js.map +1 -0
  302. package/docker-compose.nestjs.yml +89 -0
  303. package/docker-compose.yml +78 -0
  304. package/docs/AI_AGENT_ENHANCEMENT_PLAN.md +164 -0
  305. package/docs/API.md +1193 -0
  306. package/docs/API_ENDPOINTS.md +344 -0
  307. package/docs/ARCHITECTURE.md +305 -0
  308. package/docs/AUTH_API.md +252 -0
  309. package/docs/BILLING_SMS_ALERTS.md +94 -0
  310. package/docs/CHAT_ASSIGNMENT_SYSTEM.md +118 -0
  311. package/docs/CLIENT_TOOLS_AND_FEATURES.md +337 -0
  312. package/docs/ELEVENLABS_WEBHOOK_TOOLS.md +644 -0
  313. package/docs/FRONTEND_CHECKLIST.md +227 -0
  314. package/docs/IMPLEMENTATION_STATUS.md +470 -0
  315. package/docs/MIGRATION_GUIDE.md +96 -0
  316. package/docs/MISSINGS_REPORT.md +507 -0
  317. package/docs/NESTJS_MIGRATION_REFERENCE.md +5136 -0
  318. package/docs/PROJECT_DESCRIPTION.md +1038 -0
  319. package/docs/SCALING.md +148 -0
  320. package/docs/SESSION_SUMMARY_2026_03_17.md +135 -0
  321. package/docs/WHATSAPP_AGENT.md +1086 -0
  322. package/docs/architecture/00-SYSTEM-OVERVIEW.md +318 -0
  323. package/docs/architecture/01-DATABASE-SCHEMA.md +2564 -0
  324. package/docs/architecture/02-AUTHENTICATION.md +1040 -0
  325. package/docs/architecture/03-MULTI-CLINIC.md +742 -0
  326. package/docs/architecture/04-WHATSAPP-AGENT.md +608 -0
  327. package/docs/architecture/05-OPERATOR-WORKFLOW.md +444 -0
  328. package/docs/architecture/06-BAILEYS-MICROSERVICE.md +616 -0
  329. package/docs/architecture/07-APPOINTMENTS.md +849 -0
  330. package/docs/architecture/08-VOICE-CALLS.md +470 -0
  331. package/docs/architecture/09-OUTBOUND-CAMPAIGNS.md +542 -0
  332. package/docs/architecture/10-CLIENT-TOOLS.md +665 -0
  333. package/docs/architecture/11-BILLING.md +458 -0
  334. package/docs/architecture/12-SECURITY.md +216 -0
  335. package/docs/architecture/13-LOGGING-AUDIT.md +549 -0
  336. package/docs/architecture/14-META-BUSINESS-API.md +454 -0
  337. package/docs/architecture/15-AI-MODULE.md +479 -0
  338. package/docs/architecture/16-BACKGROUND-JOBS.md +469 -0
  339. package/docs/architecture/17-REALTIME-LIVECHAT.md +447 -0
  340. package/docs/architecture/18-FILE-STORAGE.md +410 -0
  341. package/docs/architecture/19-PATIENTS.md +1034 -0
  342. package/docs/architecture/20-TREATMENTS-AND-PLANS.md +774 -0
  343. package/docs/architecture/21-BEFORE-AFTER-PHOTOS.md +519 -0
  344. package/docs/database.md +456 -0
  345. package/docs/ornek-randevu-onay.csv +3 -0
  346. package/ecosystem.config.js +16 -0
  347. package/elevenlabs-convai-api-reference.md +1171 -0
  348. package/frontend/.dockerignore +2 -0
  349. package/frontend/Dockerfile +24 -0
  350. package/frontend/README.md +75 -0
  351. package/frontend/components.json +25 -0
  352. package/frontend/eslint.config.js +23 -0
  353. package/frontend/index.html +13 -0
  354. package/frontend/nginx.conf +37 -0
  355. package/frontend/package-lock.json +8709 -0
  356. package/frontend/package.json +71 -0
  357. package/frontend/public/favicon.svg +1 -0
  358. package/frontend/public/icons.svg +24 -0
  359. package/frontend/src/App.tsx +125 -0
  360. package/frontend/src/components/error-boundary.tsx +50 -0
  361. package/frontend/src/components/shared/activity-timeline.tsx +66 -0
  362. package/frontend/src/components/shared/appointment-calendar.css +80 -0
  363. package/frontend/src/components/shared/appointment-calendar.tsx +245 -0
  364. package/frontend/src/components/shared/chat-bubble.tsx +72 -0
  365. package/frontend/src/components/shared/combobox.tsx +119 -0
  366. package/frontend/src/components/shared/confirm-dialog.tsx +57 -0
  367. package/frontend/src/components/shared/data-table-pagination.tsx +97 -0
  368. package/frontend/src/components/shared/data-table-toolbar.tsx +39 -0
  369. package/frontend/src/components/shared/empty-state.tsx +27 -0
  370. package/frontend/src/components/shared/file-upload.tsx +140 -0
  371. package/frontend/src/components/shared/index.ts +20 -0
  372. package/frontend/src/components/shared/language-switcher.tsx +29 -0
  373. package/frontend/src/components/shared/notification-dropdown.tsx +115 -0
  374. package/frontend/src/components/shared/page-header.tsx +23 -0
  375. package/frontend/src/components/shared/stat-card.tsx +37 -0
  376. package/frontend/src/components/shared/status-badge.tsx +70 -0
  377. package/frontend/src/components/shared/status-dot.tsx +43 -0
  378. package/frontend/src/components/ui/alert-dialog.tsx +187 -0
  379. package/frontend/src/components/ui/alert.tsx +76 -0
  380. package/frontend/src/components/ui/avatar.tsx +109 -0
  381. package/frontend/src/components/ui/badge.tsx +52 -0
  382. package/frontend/src/components/ui/breadcrumb.tsx +125 -0
  383. package/frontend/src/components/ui/button.tsx +60 -0
  384. package/frontend/src/components/ui/calendar.tsx +219 -0
  385. package/frontend/src/components/ui/card.tsx +103 -0
  386. package/frontend/src/components/ui/chart.tsx +371 -0
  387. package/frontend/src/components/ui/checkbox.tsx +29 -0
  388. package/frontend/src/components/ui/collapsible.tsx +19 -0
  389. package/frontend/src/components/ui/command.tsx +194 -0
  390. package/frontend/src/components/ui/dialog.tsx +158 -0
  391. package/frontend/src/components/ui/dropdown-menu.tsx +268 -0
  392. package/frontend/src/components/ui/input-group.tsx +156 -0
  393. package/frontend/src/components/ui/input.tsx +20 -0
  394. package/frontend/src/components/ui/label.tsx +20 -0
  395. package/frontend/src/components/ui/pagination.tsx +130 -0
  396. package/frontend/src/components/ui/popover.tsx +90 -0
  397. package/frontend/src/components/ui/progress.tsx +83 -0
  398. package/frontend/src/components/ui/radio-group.tsx +36 -0
  399. package/frontend/src/components/ui/scroll-area.tsx +54 -0
  400. package/frontend/src/components/ui/select.tsx +199 -0
  401. package/frontend/src/components/ui/separator.tsx +23 -0
  402. package/frontend/src/components/ui/sheet.tsx +138 -0
  403. package/frontend/src/components/ui/sidebar.tsx +723 -0
  404. package/frontend/src/components/ui/skeleton.tsx +13 -0
  405. package/frontend/src/components/ui/sonner.tsx +47 -0
  406. package/frontend/src/components/ui/switch.tsx +30 -0
  407. package/frontend/src/components/ui/table.tsx +114 -0
  408. package/frontend/src/components/ui/tabs.tsx +82 -0
  409. package/frontend/src/components/ui/textarea.tsx +18 -0
  410. package/frontend/src/components/ui/toggle-group.tsx +89 -0
  411. package/frontend/src/components/ui/toggle.tsx +43 -0
  412. package/frontend/src/components/ui/tooltip.tsx +64 -0
  413. package/frontend/src/hooks/use-mobile.ts +19 -0
  414. package/frontend/src/i18n/index.ts +20 -0
  415. package/frontend/src/i18n/locales/en.json +786 -0
  416. package/frontend/src/i18n/locales/tr.json +786 -0
  417. package/frontend/src/index.css +134 -0
  418. package/frontend/src/layouts/admin-layout.tsx +111 -0
  419. package/frontend/src/layouts/app-header.tsx +130 -0
  420. package/frontend/src/layouts/app-layout.tsx +19 -0
  421. package/frontend/src/layouts/app-sidebar.tsx +212 -0
  422. package/frontend/src/layouts/auth-guard.tsx +31 -0
  423. package/frontend/src/layouts/mobile-sidebar.tsx +120 -0
  424. package/frontend/src/lib/api.ts +68 -0
  425. package/frontend/src/lib/hooks/use-appointments.ts +224 -0
  426. package/frontend/src/lib/hooks/use-availability-blocks.ts +83 -0
  427. package/frontend/src/lib/hooks/use-chats.ts +236 -0
  428. package/frontend/src/lib/hooks/use-clinic-detail.ts +171 -0
  429. package/frontend/src/lib/hooks/use-clinics.ts +37 -0
  430. package/frontend/src/lib/hooks/use-doctor-calendar.ts +80 -0
  431. package/frontend/src/lib/hooks/use-examinations.ts +89 -0
  432. package/frontend/src/lib/hooks/use-medical-history.ts +52 -0
  433. package/frontend/src/lib/hooks/use-patients.ts +296 -0
  434. package/frontend/src/lib/hooks/use-photo-sets.ts +118 -0
  435. package/frontend/src/lib/hooks/use-treatment-plans.ts +152 -0
  436. package/frontend/src/lib/hooks/use-treatments.ts +125 -0
  437. package/frontend/src/lib/hooks/use-users.ts +172 -0
  438. package/frontend/src/lib/utils.ts +6 -0
  439. package/frontend/src/main.tsx +17 -0
  440. package/frontend/src/pages/admin/agents/detail.tsx +774 -0
  441. package/frontend/src/pages/admin/agents/import.tsx +280 -0
  442. package/frontend/src/pages/admin/agents/index.tsx +245 -0
  443. package/frontend/src/pages/admin/ai-playground.tsx +543 -0
  444. package/frontend/src/pages/appointments/create-appointment-dialog.tsx +390 -0
  445. package/frontend/src/pages/appointments/index.tsx +860 -0
  446. package/frontend/src/pages/audit/index.tsx +24 -0
  447. package/frontend/src/pages/auth/login.tsx +194 -0
  448. package/frontend/src/pages/billing/index.tsx +24 -0
  449. package/frontend/src/pages/calendar/index.tsx +704 -0
  450. package/frontend/src/pages/calendar-connections/index.tsx +295 -0
  451. package/frontend/src/pages/calls/index.tsx +24 -0
  452. package/frontend/src/pages/campaigns/index.tsx +24 -0
  453. package/frontend/src/pages/chats/index.tsx +981 -0
  454. package/frontend/src/pages/clinics/index.tsx +224 -0
  455. package/frontend/src/pages/clinics/settings.tsx +412 -0
  456. package/frontend/src/pages/components-showcase.tsx +773 -0
  457. package/frontend/src/pages/connections/index.tsx +328 -0
  458. package/frontend/src/pages/dashboard.tsx +50 -0
  459. package/frontend/src/pages/leads/index.tsx +24 -0
  460. package/frontend/src/pages/my-schedule/index.tsx +496 -0
  461. package/frontend/src/pages/patients/create-patient-dialog.tsx +358 -0
  462. package/frontend/src/pages/patients/detail.tsx +1195 -0
  463. package/frontend/src/pages/patients/edit-patient-dialog.tsx +387 -0
  464. package/frontend/src/pages/patients/examinations-tab.tsx +460 -0
  465. package/frontend/src/pages/patients/index.tsx +381 -0
  466. package/frontend/src/pages/patients/medical-history-dialog.tsx +207 -0
  467. package/frontend/src/pages/patients/photo-sets-tab.tsx +616 -0
  468. package/frontend/src/pages/patients/timeline-tab.tsx +164 -0
  469. package/frontend/src/pages/patients/treatment-plans-tab.tsx +598 -0
  470. package/frontend/src/pages/phone-numbers/detail.tsx +427 -0
  471. package/frontend/src/pages/phone-numbers/index.tsx +455 -0
  472. package/frontend/src/pages/platform/index.tsx +454 -0
  473. package/frontend/src/pages/settings/index.tsx +126 -0
  474. package/frontend/src/pages/treatments/index.tsx +487 -0
  475. package/frontend/src/pages/users/doctor-profile.tsx +672 -0
  476. package/frontend/src/pages/users/edit.tsx +329 -0
  477. package/frontend/src/pages/users/index.tsx +407 -0
  478. package/frontend/src/pages/validation/index.tsx +24 -0
  479. package/frontend/src/stores/auth.store.ts +108 -0
  480. package/frontend/src/stores/ui.store.ts +41 -0
  481. package/frontend/tsconfig.app.json +32 -0
  482. package/frontend/tsconfig.json +13 -0
  483. package/frontend/tsconfig.node.json +26 -0
  484. package/frontend/vite.config.ts +29 -0
  485. package/nestjs/.dockerignore +5 -0
  486. package/nestjs/.env.docker +64 -0
  487. package/nestjs/.prettierrc +4 -0
  488. package/nestjs/Dockerfile +36 -0
  489. package/nestjs/README.md +98 -0
  490. package/nestjs/eslint.config.mjs +35 -0
  491. package/nestjs/nest-cli.json +8 -0
  492. package/nestjs/package-lock.json +13390 -0
  493. package/nestjs/package.json +114 -0
  494. package/nestjs/prisma/migrations/20260409161536_add_message_metadata_fields/migration.sql +1746 -0
  495. package/nestjs/prisma/migrations/20260410140436_add_agent_ai_fields/migration.sql +36 -0
  496. package/nestjs/prisma/migrations/20260410175519_add_agent_clinic_assignments/migration.sql +21 -0
  497. package/nestjs/prisma/migrations/20260412094344_make_agent_tenant_optional/migration.sql +2 -0
  498. package/nestjs/prisma/migrations/20260412110008_add_admin_chat_sessions/migration.sql +47 -0
  499. package/nestjs/prisma/migrations/migration_lock.toml +3 -0
  500. package/nestjs/prisma/schema.prisma +1843 -0
  501. package/nestjs/prisma/seed.ts +375 -0
  502. package/nestjs/prisma.config.ts +14 -0
  503. package/nestjs/src/admin/admin.controller.ts +27 -0
  504. package/nestjs/src/admin/admin.module.ts +16 -0
  505. package/nestjs/src/admin/admin.service.ts +91 -0
  506. package/nestjs/src/admin/ai-chat-session.service.ts +454 -0
  507. package/nestjs/src/admin/ai-test.controller.ts +191 -0
  508. package/nestjs/src/admin/superadmin.controller.ts +106 -0
  509. package/nestjs/src/agents/agents.controller.ts +262 -0
  510. package/nestjs/src/agents/agents.module.ts +13 -0
  511. package/nestjs/src/agents/agents.service.ts +733 -0
  512. package/nestjs/src/agents/dto/create-agent.dto.ts +99 -0
  513. package/nestjs/src/agents/dto/index.ts +2 -0
  514. package/nestjs/src/agents/dto/update-agent.dto.ts +148 -0
  515. package/nestjs/src/app.module.ts +115 -0
  516. package/nestjs/src/appointment-validation/appointment-validation.controller.ts +194 -0
  517. package/nestjs/src/appointment-validation/appointment-validation.module.ts +16 -0
  518. package/nestjs/src/appointment-validation/appointment-validation.service.ts +450 -0
  519. package/nestjs/src/appointment-validation/dto/create-batch.dto.ts +105 -0
  520. package/nestjs/src/appointment-validation/dto/index.ts +1 -0
  521. package/nestjs/src/appointment-validation/processors/validation-dispatch.processor.ts +26 -0
  522. package/nestjs/src/appointment-validation/processors/validation-sync.processor.ts +23 -0
  523. package/nestjs/src/appointments/appointments.controller.ts +268 -0
  524. package/nestjs/src/appointments/appointments.module.ts +13 -0
  525. package/nestjs/src/appointments/appointments.service.ts +773 -0
  526. package/nestjs/src/appointments/dto/create-appointment.dto.ts +72 -0
  527. package/nestjs/src/appointments/dto/index.ts +4 -0
  528. package/nestjs/src/appointments/dto/query-appointments.dto.ts +60 -0
  529. package/nestjs/src/appointments/dto/update-appointment.dto.ts +43 -0
  530. package/nestjs/src/appointments/dto/update-status.dto.ts +18 -0
  531. package/nestjs/src/appointments/processors/reminder.processor.ts +243 -0
  532. package/nestjs/src/audit/audit.controller.ts +84 -0
  533. package/nestjs/src/audit/audit.decorator.ts +20 -0
  534. package/nestjs/src/audit/audit.interceptor.ts +67 -0
  535. package/nestjs/src/audit/audit.interfaces.ts +15 -0
  536. package/nestjs/src/audit/audit.module.ts +12 -0
  537. package/nestjs/src/audit/audit.service.ts +177 -0
  538. package/nestjs/src/auth/auth.controller.ts +116 -0
  539. package/nestjs/src/auth/auth.module.ts +25 -0
  540. package/nestjs/src/auth/auth.service.ts +612 -0
  541. package/nestjs/src/auth/dto/change-password.dto.ts +13 -0
  542. package/nestjs/src/auth/dto/forgot-password.dto.ts +8 -0
  543. package/nestjs/src/auth/dto/index.ts +6 -0
  544. package/nestjs/src/auth/dto/login.dto.ts +13 -0
  545. package/nestjs/src/auth/dto/refresh.dto.ts +8 -0
  546. package/nestjs/src/auth/dto/register.dto.ts +28 -0
  547. package/nestjs/src/auth/dto/reset-password.dto.ts +13 -0
  548. package/nestjs/src/auth/permissions.config.ts +85 -0
  549. package/nestjs/src/availability-blocks/availability-blocks.controller.ts +83 -0
  550. package/nestjs/src/availability-blocks/availability-blocks.module.ts +10 -0
  551. package/nestjs/src/availability-blocks/availability-blocks.service.ts +202 -0
  552. package/nestjs/src/billing/billing.controller.ts +104 -0
  553. package/nestjs/src/billing/billing.module.ts +12 -0
  554. package/nestjs/src/billing/billing.service.ts +398 -0
  555. package/nestjs/src/billing/dto/index.ts +2 -0
  556. package/nestjs/src/billing/dto/query-billing.dto.ts +29 -0
  557. package/nestjs/src/billing/dto/record-payment.dto.ts +60 -0
  558. package/nestjs/src/billing/processors/alerts.processor.ts +216 -0
  559. package/nestjs/src/billing/processors/snapshot.processor.ts +181 -0
  560. package/nestjs/src/calls/calls.controller.ts +92 -0
  561. package/nestjs/src/calls/calls.module.ts +10 -0
  562. package/nestjs/src/calls/calls.service.ts +359 -0
  563. package/nestjs/src/calls/dto/index.ts +1 -0
  564. package/nestjs/src/calls/dto/query-calls.dto.ts +46 -0
  565. package/nestjs/src/clinics/clinics.controller.ts +226 -0
  566. package/nestjs/src/clinics/clinics.module.ts +11 -0
  567. package/nestjs/src/clinics/clinics.service.ts +203 -0
  568. package/nestjs/src/clinics/dto/create-clinic.dto.ts +40 -0
  569. package/nestjs/src/clinics/dto/create-meta-connection.dto.ts +44 -0
  570. package/nestjs/src/clinics/dto/index.ts +4 -0
  571. package/nestjs/src/clinics/dto/update-clinic.dto.ts +133 -0
  572. package/nestjs/src/clinics/dto/update-meta-connection.dto.ts +22 -0
  573. package/nestjs/src/clinics/meta-connections.service.ts +210 -0
  574. package/nestjs/src/common/decorators/accessible-clinics.decorator.ts +9 -0
  575. package/nestjs/src/common/decorators/current-user.decorator.ts +10 -0
  576. package/nestjs/src/common/decorators/features.decorator.ts +7 -0
  577. package/nestjs/src/common/decorators/index.ts +4 -0
  578. package/nestjs/src/common/decorators/permissions.decorator.ts +13 -0
  579. package/nestjs/src/common/gateways/events.gateway.ts +157 -0
  580. package/nestjs/src/common/guards/clinic-access.guard.ts +40 -0
  581. package/nestjs/src/common/guards/features.guard.ts +38 -0
  582. package/nestjs/src/common/guards/index.ts +5 -0
  583. package/nestjs/src/common/guards/jwt-auth.guard.ts +54 -0
  584. package/nestjs/src/common/guards/permissions.guard.ts +50 -0
  585. package/nestjs/src/common/guards/superadmin.guard.ts +35 -0
  586. package/nestjs/src/common/interceptors/request-context.interceptor.ts +32 -0
  587. package/nestjs/src/common/interceptors/superadmin-tenant.interceptor.ts +42 -0
  588. package/nestjs/src/common/interfaces/jwt-payload.interface.ts +11 -0
  589. package/nestjs/src/config/config.module.ts +13 -0
  590. package/nestjs/src/database/database.module.ts +9 -0
  591. package/nestjs/src/database/prisma.service.ts +20 -0
  592. package/nestjs/src/database/tenant-context.ts +27 -0
  593. package/nestjs/src/google-calendar/google-calendar.controller.ts +259 -0
  594. package/nestjs/src/google-calendar/google-calendar.module.ts +10 -0
  595. package/nestjs/src/google-calendar/google-calendar.service.ts +811 -0
  596. package/nestjs/src/integrations/ai/ai.interface.ts +74 -0
  597. package/nestjs/src/integrations/ai/ai.module.ts +11 -0
  598. package/nestjs/src/integrations/ai/ai.service.ts +148 -0
  599. package/nestjs/src/integrations/ai/providers/anthropic.provider.ts +146 -0
  600. package/nestjs/src/integrations/ai/providers/openai.provider.ts +158 -0
  601. package/nestjs/src/integrations/elevenlabs/elevenlabs.module.ts +8 -0
  602. package/nestjs/src/integrations/elevenlabs/elevenlabs.service.ts +226 -0
  603. package/nestjs/src/integrations/encryption/encryption.module.ts +9 -0
  604. package/nestjs/src/integrations/encryption/encryption.service.ts +31 -0
  605. package/nestjs/src/integrations/image/image.module.ts +9 -0
  606. package/nestjs/src/integrations/image/image.service.ts +61 -0
  607. package/nestjs/src/integrations/meta-business/meta-business.module.ts +10 -0
  608. package/nestjs/src/integrations/meta-business/meta-instagram.service.ts +94 -0
  609. package/nestjs/src/integrations/meta-business/meta-webhook.service.ts +52 -0
  610. package/nestjs/src/integrations/meta-business/meta-whatsapp.service.ts +254 -0
  611. package/nestjs/src/integrations/minio/minio.module.ts +9 -0
  612. package/nestjs/src/integrations/minio/minio.service.ts +88 -0
  613. package/nestjs/src/integrations/netgsm/netgsm.module.ts +8 -0
  614. package/nestjs/src/integrations/netgsm/netgsm.service.ts +17 -0
  615. package/nestjs/src/integrations/tektippay/tektippay.module.ts +8 -0
  616. package/nestjs/src/integrations/tektippay/tektippay.service.ts +23 -0
  617. package/nestjs/src/leads/dto/index.ts +2 -0
  618. package/nestjs/src/leads/dto/query-leads.dto.ts +50 -0
  619. package/nestjs/src/leads/dto/update-lead.dto.ts +26 -0
  620. package/nestjs/src/leads/leads.controller.ts +184 -0
  621. package/nestjs/src/leads/leads.module.ts +10 -0
  622. package/nestjs/src/leads/leads.service.ts +375 -0
  623. package/nestjs/src/logging/logging.controller.ts +82 -0
  624. package/nestjs/src/logging/logging.module.ts +11 -0
  625. package/nestjs/src/logging/logging.service.ts +180 -0
  626. package/nestjs/src/main.ts +86 -0
  627. package/nestjs/src/outbound-campaigns/dto/create-campaign.dto.ts +47 -0
  628. package/nestjs/src/outbound-campaigns/dto/index.ts +3 -0
  629. package/nestjs/src/outbound-campaigns/dto/update-campaign.dto.ts +31 -0
  630. package/nestjs/src/outbound-campaigns/dto/upload-entries.dto.ts +35 -0
  631. package/nestjs/src/outbound-campaigns/outbound-campaigns.controller.ts +307 -0
  632. package/nestjs/src/outbound-campaigns/outbound-campaigns.module.ts +13 -0
  633. package/nestjs/src/outbound-campaigns/outbound-campaigns.service.ts +471 -0
  634. package/nestjs/src/outbound-campaigns/processors/campaign-dispatch.processor.ts +366 -0
  635. package/nestjs/src/patients/documents.service.ts +231 -0
  636. package/nestjs/src/patients/dto/create-examination.dto.ts +34 -0
  637. package/nestjs/src/patients/dto/create-note.dto.ts +14 -0
  638. package/nestjs/src/patients/dto/create-patient.dto.ts +86 -0
  639. package/nestjs/src/patients/dto/create-photo-set.dto.ts +32 -0
  640. package/nestjs/src/patients/dto/index.ts +10 -0
  641. package/nestjs/src/patients/dto/update-examination.dto.ts +29 -0
  642. package/nestjs/src/patients/dto/update-medical-history.dto.ts +47 -0
  643. package/nestjs/src/patients/dto/update-patient.dto.ts +87 -0
  644. package/nestjs/src/patients/dto/update-photo-set.dto.ts +28 -0
  645. package/nestjs/src/patients/dto/upload-document.dto.ts +31 -0
  646. package/nestjs/src/patients/dto/upload-photo.dto.ts +27 -0
  647. package/nestjs/src/patients/examinations.service.ts +271 -0
  648. package/nestjs/src/patients/medical-history.service.ts +149 -0
  649. package/nestjs/src/patients/notes.service.ts +172 -0
  650. package/nestjs/src/patients/patients.controller.ts +485 -0
  651. package/nestjs/src/patients/patients.module.ts +22 -0
  652. package/nestjs/src/patients/patients.service.ts +412 -0
  653. package/nestjs/src/patients/photo-sets.service.ts +389 -0
  654. package/nestjs/src/phone-numbers/dto/create-phone-number.dto.ts +57 -0
  655. package/nestjs/src/phone-numbers/dto/index.ts +3 -0
  656. package/nestjs/src/phone-numbers/dto/update-phone-number.dto.ts +38 -0
  657. package/nestjs/src/phone-numbers/dto/update-schedule.dto.ts +39 -0
  658. package/nestjs/src/phone-numbers/phone-numbers.controller.ts +125 -0
  659. package/nestjs/src/phone-numbers/phone-numbers.module.ts +10 -0
  660. package/nestjs/src/phone-numbers/phone-numbers.service.ts +209 -0
  661. package/nestjs/src/plans/dto/create-plan.dto.ts +70 -0
  662. package/nestjs/src/plans/dto/index.ts +2 -0
  663. package/nestjs/src/plans/dto/update-plan.dto.ts +80 -0
  664. package/nestjs/src/plans/plans.controller.ts +50 -0
  665. package/nestjs/src/plans/plans.module.ts +10 -0
  666. package/nestjs/src/plans/plans.service.ts +115 -0
  667. package/nestjs/src/platform/dto/create-tenant.dto.ts +36 -0
  668. package/nestjs/src/platform/dto/index.ts +2 -0
  669. package/nestjs/src/platform/dto/update-tenant-platform.dto.ts +44 -0
  670. package/nestjs/src/platform/platform.controller.ts +79 -0
  671. package/nestjs/src/platform/platform.module.ts +10 -0
  672. package/nestjs/src/platform/platform.service.ts +301 -0
  673. package/nestjs/src/queue/queue.module.ts +56 -0
  674. package/nestjs/src/redis/redis.module.ts +20 -0
  675. package/nestjs/src/tenants/dto/index.ts +1 -0
  676. package/nestjs/src/tenants/dto/update-tenant.dto.ts +15 -0
  677. package/nestjs/src/tenants/tenants.controller.ts +45 -0
  678. package/nestjs/src/tenants/tenants.module.ts +10 -0
  679. package/nestjs/src/tenants/tenants.service.ts +41 -0
  680. package/nestjs/src/tools/adapters/elevenlabs-http.adapter.ts +51 -0
  681. package/nestjs/src/tools/adapters/elevenlabs-ws.adapter.ts +59 -0
  682. package/nestjs/src/tools/handlers/calendar.tools.ts +441 -0
  683. package/nestjs/src/tools/handlers/notification.tools.ts +34 -0
  684. package/nestjs/src/tools/handlers/operator.tools.ts +303 -0
  685. package/nestjs/src/tools/handlers/patient.tools.ts +242 -0
  686. package/nestjs/src/tools/handlers/payment.tools.ts +43 -0
  687. package/nestjs/src/tools/handlers/validation.tools.ts +152 -0
  688. package/nestjs/src/tools/tool-registry.service.ts +221 -0
  689. package/nestjs/src/tools/tool.decorator.ts +16 -0
  690. package/nestjs/src/tools/tool.interfaces.ts +26 -0
  691. package/nestjs/src/tools/tools.module.ts +50 -0
  692. package/nestjs/src/treatments/dto/create-plan-item.dto.ts +27 -0
  693. package/nestjs/src/treatments/dto/create-treatment-plan.dto.ts +69 -0
  694. package/nestjs/src/treatments/dto/create-treatment.dto.ts +59 -0
  695. package/nestjs/src/treatments/dto/index.ts +6 -0
  696. package/nestjs/src/treatments/dto/update-plan-item.dto.ts +23 -0
  697. package/nestjs/src/treatments/dto/update-treatment-plan.dto.ts +22 -0
  698. package/nestjs/src/treatments/dto/update-treatment.dto.ts +70 -0
  699. package/nestjs/src/treatments/treatment-plans.service.ts +362 -0
  700. package/nestjs/src/treatments/treatments.controller.ts +265 -0
  701. package/nestjs/src/treatments/treatments.module.ts +14 -0
  702. package/nestjs/src/treatments/treatments.service.ts +165 -0
  703. package/nestjs/src/users/doctor-profiles.service.ts +202 -0
  704. package/nestjs/src/users/dto/index.ts +4 -0
  705. package/nestjs/src/users/dto/invite-user.dto.ts +52 -0
  706. package/nestjs/src/users/dto/update-clinic-assignments.dto.ts +9 -0
  707. package/nestjs/src/users/dto/update-doctor-profile.dto.ts +49 -0
  708. package/nestjs/src/users/dto/update-user.dto.ts +41 -0
  709. package/nestjs/src/users/users.controller.ts +142 -0
  710. package/nestjs/src/users/users.module.ts +11 -0
  711. package/nestjs/src/users/users.service.ts +250 -0
  712. package/nestjs/src/webhooks/elevenlabs-tool.controller.ts +66 -0
  713. package/nestjs/src/webhooks/elevenlabs-webhook.controller.ts +60 -0
  714. package/nestjs/src/webhooks/meta-webhook.controller.ts +178 -0
  715. package/nestjs/src/webhooks/processors/elevenlabs-webhook.processor.ts +28 -0
  716. package/nestjs/src/webhooks/webhooks.module.ts +17 -0
  717. package/nestjs/src/whatsapp/chat-context.service.ts +281 -0
  718. package/nestjs/src/whatsapp/dto/add-blacklist.dto.ts +13 -0
  719. package/nestjs/src/whatsapp/dto/index.ts +2 -0
  720. package/nestjs/src/whatsapp/dto/send-message.dto.ts +14 -0
  721. package/nestjs/src/whatsapp/listeners/meta-message.listener.ts +579 -0
  722. package/nestjs/src/whatsapp/meta-auth.controller.ts +268 -0
  723. package/nestjs/src/whatsapp/meta-instagram-auth.controller.ts +244 -0
  724. package/nestjs/src/whatsapp/operator.service.ts +692 -0
  725. package/nestjs/src/whatsapp/processors/cost-sweep.processor.ts +130 -0
  726. package/nestjs/src/whatsapp/processors/grace.processor.ts +191 -0
  727. package/nestjs/src/whatsapp/processors/message-buffer.processor.ts +138 -0
  728. package/nestjs/src/whatsapp/processors/message-cleanup.processor.ts +148 -0
  729. package/nestjs/src/whatsapp/processors/meta-token-refresh.processor.ts +114 -0
  730. package/nestjs/src/whatsapp/processors/operator-expiry.processor.ts +105 -0
  731. package/nestjs/src/whatsapp/processors/profile-update.processor.ts +234 -0
  732. package/nestjs/src/whatsapp/processors/session-cleanup.processor.ts +178 -0
  733. package/nestjs/src/whatsapp/processors/session-labels.processor.ts +248 -0
  734. package/nestjs/src/whatsapp/whatsapp-agent.service.ts +2506 -0
  735. package/nestjs/src/whatsapp/whatsapp-recovery.service.ts +117 -0
  736. package/nestjs/src/whatsapp/whatsapp.controller.ts +398 -0
  737. package/nestjs/src/whatsapp/whatsapp.module.ts +51 -0
  738. package/nestjs/src/whatsapp/whatsapp.service.ts +592 -0
  739. package/nestjs/test/app.e2e-spec.ts +25 -0
  740. package/nestjs/test/jest-e2e.json +9 -0
  741. package/nestjs/tsconfig.build.json +4 -0
  742. package/nestjs/tsconfig.json +25 -0
  743. package/nginx.example.conf +18 -0
  744. package/package.json +47 -0
  745. package/scripts/addRecipient.ts +48 -0
  746. package/scripts/listRecipients.ts +31 -0
  747. package/scripts/migrate-agent-ref.ts +86 -0
  748. package/scripts/migrate-sessions.ts +183 -0
  749. package/scripts/promote.ts +27 -0
  750. package/scripts/retrigger.ts +84 -0
  751. package/scripts/seed.ts +435 -0
  752. package/scripts/testSend.ts +63 -0
  753. package/src/app.ts +85 -0
  754. package/src/config/agentPrompts.json +19 -0
  755. package/src/config/database.ts +21 -0
  756. package/src/config/env.ts +94 -0
  757. package/src/config/index.ts +86 -0
  758. package/src/controllers/webhook.controller.ts +150 -0
  759. package/src/errors/index.ts +9 -0
  760. package/src/hooks/webhookValidator.ts +55 -0
  761. package/src/index.ts +68 -0
  762. package/src/migrations/001_session-architecture.ts +138 -0
  763. package/src/migrations/002_agent-ref.ts +65 -0
  764. package/src/migrations/003_shift-schedule.ts +55 -0
  765. package/src/migrations/004_invert-shift-to-clinic-hours.ts +30 -0
  766. package/src/migrations/005_composite-baileys-chat-ids.ts +60 -0
  767. package/src/migrations/migration.model.ts +27 -0
  768. package/src/migrations/migration.routes.ts +40 -0
  769. package/src/migrations/migration.runner.ts +112 -0
  770. package/src/models/ConversationClaim.ts +17 -0
  771. package/src/models/ConversationEvaluation.ts +91 -0
  772. package/src/models/Summary.ts +77 -0
  773. package/src/models/Transcription.ts +68 -0
  774. package/src/models/WhatsAppRecipient.ts +37 -0
  775. package/src/modules/admin/admin.routes.ts +2385 -0
  776. package/src/modules/admin/elevenlabs-test-chat.routes.ts +193 -0
  777. package/src/modules/admin/whatsapp-test-chat.routes.ts +244 -0
  778. package/src/modules/agents/agent.model.ts +93 -0
  779. package/src/modules/agents/agent.routes.ts +65 -0
  780. package/src/modules/appointment-validation/appointment-validation.model.ts +163 -0
  781. package/src/modules/appointment-validation/appointment-validation.routes.ts +275 -0
  782. package/src/modules/appointment-validation/appointment-validation.service.ts +1028 -0
  783. package/src/modules/auth/auth.model.ts +42 -0
  784. package/src/modules/auth/auth.routes.ts +199 -0
  785. package/src/modules/auth/auth.service.ts +210 -0
  786. package/src/modules/auth/refresh-token.model.ts +26 -0
  787. package/src/modules/billing/billing-alert.model.ts +28 -0
  788. package/src/modules/billing/billing-period-snapshot.model.ts +68 -0
  789. package/src/modules/billing/billing.model.ts +42 -0
  790. package/src/modules/billing/billing.routes.ts +67 -0
  791. package/src/modules/billing/billing.service.ts +562 -0
  792. package/src/modules/billing/payment.model.ts +42 -0
  793. package/src/modules/calls/call.model.ts +102 -0
  794. package/src/modules/calls/call.routes.ts +118 -0
  795. package/src/modules/campaigns/campaign.model.ts +111 -0
  796. package/src/modules/campaigns/campaign.routes.ts +402 -0
  797. package/src/modules/campaigns/campaign.service.ts +99 -0
  798. package/src/modules/google-calendar/google-calendar.routes.ts +31 -0
  799. package/src/modules/inbound-call/inbound-call-config.model.ts +49 -0
  800. package/src/modules/inbound-call/inbound-call.routes.ts +289 -0
  801. package/src/modules/leads/lead.model.ts +40 -0
  802. package/src/modules/leads/lead.routes.ts +246 -0
  803. package/src/modules/logs/log.model.ts +27 -0
  804. package/src/modules/logs/log.routes.ts +102 -0
  805. package/src/modules/plans/plan.model.ts +45 -0
  806. package/src/modules/surveys/survey.model.ts +70 -0
  807. package/src/modules/surveys/survey.routes.ts +187 -0
  808. package/src/modules/tenants/tenant.model.ts +181 -0
  809. package/src/modules/tenants/tenant.routes.ts +78 -0
  810. package/src/modules/users/user.routes.ts +126 -0
  811. package/src/modules/webhooks/elevenlabs-tool.routes.ts +94 -0
  812. package/src/modules/webhooks/elevenlabs-tool.service.ts +491 -0
  813. package/src/modules/webhooks/elevenlabs.routes.ts +34 -0
  814. package/src/modules/webhooks/elevenlabs.service.ts +565 -0
  815. package/src/modules/webhooks/unipile.routes.ts +917 -0
  816. package/src/modules/whatsapp/appointment.model.ts +47 -0
  817. package/src/modules/whatsapp/operator-request.model.ts +58 -0
  818. package/src/modules/whatsapp/stt-usage.model.ts +30 -0
  819. package/src/modules/whatsapp/whatsapp-chat.model.ts +39 -0
  820. package/src/modules/whatsapp/whatsapp-contact-profile.model.ts +41 -0
  821. package/src/modules/whatsapp/whatsapp-message.model.ts +41 -0
  822. package/src/modules/whatsapp/whatsapp-session.model.ts +60 -0
  823. package/src/modules/whatsapp/whatsapp.routes.ts +1435 -0
  824. package/src/plugins/cors.ts +7 -0
  825. package/src/plugins/jwt.ts +18 -0
  826. package/src/plugins/rawBody.ts +12 -0
  827. package/src/plugins/rbac.ts +24 -0
  828. package/src/routes/admin.routes.ts +208 -0
  829. package/src/routes/health.routes.ts +12 -0
  830. package/src/routes/webhook.routes.ts +12 -0
  831. package/src/services/ai/base.ai.ts +132 -0
  832. package/src/services/ai/gemini.service.ts +41 -0
  833. package/src/services/ai/index.ts +24 -0
  834. package/src/services/ai/openai.service.ts +48 -0
  835. package/src/services/elevenlabs.service.ts +532 -0
  836. package/src/services/google-calendar.service.ts +656 -0
  837. package/src/services/inbound-call-schedule.service.ts +174 -0
  838. package/src/services/netgsm.service.ts +128 -0
  839. package/src/services/unipile.service.ts +200 -0
  840. package/src/services/whatsapp-agent.service.ts +2479 -0
  841. package/src/services/whatsapp.service.ts +245 -0
  842. package/src/templates/index.ts +71 -0
  843. package/src/templates/receptionist.ts +44 -0
  844. package/src/templates/survey.ts +44 -0
  845. package/src/types/index.ts +218 -0
  846. package/src/utils/logger.ts +83 -0
  847. package/tsconfig.json +19 -0
  848. package/web/.dockerignore +4 -0
  849. package/web/Dockerfile +18 -0
  850. package/web/README.md +73 -0
  851. package/web/components.json +23 -0
  852. package/web/eslint.config.js +23 -0
  853. package/web/index.html +14 -0
  854. package/web/nginx.conf +18 -0
  855. package/web/package-lock.json +10292 -0
  856. package/web/package.json +48 -0
  857. package/web/public/favicon.ico +0 -0
  858. package/web/public/vite.svg +1 -0
  859. package/web/src/App.tsx +191 -0
  860. package/web/src/assets/react.svg +1 -0
  861. package/web/src/components/Layout.tsx +261 -0
  862. package/web/src/components/LeadConversation.tsx +251 -0
  863. package/web/src/components/ProtectedRoute.tsx +20 -0
  864. package/web/src/components/conversation-review/CardAudioPlayer.tsx +200 -0
  865. package/web/src/components/conversation-review/CardEvaluation.tsx +351 -0
  866. package/web/src/components/conversation-review/CardMetadata.tsx +44 -0
  867. package/web/src/components/conversation-review/ConversationCard.tsx +95 -0
  868. package/web/src/components/conversation-review/ReviewContainer.tsx +120 -0
  869. package/web/src/components/conversation-review/ReviewFilters.tsx +88 -0
  870. package/web/src/components/empty-state.tsx +15 -0
  871. package/web/src/components/page-header.tsx +19 -0
  872. package/web/src/components/page-loader.tsx +32 -0
  873. package/web/src/components/pagination.tsx +38 -0
  874. package/web/src/components/stat-card.tsx +27 -0
  875. package/web/src/components/status-badge.tsx +125 -0
  876. package/web/src/components/ui/alert.tsx +66 -0
  877. package/web/src/components/ui/badge.tsx +48 -0
  878. package/web/src/components/ui/button.tsx +64 -0
  879. package/web/src/components/ui/card.tsx +92 -0
  880. package/web/src/components/ui/checkbox.tsx +32 -0
  881. package/web/src/components/ui/dialog.tsx +158 -0
  882. package/web/src/components/ui/dropdown-menu.tsx +255 -0
  883. package/web/src/components/ui/input.tsx +21 -0
  884. package/web/src/components/ui/label.tsx +22 -0
  885. package/web/src/components/ui/progress.tsx +29 -0
  886. package/web/src/components/ui/select.tsx +188 -0
  887. package/web/src/components/ui/separator.tsx +28 -0
  888. package/web/src/components/ui/sheet.tsx +123 -0
  889. package/web/src/components/ui/skeleton.tsx +13 -0
  890. package/web/src/components/ui/sonner.tsx +35 -0
  891. package/web/src/components/ui/table.tsx +116 -0
  892. package/web/src/components/ui/tabs.tsx +89 -0
  893. package/web/src/components/ui/textarea.tsx +18 -0
  894. package/web/src/components/ui/tooltip.tsx +57 -0
  895. package/web/src/components/whatsapp/ChatDetail.tsx +417 -0
  896. package/web/src/components/whatsapp/ChatHeader.tsx +78 -0
  897. package/web/src/components/whatsapp/ChatList.tsx +107 -0
  898. package/web/src/components/whatsapp/ChatListItem.tsx +60 -0
  899. package/web/src/components/whatsapp/MessageBubble.tsx +46 -0
  900. package/web/src/components/whatsapp/MessageInput.tsx +63 -0
  901. package/web/src/components/whatsapp/MessageStream.tsx +135 -0
  902. package/web/src/components/whatsapp/SessionDivider.tsx +65 -0
  903. package/web/src/components/whatsapp/SessionHistory.tsx +119 -0
  904. package/web/src/components/whatsapp/settings/AiSettingsTab.tsx +268 -0
  905. package/web/src/components/whatsapp/settings/CalendarTab.tsx +339 -0
  906. package/web/src/components/whatsapp/settings/ConnectionTab.tsx +236 -0
  907. package/web/src/components/whatsapp/settings/NotificationsTab.tsx +109 -0
  908. package/web/src/components/whatsapp/settings/OperatorTab.tsx +303 -0
  909. package/web/src/contexts/AuthContext.tsx +103 -0
  910. package/web/src/index.css +130 -0
  911. package/web/src/lib/api.ts +92 -0
  912. package/web/src/lib/utils.ts +6 -0
  913. package/web/src/main.tsx +10 -0
  914. package/web/src/pages/AppointmentDetail.tsx +206 -0
  915. package/web/src/pages/AppointmentValidation.tsx +157 -0
  916. package/web/src/pages/AppointmentValidationDetail.tsx +617 -0
  917. package/web/src/pages/AppointmentValidationNew.tsx +1005 -0
  918. package/web/src/pages/Appointments.tsx +283 -0
  919. package/web/src/pages/Billing.tsx +126 -0
  920. package/web/src/pages/CallDetail.tsx +293 -0
  921. package/web/src/pages/CallSettings.tsx +313 -0
  922. package/web/src/pages/Calls.tsx +188 -0
  923. package/web/src/pages/CampaignDetail.tsx +216 -0
  924. package/web/src/pages/CampaignNew.tsx +277 -0
  925. package/web/src/pages/CampaignResults.tsx +185 -0
  926. package/web/src/pages/Campaigns.tsx +171 -0
  927. package/web/src/pages/Dashboard.tsx +336 -0
  928. package/web/src/pages/InboundSchedule.tsx +246 -0
  929. package/web/src/pages/LeadDetail.tsx +183 -0
  930. package/web/src/pages/Leads.tsx +258 -0
  931. package/web/src/pages/Login.tsx +99 -0
  932. package/web/src/pages/Register.tsx +129 -0
  933. package/web/src/pages/Settings.tsx +133 -0
  934. package/web/src/pages/SurveyDetail.tsx +232 -0
  935. package/web/src/pages/SurveyPreview.tsx +179 -0
  936. package/web/src/pages/Surveys.tsx +207 -0
  937. package/web/src/pages/Users.tsx +199 -0
  938. package/web/src/pages/WhatsApp.tsx +147 -0
  939. package/web/src/pages/WhatsAppSettings.tsx +215 -0
  940. package/web/src/pages/admin/AdminBaileysMessageLog.tsx +331 -0
  941. package/web/src/pages/admin/AdminBaileysRawMessages.tsx +318 -0
  942. package/web/src/pages/admin/AdminConversationReview.tsx +116 -0
  943. package/web/src/pages/admin/AdminCredits.tsx +467 -0
  944. package/web/src/pages/admin/AdminElevenLabsAgentDetail.tsx +332 -0
  945. package/web/src/pages/admin/AdminElevenLabsAgents.tsx +164 -0
  946. package/web/src/pages/admin/AdminElevenLabsBatchCallDetail.tsx +214 -0
  947. package/web/src/pages/admin/AdminElevenLabsBatchCalls.tsx +293 -0
  948. package/web/src/pages/admin/AdminElevenLabsConversationDetail.tsx +230 -0
  949. package/web/src/pages/admin/AdminElevenLabsConversations.tsx +228 -0
  950. package/web/src/pages/admin/AdminElevenLabsInboundCalls.tsx +293 -0
  951. package/web/src/pages/admin/AdminElevenLabsPhoneNumbers.tsx +506 -0
  952. package/web/src/pages/admin/AdminElevenLabsTestChat.tsx +258 -0
  953. package/web/src/pages/admin/AdminElevenLabsWebhooks.tsx +289 -0
  954. package/web/src/pages/admin/AdminEvaluationDashboard.tsx +520 -0
  955. package/web/src/pages/admin/AdminLeads.tsx +339 -0
  956. package/web/src/pages/admin/AdminLogs.tsx +283 -0
  957. package/web/src/pages/admin/AdminMigrations.tsx +247 -0
  958. package/web/src/pages/admin/AdminPlans.tsx +313 -0
  959. package/web/src/pages/admin/AdminSystem.tsx +391 -0
  960. package/web/src/pages/admin/AdminTenantBillableItems.tsx +464 -0
  961. package/web/src/pages/admin/AdminTenantDetail.tsx +1317 -0
  962. package/web/src/pages/admin/AdminTenants.tsx +274 -0
  963. package/web/src/pages/admin/AdminWhatsApp.tsx +618 -0
  964. package/web/src/pages/admin/AdminWhatsAppTestChat.tsx +328 -0
  965. package/web/src/types/index.ts +242 -0
  966. package/web/tsconfig.app.json +32 -0
  967. package/web/tsconfig.json +13 -0
  968. package/web/tsconfig.node.json +26 -0
  969. package/web/vite.config.ts +23 -0
@@ -0,0 +1,742 @@
1
+ # 03 — Multi-Clinic & Multi-Phone Architecture
2
+
3
+ > Last updated: 2026-04-02
4
+
5
+ > Covers the Clinic model, PhoneNumber model, clinic connections (Calendar, Meta),
6
+ > phone-to-clinic-to-agent routing, and per-clinic self-contained configuration.
7
+
8
+ ---
9
+
10
+ ## Table of Contents
11
+
12
+ 1. [Overview](#1-overview)
13
+ 2. [Clinic Model](#2-clinic-model)
14
+ 3. [PhoneNumber Model](#3-phonenumber-model)
15
+ 4. [Clinic Connections](#4-clinic-connections)
16
+ 5. [Routing Flow](#5-routing-flow)
17
+ 6. [Clinic Configuration](#6-clinic-configuration)
18
+ 7. [Examples](#7-examples)
19
+
20
+ ---
21
+
22
+ ## 1. Overview
23
+
24
+ The system supports two operating modes through the same data model:
25
+
26
+ - **Single-clinic tenants** -- one tenant, one clinic (auto-created on registration as the default clinic). Everything works transparently with no clinic selection required. This is the common case for a solo practice.
27
+ - **Multi-clinic tenants** -- one tenant, many clinics (branches/locations). Each clinic has its own phone numbers, calendar, operator, and agent configuration. Incoming messages and calls are routed to the correct clinic based on which phone number the patient contacted.
28
+
29
+ The architecture uses two layers:
30
+
31
+ ```
32
+ Tenant (1)
33
+ |
34
+ +-- Clinic (1..N)
35
+ |
36
+ +-- PhoneNumber (0..N) -- WhatsApp, inbound calls, outbound calls
37
+ +-- Agent (0..N) -- ElevenLabs AI agents
38
+ +-- CalendarConnection (0..1)
39
+ +-- ClinicMetaConnections (0..N) -- multiple WhatsApp/Instagram connections
40
+ +-- Users (via assignment)
41
+ +-- Patients (0..N)
42
+ +-- Treatments (0..N)
43
+ ```
44
+
45
+ Each clinic is **self-contained** -- it owns all its operational configuration directly (language, AI provider, grace period, operator settings, SMS, notifications). There is no settings inheritance chain from tenant to clinic.
46
+
47
+ ---
48
+
49
+ ## 2. Clinic Model
50
+
51
+ ### Prisma Schema
52
+
53
+ ```prisma
54
+ model Clinic {
55
+ clinic_id String @id @default(uuid())
56
+ clinic_tenant_id String
57
+ clinic_name String
58
+ clinic_slug String // URL-friendly: "kadikoy", "main"
59
+ clinic_address String @default("")
60
+ clinic_timezone String @default("Europe/Istanbul")
61
+ clinic_is_default Boolean @default(false)
62
+ clinic_is_active Boolean @default(true)
63
+
64
+ // Language & AI (self-contained -- no tenant fallback)
65
+ clinic_language String @default("tr")
66
+ clinic_ai_provider String @default("elevenlabs")
67
+ clinic_ai_model String @default("")
68
+
69
+ // Operator workflow (proper columns -- queried on every incoming message)
70
+ clinic_operator_phone String? // Doctor's WhatsApp number for this clinic
71
+ clinic_operator_prefix String @default("R") // REF code prefix
72
+ clinic_operator_timeout_hours Int @default(24) // hours before request expires
73
+ clinic_grace_period_seconds Int @default(180) // seconds before AI takes over
74
+
75
+ // AI shift (proper columns)
76
+ clinic_ai_shift_enabled Boolean @default(false)
77
+ clinic_ai_shift_schedule Json @default("[]") // [{day, start, end}]
78
+
79
+ // Messaging
80
+ clinic_blacklisted_numbers String[] @default([])
81
+ clinic_fixed_first_message String? // null = disabled
82
+
83
+ // SMS & notifications
84
+ clinic_sms_enabled Boolean @default(false)
85
+ clinic_sms_phones String[] @default([])
86
+ clinic_notification_phones String[] @default([])
87
+
88
+ // Message retention
89
+ clinic_message_retention_days Int @default(7) // auto-deletion via BullMQ job
90
+
91
+ clinic_created_at DateTime @default(now())
92
+ clinic_updated_at DateTime @updatedAt
93
+
94
+ tenant Tenant @relation(fields: [clinic_tenant_id], references: [tenant_id], onDelete: Cascade)
95
+ userAssignments UserClinicAssignment[]
96
+ agents Agent[]
97
+ phoneNumbers PhoneNumber[]
98
+ calendarConnection ClinicCalendarConnection?
99
+ metaConnections ClinicMetaConnection[] // 1:many -- multiple WhatsApp/Instagram connections
100
+ whatsappChats WhatsAppChat[]
101
+ whatsappSessions WhatsAppSession[]
102
+ appointments Appointment[]
103
+ operatorRequests OperatorRequest[]
104
+ calls Call[]
105
+ leads Lead[]
106
+ outboundCampaigns OutboundCampaign[]
107
+ validationBatches AppointmentValidationBatch[]
108
+ patients Patient[]
109
+ treatments Treatment[]
110
+
111
+ @@unique([clinic_tenant_id, clinic_slug])
112
+ @@index([clinic_tenant_id])
113
+ @@index([clinic_tenant_id, clinic_operator_phone])
114
+ @@map("clinics")
115
+ }
116
+ ```
117
+
118
+ ### Key Design Decisions
119
+
120
+ **Default clinic:** Every tenant gets exactly one clinic with `clinic_is_default = true` on registration. Single-clinic tenants never need to create or manage clinics -- the default clinic is used implicitly. Multi-clinic tenants can create additional clinics and optionally change which one is the default.
121
+
122
+ **All operational config is on proper columns:** There is no `clinic_settings` JSONB blob. Every configurable value is a typed column with a sensible default. This means no null-means-inherit pattern and no runtime resolution logic -- the clinic row is the single source of truth.
123
+
124
+ | Column | Reason |
125
+ |--------|--------|
126
+ | `clinic_operator_phone` | Queried on every incoming message (WHERE clause) |
127
+ | `clinic_operator_prefix` | Queried for REF code generation |
128
+ | `clinic_operator_timeout_hours` | Queried for expiry sweep |
129
+ | `clinic_grace_period_seconds` | Queried on every session start |
130
+ | `clinic_ai_shift_enabled`, `clinic_ai_shift_schedule` | Queried by schedule sync job |
131
+ | `clinic_blacklisted_numbers` | Queried on every incoming message |
132
+ | `clinic_fixed_first_message` | Queried on first message in session |
133
+ | `clinic_language`, `clinic_ai_provider`, `clinic_ai_model` | Used when initializing AI connections |
134
+ | `clinic_sms_enabled`, `clinic_sms_phones`, `clinic_notification_phones` | Queried by notification service |
135
+ | `clinic_message_retention_days` | Used by BullMQ auto-deletion job |
136
+
137
+ ### Slug
138
+
139
+ The `clinic_slug` is a URL-friendly identifier unique within a tenant (enforced by `@@unique([clinic_tenant_id, clinic_slug])`). Used in URLs and webhook routing. Examples: `"main"`, `"kadikoy"`, `"besiktas"`.
140
+
141
+ ---
142
+
143
+ ## 3. PhoneNumber Model
144
+
145
+ ### Purpose
146
+
147
+ The `PhoneNumber` table is a **unified registry** for all phone numbers across all use cases. It replaces four scattered locations in the current system:
148
+
149
+ | Old Location | Now In |
150
+ |-------------|--------|
151
+ | `tenant.settings.whatsapp_agent.connected_phone` | `phone_numbers` with `purpose = whatsapp` |
152
+ | `InboundCallConfig.phone_number` | `phone_numbers` with `purpose = inbound_call` |
153
+ | `tenant.settings.outbound_call_phone_number_id` | `phone_numbers` with `purpose = outbound_call` |
154
+ | Per-clinic operator phones | `clinic.clinic_operator_phone` (separate -- this is the *doctor's* personal number, not a system phone) |
155
+
156
+ ### Prisma Schema
157
+
158
+ ```prisma
159
+ model PhoneNumber {
160
+ phone_id String @id @default(uuid())
161
+ phone_tenant_id String
162
+ phone_clinic_id String? // null = tenant-level (unassigned)
163
+ phone_number String // E.164: +905551234567
164
+ phone_label String @default("")
165
+ phone_purpose PhoneNumberPurpose // whatsapp | inbound_call | outbound_call
166
+ phone_provider PhoneNumberProvider // meta_business | elevenlabs
167
+ phone_external_account_id String? // Meta phone_number_id
168
+ phone_elevenlabs_phone_id String? // ElevenLabs phone number ID
169
+ phone_elevenlabs_agent_id String? // ElevenLabs agent ID (external)
170
+ phone_agent_id String? // FK to agents table (internal routing)
171
+ phone_wa_connected Boolean @default(false)
172
+ phone_wa_connected_at DateTime?
173
+ phone_wa_bridge_provider String? // reserved for future use
174
+ phone_schedule_enabled Boolean @default(false)
175
+ phone_schedule Json @default("[]") // [{day, start, end}]
176
+ phone_agent_assigned Boolean @default(false)
177
+ phone_is_active Boolean @default(true)
178
+ phone_created_at DateTime @default(now())
179
+ phone_updated_at DateTime @updatedAt
180
+
181
+ tenant Tenant @relation(fields: [phone_tenant_id], references: [tenant_id], onDelete: Cascade)
182
+ clinic Clinic? @relation(fields: [phone_clinic_id], references: [clinic_id])
183
+ agent Agent? @relation(fields: [phone_agent_id], references: [agent_id])
184
+ chats WhatsAppChat[]
185
+ campaigns OutboundCampaign[]
186
+ validationBatches AppointmentValidationBatch[]
187
+
188
+ @@unique([phone_tenant_id, phone_number, phone_purpose])
189
+ @@index([phone_tenant_id, phone_purpose])
190
+ @@index([phone_clinic_id])
191
+ @@index([phone_provider, phone_external_account_id])
192
+ @@map("phone_numbers")
193
+ }
194
+ ```
195
+
196
+ ### Enums
197
+
198
+ ```prisma
199
+ enum PhoneNumberPurpose {
200
+ whatsapp // WhatsApp AI chat
201
+ inbound_call // Receive voice calls via ElevenLabs SIP trunk
202
+ outbound_call // Make voice calls (campaigns, appointment validation)
203
+ }
204
+
205
+ enum PhoneNumberProvider {
206
+ meta_business // Official Meta Business Cloud API
207
+ elevenlabs // ElevenLabs SIP trunk (voice calls)
208
+ }
209
+ ```
210
+
211
+ ### Key Concepts
212
+
213
+ **One number, one purpose:** The same E.164 number can appear multiple times in the table with different purposes. For example, `+905551234567` might be both a `whatsapp` number (for AI chat) and an `inbound_call` number (for voice). The uniqueness constraint is `(tenant_id, number, purpose)`.
214
+
215
+ **Provider determines how the number connects:**
216
+
217
+ | Purpose | Provider | How It Works |
218
+ |---------|----------|-------------|
219
+ | `whatsapp` | `meta_business` | Official WhatsApp Business API via Meta. OAuth-based setup. |
220
+ | `inbound_call` | `elevenlabs` | ElevenLabs SIP trunk. Phone is registered with ElevenLabs, agent assigned via API. |
221
+ | `outbound_call` | `elevenlabs` | Same ElevenLabs SIP trunk. Used for outbound campaigns and appointment validation. |
222
+
223
+ **Phone -> Clinic -> Agent routing chain:**
224
+ A phone number is assigned to a clinic (`phone_clinic_id`). The phone number points to an agent (`phone_agent_id`). When a message arrives on a phone number, the system looks up the phone, gets the clinic, gets the agent, and routes accordingly.
225
+
226
+ ```
227
+ Incoming message/call
228
+ |
229
+ v
230
+ PhoneNumber (lookup by phone_number + purpose)
231
+ |
232
+ +-- phone_clinic_id --> Clinic (settings, operator, calendar)
233
+ |
234
+ +-- phone_agent_id --> Agent (AI config, voice, prompt)
235
+ ```
236
+
237
+ **Unassigned phones:** A phone number with `phone_clinic_id = null` is tenant-level (not yet assigned to a clinic). It must be assigned before it can route messages.
238
+
239
+ ### Indexes
240
+
241
+ | Index | Purpose |
242
+ |-------|---------|
243
+ | `(phone_tenant_id, phone_purpose)` | List all WhatsApp numbers for a tenant, all inbound numbers, etc. |
244
+ | `(phone_clinic_id)` | Find all numbers for a clinic |
245
+ | `(phone_provider, phone_external_account_id)` | Webhook routing: look up phone by Meta phone_number_id |
246
+ | `(phone_tenant_id, phone_number, phone_purpose)` UNIQUE | Prevent duplicate registrations |
247
+
248
+ ### API Endpoints
249
+
250
+ | Method | Path | Permission | Description |
251
+ |--------|------|-----------|-------------|
252
+ | GET | `/phone-numbers` | `phone_numbers:read` | List all (filterable by purpose, clinic, provider) |
253
+ | POST | `/phone-numbers` | `phone_numbers:manage` | Register phone number |
254
+ | GET | `/phone-numbers/:id` | `phone_numbers:read` | Detail with status |
255
+ | PUT | `/phone-numbers/:id` | `phone_numbers:manage` | Update config (label, clinic, agent, schedule) |
256
+ | DELETE | `/phone-numbers/:id` | `phone_numbers:manage` | Remove phone number |
257
+ | POST | `/phone-numbers/:id/connect-whatsapp` | `phone_numbers:manage` | Initiate WhatsApp connection |
258
+ | POST | `/phone-numbers/:id/disconnect-whatsapp` | `phone_numbers:manage` | Disconnect WhatsApp |
259
+ | GET | `/phone-numbers/:id/whatsapp-status` | `phone_numbers:read` | Connection status |
260
+ | PUT | `/phone-numbers/:id/schedule` | `phone_numbers:manage` | Update inbound call schedule |
261
+ | POST | `/phone-numbers/:id/toggle-agent` | `phone_numbers:manage` | Manual assign/unassign ElevenLabs agent |
262
+
263
+ ---
264
+
265
+ ## 4. Clinic Connections
266
+
267
+ Clinic connections are **extracted from JSONB into dedicated tables** because they contain encrypted secrets and have distinct query/lifecycle patterns.
268
+
269
+ ### 4.1 ClinicCalendarConnection
270
+
271
+ One Google Calendar OAuth connection per clinic. Stores encrypted refresh tokens for the Calendar API.
272
+
273
+ ```prisma
274
+ model ClinicCalendarConnection {
275
+ calcn_id String @id @default(uuid())
276
+ calcn_clinic_id String @unique // 1:1 with Clinic
277
+ calcn_google_email String?
278
+ calcn_encrypted_refresh_token String? // AES-256-GCM encrypted
279
+ calcn_calendar_id String?
280
+ calcn_calendar_name String?
281
+ calcn_timezone String @default("Europe/Istanbul")
282
+ calcn_appointment_duration Int @default(30) // minutes
283
+ calcn_working_hours Json @default("[]") // [{day, start, end}]
284
+ calcn_blocked_dates Json @default("[]") // [{date, reason}]
285
+ calcn_connected_at DateTime?
286
+ calcn_created_at DateTime @default(now())
287
+ calcn_updated_at DateTime @updatedAt
288
+
289
+ clinic Clinic @relation(fields: [calcn_clinic_id], references: [clinic_id], onDelete: Cascade)
290
+
291
+ @@map("clinic_calendar_connections")
292
+ }
293
+ ```
294
+
295
+ **Why extracted from JSONB:**
296
+ - Contains `calcn_encrypted_refresh_token` -- encrypted secrets should not live in a generic JSON blob. Dedicated columns allow explicit access control and audit.
297
+ - Queried independently: token refresh logic, FreeBusy API calls, and appointment tools all need this data without loading the full clinic settings.
298
+ - Lifecycle differs from clinic settings: connection/disconnection is a distinct operation with its own OAuth flow.
299
+
300
+ ### 4.2 ClinicMetaConnection
301
+
302
+ Multiple Meta Business API connections per clinic. Each connection represents one WhatsApp phone number or Instagram page. A clinic can have several WhatsApp numbers and Instagram connections simultaneously.
303
+
304
+ ```prisma
305
+ model ClinicMetaConnection {
306
+ meta_id String @id @default(uuid())
307
+ meta_clinic_id String // FK to clinics (1:many -- multiple connections per clinic)
308
+ meta_waba_id String? // WhatsApp Business Account ID
309
+ meta_phone_number_id String?
310
+ meta_display_phone String?
311
+ meta_encrypted_access_token String? // AES-256-GCM encrypted
312
+ meta_instagram_connected Boolean @default(false)
313
+ meta_instagram_page_id String?
314
+ meta_encrypted_page_token String? // AES-256-GCM encrypted
315
+ meta_connected_at DateTime?
316
+ meta_created_at DateTime @default(now())
317
+ meta_updated_at DateTime @updatedAt
318
+
319
+ clinic Clinic @relation(fields: [meta_clinic_id], references: [clinic_id], onDelete: Cascade)
320
+
321
+ @@map("clinic_meta_connections")
322
+ }
323
+ ```
324
+
325
+ **Why extracted from JSONB:**
326
+ - Two encrypted token fields (`meta_encrypted_access_token`, `meta_encrypted_page_token`).
327
+ - Queried on every incoming Meta webhook to resolve the clinic.
328
+ - Indexed by `meta_phone_number_id` for webhook routing (not shown in schema but critical for performance).
329
+ - Connection/disconnection is a distinct OAuth flow with its own state.
330
+
331
+ ### Why Not Keep Secrets in JSONB?
332
+
333
+ | Concern | JSONB column | Dedicated table |
334
+ |---------|-------------|-----------------|
335
+ | Encryption at field level | Must decrypt entire JSON, extract, re-encrypt on update | Encrypt/decrypt individual column |
336
+ | Query pattern | `WHERE settings->>'encrypted_token' IS NOT NULL` is awkward | `WHERE encrypted_refresh_token IS NOT NULL` |
337
+ | Audit trail | "settings changed" -- which field? | "calendar connection updated" -- clear |
338
+ | Access control | Cannot grant column-level DB permissions | Can restrict table access |
339
+ | Schema evolution | Add fields to JSON blob, hope nothing breaks | Add columns with proper migrations |
340
+
341
+ ---
342
+
343
+ ## 5. Routing Flow
344
+
345
+ ### 5.1 Incoming WhatsApp Message
346
+
347
+ ```
348
+ WhatsApp message arrives at webhook
349
+ |
350
+ v
351
+ Extract sender phone number + recipient phone number
352
+ |
353
+ v
354
+ Lookup: phone_numbers WHERE phone_number = recipient
355
+ AND phone_purpose = 'whatsapp'
356
+ AND phone_wa_connected = true
357
+ |
358
+ v
359
+ Found PhoneNumber record
360
+ |
361
+ +-- phone_clinic_id --> Clinic
362
+ | |
363
+ | +-- clinic_operator_phone (for operator workflow)
364
+ | +-- clinic_grace_period_seconds (self-contained, no fallback)
365
+ | +-- clinic_blacklisted_numbers (check sender)
366
+ | +-- calendarConnection (for appointment tools)
367
+ |
368
+ +-- phone_agent_id --> Agent
369
+ | |
370
+ | +-- agent_elevenlabs_id (for ElevenLabs WS connection)
371
+ | +-- agent_system_prompt
372
+ | +-- agent_language
373
+ |
374
+ +-- phone_tenant_id --> Tenant
375
+ |
376
+ +-- tenant_enabled_features (feature flags)
377
+ ```
378
+
379
+ ### 5.2 Incoming Voice Call
380
+
381
+ ```
382
+ Inbound call arrives at ElevenLabs SIP trunk
383
+ |
384
+ v
385
+ ElevenLabs routes to configured agent (by phone_elevenlabs_agent_id)
386
+ |
387
+ v
388
+ Post-call webhook fires with agent_id
389
+ |
390
+ v
391
+ Lookup: agents WHERE agent_elevenlabs_id = webhook.agent_id
392
+ |
393
+ v
394
+ Agent --> Clinic (agent_clinic_id) --> Tenant (agent_tenant_id)
395
+ |
396
+ v
397
+ Process call record, trigger post-call actions
398
+ ```
399
+
400
+ ### 5.3 Single-Clinic vs Multi-Clinic Routing
401
+
402
+ **Single-clinic tenant:**
403
+ - One default clinic, one or two phone numbers.
404
+ - Routing is trivial: every phone number points to the same clinic.
405
+ - No clinic selection UI needed. The clinic is implicit.
406
+ - All data (chats, calls, appointments) belongs to the single clinic.
407
+
408
+ **Multi-clinic tenant:**
409
+ - Multiple clinics, each with its own phone numbers.
410
+ - Routing is phone-number-based: the patient's choice of which number to contact determines which clinic they reach.
411
+ - Each clinic can have a different agent, different calendar, different operator.
412
+ - The dashboard shows a clinic selector, and data is filtered by clinic.
413
+
414
+ ```
415
+ Multi-clinic dental chain:
416
+
417
+ Tenant: "DentPlus"
418
+ |
419
+ +-- Clinic: "Kadikoy"
420
+ | +-- Phone: +905551001 (whatsapp, meta_business) --> Agent: "DentPlus Kadikoy AI"
421
+ | +-- Phone: +905551002 (inbound_call, elevenlabs) --> Agent: "DentPlus Kadikoy Voice"
422
+ | +-- CalendarConnection: dentplus.kadikoy@gmail.com
423
+ |
424
+ +-- Clinic: "Besiktas"
425
+ | +-- Phone: +905552001 (whatsapp, meta_business) --> Agent: "DentPlus Besiktas AI"
426
+ | +-- Phone: +905552002 (inbound_call, elevenlabs) --> Agent: "DentPlus Besiktas Voice"
427
+ | +-- CalendarConnection: dentplus.besiktas@gmail.com
428
+ |
429
+ +-- Clinic: "Atasehir"
430
+ +-- Phone: +905553001 (whatsapp, meta_business) --> Agent: "DentPlus Atasehir AI"
431
+ +-- CalendarConnection: dentplus.atasehir@gmail.com
432
+ ```
433
+
434
+ Patient texts `+905551001` --> routed to Kadikoy clinic --> Kadikoy AI agent responds --> appointments booked on Kadikoy calendar.
435
+
436
+ ---
437
+
438
+ ## 6. Clinic Configuration
439
+
440
+ Each clinic is **self-contained** -- every operational setting lives directly on the clinic row with a sensible default. There is no null-means-inherit pattern and no tenant-level fallback chain.
441
+
442
+ ### 6.1 Configuration Table
443
+
444
+ | Setting | Column | Type | Default | Description |
445
+ |---------|--------|------|---------|-------------|
446
+ | Language | `clinic_language` | String | `"tr"` | AI and notification language |
447
+ | AI provider | `clinic_ai_provider` | String | `"elevenlabs"` | AI service provider |
448
+ | AI model | `clinic_ai_model` | String | `""` | Specific model override |
449
+ | Grace period (seconds) | `clinic_grace_period_seconds` | Int | 180 | Time before AI takes over |
450
+ | Operator phone | `clinic_operator_phone` | String? | null (disabled) | Doctor's WhatsApp number |
451
+ | Operator REF prefix | `clinic_operator_prefix` | String | `"R"` | REF code prefix letter |
452
+ | Operator timeout (hours) | `clinic_operator_timeout_hours` | Int | 24 | Hours before request expires |
453
+ | AI shift | `clinic_ai_shift_enabled` + `clinic_ai_shift_schedule` | Bool + Json | disabled | Schedule windows |
454
+ | Blacklisted numbers | `clinic_blacklisted_numbers` | String[] | [] | Numbers that bypass AI |
455
+ | Fixed first message | `clinic_fixed_first_message` | String? | null (disabled) | Auto-greeting on new session |
456
+ | SMS enabled | `clinic_sms_enabled` | Bool | false | Whether SMS notifications are active |
457
+ | SMS phones | `clinic_sms_phones` | String[] | [] | Recipient numbers for SMS |
458
+ | Notification phones | `clinic_notification_phones` | String[] | [] | Recipient numbers for push notifications |
459
+ | Message retention (days) | `clinic_message_retention_days` | Int | 7 | Auto-deletion via BullMQ job |
460
+ | Appointment duration (min) | `calcn_appointment_duration` | Int | 30 | On `ClinicCalendarConnection` |
461
+
462
+ ### 6.2 Reading Config
463
+
464
+ ```typescript
465
+ // No resolution logic needed -- read directly from clinic
466
+ const gracePeriod = clinic.clinic_grace_period_seconds; // always has a value (default 180)
467
+ const operatorPrefix = clinic.clinic_operator_prefix; // always has a value (default "R")
468
+ const operatorTimeout = clinic.clinic_operator_timeout_hours; // always has a value (default 24)
469
+ const operatorPhone = clinic.clinic_operator_phone; // null means operator workflow disabled
470
+ const retentionDays = clinic.clinic_message_retention_days; // always has a value (default 7)
471
+ ```
472
+
473
+ No `resolveClinicSettings()` function is needed. The clinic row is the single source of truth.
474
+
475
+ ---
476
+
477
+ ## 7. Examples
478
+
479
+ ### Example 1: Single-Clinic Tenant (Solo Dental Practice)
480
+
481
+ **Tenant:** "Dr. Ayse Yilmaz Dis Klinigi"
482
+
483
+ ```
484
+ Tenant
485
+ tenant_id: "t-001"
486
+ tenant_name: "Dr. Ayse Yilmaz Dis Klinigi"
487
+ tenant_enabled_features: ["whatsapp_agent", "google_calendar", "operator_workflow"]
488
+
489
+ Clinic (auto-created on registration)
490
+ clinic_id: "c-001"
491
+ clinic_tenant_id: "t-001"
492
+ clinic_name: "Dr. Ayse Yilmaz Dis Klinigi"
493
+ clinic_slug: "main"
494
+ clinic_is_default: true
495
+ clinic_language: "tr"
496
+ clinic_operator_phone: "+905559876543" (Dr. Ayse's personal WhatsApp)
497
+ clinic_operator_prefix: "K"
498
+ clinic_operator_timeout_hours: 24
499
+ clinic_grace_period_seconds: 180
500
+ clinic_message_retention_days: 7
501
+
502
+ PhoneNumber
503
+ phone_id: "p-001"
504
+ phone_tenant_id: "t-001"
505
+ phone_clinic_id: "c-001"
506
+ phone_number: "+905551112233"
507
+ phone_purpose: whatsapp
508
+ phone_provider: meta_business
509
+ phone_wa_connected: true
510
+ phone_agent_id: "a-001"
511
+
512
+ Agent
513
+ agent_id: "a-001"
514
+ agent_tenant_id: "t-001"
515
+ agent_clinic_id: "c-001"
516
+ agent_elevenlabs_id: "el_abc123"
517
+ agent_name: "Ayse Klinik AI"
518
+ agent_language: "tr"
519
+
520
+ ClinicCalendarConnection
521
+ calcn_clinic_id: "c-001"
522
+ calcn_google_email: "ayse.klinik@gmail.com"
523
+ calcn_encrypted_refresh_token: "AES256GCM:..."
524
+ calcn_calendar_id: "primary"
525
+ calcn_appointment_duration: 30
526
+ calcn_working_hours: [
527
+ {"day": 1, "start": "09:00", "end": "18:00"},
528
+ {"day": 2, "start": "09:00", "end": "18:00"},
529
+ {"day": 3, "start": "09:00", "end": "18:00"},
530
+ {"day": 4, "start": "09:00", "end": "18:00"},
531
+ {"day": 5, "start": "09:00", "end": "17:00"}
532
+ ]
533
+ ```
534
+
535
+ **What happens when a patient texts +905551112233:**
536
+
537
+ 1. Meta webhook arrives. Lookup `phone_numbers` by `+905551112233` + `whatsapp`.
538
+ 2. Found: clinic = `c-001`, agent = `a-001`.
539
+ 3. Read settings directly from clinic: grace period = 180, operator prefix = "K".
540
+ 4. Check blacklist: `clinic_blacklisted_numbers` is empty.
541
+ 5. Route to Agent `a-001` (ElevenLabs ID `el_abc123`).
542
+ 6. AI responds. If patient sends photo, forward to operator phone `+905559876543`.
543
+ 7. If patient asks for appointment, AI checks `calcn_working_hours` and Google FreeBusy.
544
+
545
+ The user (Dr. Ayse, role = `owner`) never sees a clinic selector in the UI. The single default clinic is implicit everywhere.
546
+
547
+ ---
548
+
549
+ ### Example 2: Multi-Clinic Dental Chain (3 Branches)
550
+
551
+ **Tenant:** "DentPlus"
552
+
553
+ ```
554
+ Tenant
555
+ tenant_id: "t-002"
556
+ tenant_name: "DentPlus"
557
+ tenant_enabled_features: [
558
+ "whatsapp_agent", "google_calendar", "operator_workflow",
559
+ "inbound_agent", "appointment_validation"
560
+ ]
561
+ ```
562
+
563
+ #### Clinic 1: Kadikoy (default)
564
+
565
+ ```
566
+ Clinic
567
+ clinic_id: "c-010"
568
+ clinic_name: "DentPlus Kadikoy"
569
+ clinic_slug: "kadikoy"
570
+ clinic_is_default: true
571
+ clinic_operator_phone: "+905551110001" (Dr. Mehmet)
572
+ clinic_operator_prefix: "D"
573
+ clinic_operator_timeout_hours: 8
574
+ clinic_grace_period_seconds: 120
575
+ clinic_message_retention_days: 7
576
+
577
+ PhoneNumbers:
578
+ +905550010001 purpose=whatsapp provider=meta_business agent="DentPlus Kadikoy Chat AI"
579
+ +905550010002 purpose=inbound_call provider=elevenlabs agent="DentPlus Kadikoy Voice AI"
580
+ +905550010003 purpose=outbound_call provider=elevenlabs agent="DentPlus Outbound"
581
+
582
+ CalendarConnection:
583
+ google_email: dentplus.kadikoy@gmail.com
584
+ appointment_duration: 45
585
+ working_hours: Mon-Fri 09:00-19:00, Sat 10:00-14:00
586
+ ```
587
+
588
+ #### Clinic 2: Besiktas
589
+
590
+ ```
591
+ Clinic
592
+ clinic_id: "c-011"
593
+ clinic_name: "DentPlus Besiktas"
594
+ clinic_slug: "besiktas"
595
+ clinic_is_default: false
596
+ clinic_operator_phone: "+905551110002" (Dr. Elif)
597
+ clinic_operator_prefix: "B"
598
+ clinic_operator_timeout_hours: 12
599
+ clinic_grace_period_seconds: 90
600
+ clinic_message_retention_days: 7
601
+
602
+ PhoneNumbers:
603
+ +905550020001 purpose=whatsapp provider=meta_business agent="DentPlus Besiktas Chat AI"
604
+ +905550020002 purpose=inbound_call provider=elevenlabs agent="DentPlus Besiktas Voice AI"
605
+
606
+ CalendarConnection:
607
+ google_email: dentplus.besiktas@gmail.com
608
+ appointment_duration: 30 (shorter appointments at this branch)
609
+ working_hours: Mon-Sat 08:00-20:00
610
+ ```
611
+
612
+ #### Clinic 3: Atasehir
613
+
614
+ ```
615
+ Clinic
616
+ clinic_id: "c-012"
617
+ clinic_name: "DentPlus Atasehir"
618
+ clinic_slug: "atasehir"
619
+ clinic_is_default: false
620
+ clinic_operator_phone: null (no operator workflow -- AI only)
621
+ clinic_operator_prefix: "D"
622
+ clinic_operator_timeout_hours: 12
623
+ clinic_grace_period_seconds: 120
624
+ clinic_message_retention_days: 7
625
+
626
+ PhoneNumbers:
627
+ +905550030001 purpose=whatsapp provider=meta_business agent="DentPlus Atasehir Chat AI"
628
+
629
+ CalendarConnection:
630
+ google_email: dentplus.atasehir@gmail.com
631
+ appointment_duration: 45
632
+ working_hours: Mon-Fri 10:00-18:00
633
+ ```
634
+
635
+ #### Users and Clinic Assignments
636
+
637
+ ```
638
+ User: Ahmet (owner)
639
+ role: owner
640
+ --> sees ALL three clinics (no assignments needed)
641
+
642
+ User: Zeynep (admin)
643
+ role: admin
644
+ assignments: [c-010 (Kadikoy), c-011 (Besiktas)]
645
+ --> sees Kadikoy + Besiktas data
646
+
647
+ User: Dr. Mehmet (doctor)
648
+ role: doctor
649
+ assignments: [c-010 (Kadikoy)]
650
+ --> sees only Kadikoy patients, appointments, chats
651
+
652
+ User: Fatma (receptionist)
653
+ role: receptionist
654
+ assignments: [c-011 (Besiktas), c-012 (Atasehir)]
655
+ --> sees Besiktas + Atasehir chats, appointments, leads
656
+ ```
657
+
658
+ #### Settings Per Clinic
659
+
660
+ | Setting | Kadikoy | Besiktas | Atasehir |
661
+ |---------|---------|----------|----------|
662
+ | Grace period (s) | 120 | 90 | 120 |
663
+ | Operator prefix | "D" | "B" | "D" |
664
+ | Operator timeout (h) | 8 | 12 | 12 |
665
+ | Appt duration (min) | 45 (calendar) | 30 (calendar) | 45 (calendar) |
666
+ | Operator phone | +905551110001 | +905551110002 | null (disabled) |
667
+ | WhatsApp provider | Meta Business | Meta Business | Meta Business |
668
+ | Message retention | 7 days | 7 days | 7 days |
669
+
670
+ #### Routing in Action
671
+
672
+ **Patient A texts +905550020001 (Besiktas WhatsApp):**
673
+ - Lookup phone number --> Besiktas clinic (`c-011`)
674
+ - Agent: "DentPlus Besiktas Chat AI"
675
+ - Grace period: 90s (Besiktas override)
676
+ - If patient sends photo: forward to Dr. Elif (+905551110002)
677
+ - REF code prefix: "B" (Besiktas override) --> B0001
678
+ - Appointment: booked on `dentplus.besiktas@gmail.com`, 30-minute slots
679
+
680
+ **Patient B calls +905550010002 (Kadikoy inbound):**
681
+ - ElevenLabs routes to "DentPlus Kadikoy Voice AI"
682
+ - Post-call webhook: agent_elevenlabs_id --> Agent --> Clinic = Kadikoy
683
+ - Call record stored with `call_clinic_id = c-010`
684
+ - Lead generated with `lead_clinic_id = c-010`
685
+
686
+ **Patient C texts +905550030001 (Atasehir WhatsApp):**
687
+ - Lookup phone number --> Atasehir clinic (`c-012`)
688
+ - Operator phone is null --> operator workflow disabled for this clinic
689
+ - AI handles everything directly (no photo forwarding)
690
+
691
+ ---
692
+
693
+ ## Appendix: Agent Model
694
+
695
+ Agents are not tied to a specific phone number or call direction. The same agent can serve WhatsApp chat, inbound calls, and outbound campaigns through different PhoneNumber records pointing to it.
696
+
697
+ ```prisma
698
+ model Agent {
699
+ agent_id String @id @default(uuid())
700
+ agent_tenant_id String
701
+ agent_clinic_id String? // null = tenant-level (shared across clinics)
702
+ agent_elevenlabs_id String // ElevenLabs agent ID
703
+ agent_name String @default("")
704
+ agent_description String @default("")
705
+
706
+ // Voice & language
707
+ agent_voice_id String @default("")
708
+ agent_language String @default("tr")
709
+ agent_greeting String @default("")
710
+
711
+ // AI config
712
+ agent_system_prompt String @default("")
713
+ agent_ai_provider String? // null = use clinic default
714
+ agent_ai_model String? // null = use clinic default
715
+
716
+ // Post-call processing
717
+ agent_post_call_strategy PostCallStrategy @default(summarize)
718
+ agent_post_call_wa_notify Boolean @default(true)
719
+ agent_post_call_sms_notify Boolean @default(false)
720
+ agent_summary_prompt String @default("")
721
+ agent_wa_message_template String @default("")
722
+
723
+ agent_extra_config Json @default("{}")
724
+ agent_is_active Boolean @default(true)
725
+ agent_created_at DateTime @default(now())
726
+ agent_updated_at DateTime @updatedAt
727
+
728
+ tenant Tenant @relation(...)
729
+ clinic Clinic? @relation(...)
730
+ phoneNumbers PhoneNumber[]
731
+ calls Call[]
732
+ outboundCampaigns OutboundCampaign[]
733
+ validationBatches AppointmentValidationBatch[]
734
+
735
+ @@index([agent_tenant_id])
736
+ @@index([agent_clinic_id])
737
+ @@index([agent_elevenlabs_id])
738
+ @@map("agents")
739
+ }
740
+ ```
741
+
742
+ **Tenant-level agents** (`agent_clinic_id = null`) are shared across all clinics. Clinic-level agents are scoped to a specific clinic. A phone number references an agent via `phone_agent_id`; the agent's clinic assignment does not need to match the phone's clinic assignment (though it usually does).