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,458 @@
1
+ # 11. Billing System
2
+
3
+ > Subscription-based billing with usage tracking, period snapshots, and threshold alerts.
4
+ > Last updated: 2026-04-02
5
+
6
+ ---
7
+
8
+ ## Billing Model Overview
9
+
10
+ The billing system tracks tenant subscriptions, usage, and charges through five interconnected entities:
11
+
12
+ ```
13
+ Plan (defines quotas)
14
+ |
15
+ v
16
+ Payment (subscription period with start/end dates)
17
+ |
18
+ +---> BillingEvent (append-only ledger of charges/credits)
19
+ |
20
+ +---> BillingPeriodSnapshot (immutable usage record at period end)
21
+ |
22
+ +---> BillingAlert (threshold notifications: 75%, 90%, 100%)
23
+ ```
24
+
25
+ ### Plans
26
+
27
+ Plans define what a tenant gets. They are system-wide records managed by superadmin/sales.
28
+
29
+ ```prisma
30
+ model Plan {
31
+ plan_id String @id @default(uuid())
32
+ plan_name String
33
+ plan_slug String @unique
34
+ plan_price Decimal
35
+ plan_overage_rate Decimal
36
+ plan_included_inbound_minutes Int @default(0)
37
+ plan_included_inbound_calls Int @default(0)
38
+ plan_included_outbound_minutes Int @default(0)
39
+ plan_included_outbound_calls Int @default(0)
40
+ plan_included_wa_chats Int @default(0)
41
+ plan_language_support LanguageSupport @default(single)
42
+ plan_is_active Boolean @default(true)
43
+ plan_sort_order Int @default(0)
44
+ plan_created_at DateTime @default(now())
45
+ plan_updated_at DateTime @updatedAt
46
+
47
+ tenants Tenant[]
48
+ snapshots BillingPeriodSnapshot[]
49
+
50
+ @@map("plans")
51
+ }
52
+ ```
53
+
54
+ Quotas defined per plan:
55
+
56
+ | Quota | Field | Description |
57
+ |-------|-------|-------------|
58
+ | Inbound minutes | `plan_included_inbound_minutes` | Total inbound call minutes per billing period |
59
+ | Inbound calls | `plan_included_inbound_calls` | Total inbound call count per period |
60
+ | Outbound minutes | `plan_included_outbound_minutes` | Outbound call minutes (campaigns, validation) |
61
+ | Outbound calls | `plan_included_outbound_calls` | Outbound call count |
62
+ | WhatsApp chats | `plan_included_wa_chats` | Billable WhatsApp chat sessions per period |
63
+ | Language support | `plan_language_support` | single, dual, or multi |
64
+
65
+ ### Payments
66
+
67
+ A Payment represents a subscription period. Each payment has explicit start/end dates and is linked to the plan in effect at the time.
68
+
69
+ ```prisma
70
+ model Payment {
71
+ payment_id String @id @default(uuid())
72
+ payment_tenant_id String
73
+ payment_type PaymentType @default(subscription) // subscription | top_up
74
+ payment_plan_slug String
75
+ payment_plan_name String
76
+ payment_amount Decimal
77
+ payment_extra_minutes Int @default(0)
78
+ payment_period_start DateTime
79
+ payment_period_end DateTime
80
+ payment_method PaymentMethod @default(cash) // cash | bank_transfer | other
81
+ payment_notes String @default("")
82
+ payment_recorded_by_id String
83
+ payment_created_at DateTime @default(now())
84
+ payment_updated_at DateTime @updatedAt
85
+
86
+ tenant Tenant @relation(...)
87
+ recordedBy User @relation("RecordedBy", ...)
88
+ snapshots BillingPeriodSnapshot[]
89
+ alerts BillingAlert[]
90
+
91
+ @@index([payment_tenant_id])
92
+ @@index([payment_tenant_id, payment_period_end(sort: Desc)])
93
+ @@map("payments")
94
+ }
95
+ ```
96
+
97
+ ### BillingEvents (Append-Only Ledger)
98
+
99
+ Every financial event is recorded as an immutable billing event. These are never updated or deleted.
100
+
101
+ ```prisma
102
+ model BillingEvent {
103
+ billing_id String @id @default(uuid())
104
+ billing_tenant_id String
105
+ billing_clinic_id String? // FK -> clinics. Populated for call_charge (copied from call's clinic_id). Null for tenant-level events (subscription, top_up).
106
+ billing_type BillingEventType // call_charge | subscription | top_up | refund
107
+ billing_amount Decimal
108
+ billing_currency String @default("TRY")
109
+ billing_call_id String?
110
+ billing_description String @default("")
111
+ billing_created_at DateTime @default(now())
112
+
113
+ tenant Tenant @relation(...)
114
+ clinic Clinic? @relation(...)
115
+ call Call? @relation(...)
116
+
117
+ @@index([billing_tenant_id, billing_created_at(sort: Desc)])
118
+ @@index([billing_clinic_id, billing_created_at(sort: Desc)])
119
+ @@map("billing_events")
120
+ }
121
+ ```
122
+
123
+ Event types:
124
+
125
+ | Type | When Created | `billing_clinic_id` |
126
+ |------|-------------|---------------------|
127
+ | `call_charge` | After each call completes -- amount = duration * overage_rate | Copied from the call's `call_clinic_id`. Enables per-clinic cost breakdown. |
128
+ | `subscription` | When a new payment/subscription is recorded | `null` (tenant-level event) |
129
+ | `top_up` | When extra minutes are purchased | `null` (tenant-level event) |
130
+ | `refund` | When a charge is refunded | Copied from the original event's clinic, if applicable |
131
+
132
+ ### BillingPeriodSnapshots
133
+
134
+ An immutable snapshot of usage at the end of a billing period. Once created, it never changes. This provides a historical record even if the tenant's plan or data changes later.
135
+
136
+ ```prisma
137
+ model BillingPeriodSnapshot {
138
+ snapshot_id String @id @default(uuid())
139
+ snapshot_tenant_id String
140
+ snapshot_payment_id String
141
+ snapshot_plan_id String? // FK to Plan at time of snapshot (historical reference)
142
+ snapshot_period_start DateTime
143
+ snapshot_period_end DateTime
144
+
145
+ // Actual usage during period
146
+ snapshot_total_calls Int @default(0)
147
+ snapshot_inbound_calls Int @default(0)
148
+ snapshot_inbound_minutes Decimal @default(0)
149
+ snapshot_outbound_calls Int @default(0)
150
+ snapshot_outbound_minutes Decimal @default(0)
151
+ snapshot_total_charges Decimal @default(0)
152
+ snapshot_wa_billable_chats Int @default(0)
153
+ snapshot_wa_total_sessions Int @default(0)
154
+ snapshot_wa_total_messages Int @default(0)
155
+ snapshot_wa_ai_messages Int @default(0)
156
+ snapshot_wa_el_cost Decimal @default(0)
157
+ snapshot_wa_stt_count Int @default(0)
158
+ snapshot_wa_stt_seconds Decimal @default(0)
159
+ snapshot_created_at DateTime @default(now())
160
+
161
+ tenant Tenant @relation(...)
162
+ payment Payment @relation(...)
163
+ plan Plan? @relation(...)
164
+
165
+ @@index([snapshot_tenant_id, snapshot_period_start(sort: Desc)])
166
+ @@map("billing_period_snapshots")
167
+ }
168
+ ```
169
+
170
+ The `snapshot_plan_id` field is critical: it captures which plan was active at the time of the snapshot. If the tenant upgrades later, historical snapshots still reference the old plan's limits for accurate reporting.
171
+
172
+ ### BillingAlerts
173
+
174
+ Usage threshold alerts. A unique constraint prevents duplicate alerts for the same threshold within the same billing period.
175
+
176
+ ```prisma
177
+ model BillingAlert {
178
+ alert_id String @id @default(uuid())
179
+ alert_tenant_id String
180
+ alert_type AlertType // usage_75 | usage_90 | usage_100 | period_expiring
181
+ alert_service AlertService // inbound_minutes | inbound_calls | wa_chats | billing_period
182
+ alert_payment_id String
183
+ alert_created_at DateTime @default(now())
184
+
185
+ tenant Tenant @relation(...)
186
+ payment Payment @relation(...)
187
+
188
+ @@unique([alert_tenant_id, alert_type, alert_service, alert_payment_id])
189
+ @@map("billing_alerts")
190
+ }
191
+ ```
192
+
193
+ The `@@unique` constraint on `[tenant_id, type, service, payment_id]` ensures a tenant receives at most one alert of each type per service per billing period. Once the "90% inbound minutes" alert fires, it will not fire again until the next period.
194
+
195
+ ---
196
+
197
+ ## Call Charging
198
+
199
+ ### Rate
200
+
201
+ Configurable per plan via `plan_overage_rate`. Current default: **1.5 TRY per minute**.
202
+
203
+ ### Process
204
+
205
+ After each call completes (via ElevenLabs post-call webhook), the billing service creates a `BillingEvent`:
206
+
207
+ ```typescript
208
+ async logCallCharge(tenantId: string, clinicId: string, callId: string, durationSeconds: number): Promise<void> {
209
+ const tenant = await this.prisma.tenant.findUnique({ where: { tenant_id: tenantId }, include: { plan: true } });
210
+ const rate = tenant.plan.plan_overage_rate;
211
+ const minutes = Math.ceil(durationSeconds / 60);
212
+ const amount = minutes * rate;
213
+
214
+ await this.prisma.billingEvent.create({
215
+ data: {
216
+ billing_tenant_id: tenantId,
217
+ billing_clinic_id: clinicId, // Copied from the call's clinic for per-clinic cost breakdown
218
+ billing_type: 'call_charge',
219
+ billing_amount: amount,
220
+ billing_call_id: callId,
221
+ billing_description: `Call charge: ${minutes} min @ ${rate} TRY/min`,
222
+ },
223
+ });
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Usage Calculation
230
+
231
+ ### Active Payment Lookup
232
+
233
+ The active payment is the one whose period has not yet ended. For a given tenant, find the payment where `payment_period_end > now()`, sorted by `payment_period_end DESC`, take the first result.
234
+
235
+ ```typescript
236
+ async getActivePayment(tenantId: string): Promise<Payment | null> {
237
+ return this.prisma.payment.findFirst({
238
+ where: {
239
+ payment_tenant_id: tenantId,
240
+ payment_period_end: { gt: new Date() },
241
+ },
242
+ orderBy: { payment_period_end: 'desc' },
243
+ });
244
+ }
245
+ ```
246
+
247
+ **Index used:** `@@index([payment_tenant_id, payment_period_end(sort: Desc)])` -- this is the most critical billing index.
248
+
249
+ ### Usage Aggregation
250
+
251
+ Within the active payment's period, aggregate:
252
+
253
+ | Metric | Source |
254
+ |--------|--------|
255
+ | Inbound calls / minutes | `Call` table (where `call_direction = 'inbound'`, `call_start_time` within period) |
256
+ | Outbound calls / minutes | `Call` table (where `call_direction = 'outbound'`, `call_start_time` within period) |
257
+ | WhatsApp sessions | `WhatsAppSession` table (where `created_at` within period, billable = true) |
258
+ | STT usage | `SttUsage` table (where `stt_created_at` within period) |
259
+ | Total charges | `BillingEvent` table (where `billing_created_at` within period, type = `call_charge`) |
260
+
261
+ ### Comparison Against Quotas
262
+
263
+ The usage summary compares aggregated values against the plan's included quotas:
264
+
265
+ ```typescript
266
+ {
267
+ inbound_minutes: { used: 450, included: 500, percentage: 90 },
268
+ inbound_calls: { used: 120, included: 200, percentage: 60 },
269
+ wa_chats: { used: 80, included: 100, percentage: 80 },
270
+ total_charges: 675.00,
271
+ period: { start: '2026-03-01', end: '2026-03-31' },
272
+ }
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Period Lifecycle
278
+
279
+ ### New Payment Recorded
280
+
281
+ When a new payment is recorded:
282
+
283
+ 1. Find the previous active payment (if any).
284
+ 2. Snapshot the previous period's usage (see below).
285
+ 3. The new payment becomes the active payment.
286
+
287
+ ### Period Snapshot on Expiry
288
+
289
+ A BullMQ repeatable job runs **daily at 00:05 Istanbul time**. It finds all payments where `payment_period_end < now()` and no snapshot exists yet, then creates an immutable `BillingPeriodSnapshot` for each.
290
+
291
+ ```typescript
292
+ // BullMQ job: billing:snapshot-expired-periods
293
+ // Cron: '5 0 * * *' (00:05 daily, Europe/Istanbul)
294
+
295
+ async snapshotExpiredPeriods(): Promise<void> {
296
+ const expiredPayments = await this.prisma.payment.findMany({
297
+ where: {
298
+ payment_period_end: { lt: new Date() },
299
+ snapshots: { none: {} }, // No snapshot yet
300
+ },
301
+ });
302
+
303
+ for (const payment of expiredPayments) {
304
+ const usage = await this.aggregateUsage(payment.payment_tenant_id, payment.payment_period_start, payment.payment_period_end);
305
+ await this.prisma.billingPeriodSnapshot.create({
306
+ data: {
307
+ snapshot_tenant_id: payment.payment_tenant_id,
308
+ snapshot_payment_id: payment.payment_id,
309
+ snapshot_plan_id: /* tenant's plan at time of snapshot */,
310
+ snapshot_period_start: payment.payment_period_start,
311
+ snapshot_period_end: payment.payment_period_end,
312
+ ...usage,
313
+ },
314
+ });
315
+ }
316
+ }
317
+ ```
318
+
319
+ ### Billing Alert Check
320
+
321
+ A separate BullMQ repeatable job runs **daily at 09:00 Istanbul time**. It checks each tenant's current usage against plan quotas and sends alerts via SMS (NetGSM) when thresholds are crossed.
322
+
323
+ ```typescript
324
+ // BullMQ job: billing:check-alerts
325
+ // Cron: '0 9 * * *' (09:00 daily, Europe/Istanbul)
326
+
327
+ async checkAndSendBillingAlerts(): Promise<void> {
328
+ const tenants = await this.getTenantsWithActivePayments();
329
+
330
+ for (const { tenant, payment, plan } of tenants) {
331
+ const usage = await this.getUsageSummary(tenant.tenant_id);
332
+
333
+ for (const [service, metric] of [
334
+ ['inbound_minutes', usage.inbound_minutes],
335
+ ['inbound_calls', usage.inbound_calls],
336
+ ['wa_chats', usage.wa_chats],
337
+ ]) {
338
+ for (const threshold of [75, 90, 100]) {
339
+ if (metric.percentage >= threshold) {
340
+ // Unique constraint prevents duplicates
341
+ await this.prisma.billingAlert.create({
342
+ data: {
343
+ alert_tenant_id: tenant.tenant_id,
344
+ alert_type: `usage_${threshold}`,
345
+ alert_service: service,
346
+ alert_payment_id: payment.payment_id,
347
+ },
348
+ }).catch(() => {}); // Ignore unique constraint violation (already sent)
349
+
350
+ // Send SMS notification
351
+ await this.netgsmService.sendSms(tenant.manager_phone, alertMessage);
352
+ }
353
+ }
354
+ }
355
+ }
356
+ }
357
+ ```
358
+
359
+ **Alert types:**
360
+
361
+ | Type | Trigger |
362
+ |------|---------|
363
+ | `usage_75` | Usage reaches 75% of included quota |
364
+ | `usage_90` | Usage reaches 90% of included quota |
365
+ | `usage_100` | Usage reaches 100% -- overage charges begin |
366
+ | `period_expiring` | Billing period ends within 3 days |
367
+
368
+ **Services tracked:**
369
+
370
+ | Service | Quota Source |
371
+ |---------|-------------|
372
+ | `inbound_minutes` | `plan_included_inbound_minutes` |
373
+ | `inbound_calls` | `plan_included_inbound_calls` |
374
+ | `wa_chats` | `plan_included_wa_chats` |
375
+ | `billing_period` | Payment `period_end` date |
376
+
377
+ ---
378
+
379
+ ## Data Model Summary
380
+
381
+ ### Tables
382
+
383
+ | Table | Purpose | Mutable |
384
+ |-------|---------|---------|
385
+ | `plans` | Define quotas and pricing | Yes (superadmin) |
386
+ | `payments` | Subscription periods with start/end dates | Yes (notes, method) |
387
+ | `billing_events` | Append-only ledger of all financial events | No (append-only) |
388
+ | `billing_period_snapshots` | Immutable usage record at period end | No (immutable) |
389
+ | `billing_alerts` | Usage threshold alert records | No (append-only) |
390
+
391
+ ### Enums
392
+
393
+ ```prisma
394
+ enum BillingEventType {
395
+ call_charge
396
+ subscription
397
+ top_up
398
+ refund
399
+ }
400
+
401
+ enum PaymentType {
402
+ subscription
403
+ top_up
404
+ }
405
+
406
+ enum PaymentMethod {
407
+ cash
408
+ bank_transfer
409
+ other
410
+ }
411
+
412
+ enum AlertType {
413
+ usage_75
414
+ usage_90
415
+ usage_100
416
+ period_expiring
417
+ }
418
+
419
+ enum AlertService {
420
+ inbound_minutes
421
+ inbound_calls
422
+ wa_chats
423
+ billing_period
424
+ }
425
+ ```
426
+
427
+ ### Key Indexes
428
+
429
+ | Index | Purpose |
430
+ |-------|---------|
431
+ | `payments(tenant_id, period_end DESC)` | Active payment lookup -- the single most important billing query |
432
+ | `billing_events(tenant_id, created_at DESC)` | Usage aggregation within a period |
433
+ | `billing_events(clinic_id, created_at DESC)` | Per-clinic cost breakdown |
434
+ | `billing_period_snapshots(tenant_id, period_start DESC)` | Historical period browsing |
435
+ | `billing_alerts(tenant_id, type, service, payment_id) UNIQUE` | Duplicate alert prevention |
436
+
437
+ ---
438
+
439
+ ## BullMQ Jobs
440
+
441
+ | Job Name | Schedule | What It Does |
442
+ |----------|----------|-------------|
443
+ | `billing:snapshot-expired-periods` | Daily at 00:05 (Europe/Istanbul) | Snapshot usage for all expired billing periods |
444
+ | `billing:check-alerts` | Daily at 09:00 (Europe/Istanbul) | Check usage thresholds and send SMS alerts |
445
+
446
+ ---
447
+
448
+ ## Service API
449
+
450
+ The billing service exposes these methods (Mongoose calls migrated to Prisma):
451
+
452
+ | Method | Prisma Equivalent | Description |
453
+ |--------|-------------------|-------------|
454
+ | `logCallCharge()` | `prisma.billingEvent.create()` | Log a call charge as a billing event |
455
+ | `getUsageSummary()` | Prisma aggregation queries | Current period usage vs. plan quotas |
456
+ | `getActivePayment()` | `prisma.payment.findFirst()` with period_end filter | Find current active payment |
457
+ | `snapshotExpiredPeriods()` | BullMQ repeatable job | Create snapshots for ended periods |
458
+ | `checkAndSendBillingAlerts()` | BullMQ repeatable job | Check thresholds, send SMS via NetGSM |
@@ -0,0 +1,216 @@
1
+ # 12. Security Architecture
2
+
3
+ > Security is not a separate phase -- it is built into every migration phase from day one.
4
+ > Last updated: 2026-04-02
5
+
6
+ ---
7
+
8
+ ## Data Encryption
9
+
10
+ ### Six AES-256-GCM Encryption Keys
11
+
12
+ Each domain has its own encryption key to limit blast radius. Compromise of one key does not expose data encrypted by another.
13
+
14
+ | Key | Env Variable | What It Protects |
15
+ |-----|-------------|-----------------|
16
+ | Google tokens | `GOOGLE_TOKEN_ENCRYPTION_KEY` | OAuth2 refresh tokens for Google Calendar |
17
+ | Meta tokens | `META_TOKEN_ENCRYPTION_KEY` | Page access tokens, WABA tokens for WhatsApp Business + Instagram |
18
+ | TekTipPay | `TEKTIPPAY_ENCRYPTION_KEY` | Payment API keys and secrets |
19
+ | Message content | `MESSAGE_ENCRYPTION_KEY` | Chat message text (`msg_text`, `msg_quoted_text`), operator request text |
20
+ | Patient PII | `PATIENT_PII_ENCRYPTION_KEY` | TC Kimlik, medical history, exam records, clinical notes, document notes, photo set notes |
21
+ | Patient summaries | `PATIENT_SUMMARY_ENCRYPTION_KEY` | AI-generated patient summaries (`patient_ai_summary`) |
22
+
23
+ All keys are 32-byte hex strings. Generate with: `openssl rand -hex 32`.
24
+
25
+ ### EncryptionService (Shared)
26
+
27
+ A single `@Injectable()` service used across the application. Each caller passes the appropriate key for their domain.
28
+
29
+ ```typescript
30
+ @Injectable()
31
+ export class EncryptionService {
32
+ encrypt(plaintext: string, key: string): string {
33
+ const iv = randomBytes(12);
34
+ const cipher = createCipheriv('aes-256-gcm', Buffer.from(key, 'hex'), iv);
35
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
36
+ const authTag = cipher.getAuthTag();
37
+ return Buffer.concat([iv, authTag, encrypted]).toString('base64');
38
+ }
39
+
40
+ decrypt(ciphertext: string, key: string): string {
41
+ const buf = Buffer.from(ciphertext, 'base64');
42
+ const iv = buf.subarray(0, 12);
43
+ const authTag = buf.subarray(12, 28);
44
+ const data = buf.subarray(28);
45
+ const decipher = createDecipheriv('aes-256-gcm', Buffer.from(key, 'hex'), iv);
46
+ decipher.setAuthTag(authTag);
47
+ return Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8');
48
+ }
49
+ }
50
+ ```
51
+
52
+ **Wire format:** `base64(iv[12] + authTag[16] + ciphertext[...])` -- a single opaque string stored in the database.
53
+
54
+ ### Per-Domain Key Derivation
55
+
56
+ All encryption domains (Google, Meta, TekTipPay, messages, patient PII, patient summaries) use the master key directly since there is no per-entity isolation requirement. Tenant isolation is enforced at the query layer, not the encryption layer.
57
+
58
+ ### What Is Encrypted at Field Level vs. Disk Level
59
+
60
+ | Data | Encryption Level | Reasoning |
61
+ |------|-----------------|-----------|
62
+ | Google OAuth refresh tokens | **Field-level** (AES-256-GCM) | Calendar access if exposed. Already encrypted in current system. |
63
+ | Meta Business access tokens | **Field-level** (AES-256-GCM) | WhatsApp Business + Instagram takeover if exposed. |
64
+ | TekTipPay credentials | **Field-level** (AES-256-GCM) | Payment system access if exposed. |
65
+ | Chat message text | **Field-level** (AES-256-GCM) | `msg_text`, `msg_quoted_text` encrypted with `MESSAGE_ENCRYPTION_KEY`. Operator request text also encrypted. |
66
+ | Patient PII (TC Kimlik, medical) | **Field-level** (AES-256-GCM) | TC Kimlik numbers, medical history, exam records, clinical notes, document notes, photo set notes encrypted with `PATIENT_PII_ENCRYPTION_KEY`. |
67
+ | Patient AI summaries | **Field-level** (AES-256-GCM) | `patient_ai_summary` encrypted with `PATIENT_SUMMARY_ENCRYPTION_KEY`. |
68
+ | User passwords | **One-way hash** (bcrypt 12 rounds) | Never decrypted. |
69
+ | Tenant API keys | **One-way hash** (bcrypt) | Prefix stored for identification, full key returned once on creation. |
70
+ | Patient phone numbers | **Disk-level** only | Must remain queryable for lookups. Protected by tenant isolation + disk encryption. |
71
+ | Voice recordings | **MinIO SSE** (server-side encryption) | Signed URLs with 1hr TTL control access. |
72
+ | Patient photos | **MinIO SSE** + signed URLs (1hr TTL) | Medical images. Never publicly accessible. |
73
+ | Call transcripts | **Disk-level** only | Must be searchable. Protected by tenant isolation. |
74
+ | CSV exports | **MinIO SSE** + signed URLs (1hr TTL) + auto-delete after 24h | Bulk PII. Time-limited access. |
75
+
76
+ **Design decision:** Chat message content, patient PII, and patient AI summaries are encrypted at the field level with dedicated keys. This means search and AI processing require decryption at the application layer. Phone numbers remain unencrypted for query lookups. Additional protection comes from: tenant-scoped queries (Prisma middleware), RBAC + clinic scoping, PostgreSQL disk encryption, network isolation, and audit logging.
77
+
78
+ ---
79
+
80
+ ## Tenant Data Isolation
81
+
82
+ ### Prisma Middleware
83
+
84
+ Every query passes through Prisma middleware that auto-injects tenant scoping:
85
+
86
+ ```typescript
87
+ prisma.$use(async (params, next) => {
88
+ // Auto-inject WHERE tenantId = currentTenant for all queries
89
+ // Throw if tenantId is missing on mutations
90
+ // superadmin/sales bypass with explicit allTenants: true flag
91
+ });
92
+ ```
93
+
94
+ ### Isolation Guarantees
95
+
96
+ | Layer | Mechanism |
97
+ |-------|-----------|
98
+ | **Database queries** | Prisma middleware auto-injects `WHERE tenantId`. No SQL query can return data from another tenant. |
99
+ | **Cross-tenant access** | Requires `superadmin` role + explicit `allTenants: true` flag. |
100
+ | **Clinic scoping** | Layered on top of tenant scoping. `admin/doctor/receptionist` only see assigned clinics. |
101
+ | **MinIO file storage** | Path prefixed with `{tenantId}/`. Signed URLs scoped to tenant path. |
102
+ | **Redis keys** | Prefixed with `tenant:{tenantId}:` where applicable. |
103
+ | **BullMQ jobs** | Jobs carry `tenantId`. Processors verify tenant ownership before acting. |
104
+
105
+ ---
106
+
107
+ ## API Security (11 Layers)
108
+
109
+ | # | Layer | Implementation |
110
+ |---|-------|---------------|
111
+ | 1 | **Authentication** | Opaque session tokens. Client never sees JWT. Server maps opaque token to JWT stored in Redis. |
112
+ | 2 | **Token revocation** | Delete Redis key = instant revocation. No blacklist needed. |
113
+ | 3 | **Rate limiting** | `@nestjs/throttler` + Redis -- per-route limits (5/min login, 200/min general API, 100/min webhooks). |
114
+ | 4 | **Input validation** | `class-validator` DTOs on every endpoint -- reject malformed requests before they reach business logic. |
115
+ | 5 | **SQL injection** | Prisma parameterized queries -- no raw SQL unless explicitly needed. |
116
+ | 6 | **CORS** | Strict origin whitelist -- only `FRONTEND_URL` allowed. |
117
+ | 7 | **Helmet** | `@fastify/helmet` -- security headers (CSP, HSTS, X-Frame-Options). |
118
+ | 8 | **Body size limits** | Fastify body limit: 10MB default, 50MB for file upload routes. |
119
+ | 9 | **Webhook HMAC** | Signature verification on all inbound webhooks (ElevenLabs, Meta). |
120
+ | 10 | **OAuth state** | HMAC-signed state parameter prevents CSRF on OAuth flows (Google Calendar, Meta). |
121
+ | 11 | **Request logging** | Every request logged with method, URL, status, duration, userId, tenantId, clinicId, requestId. |
122
+
123
+ ### Rate Limiting Details
124
+
125
+ | Scope | Limit | Window | Purpose |
126
+ |-------|-------|--------|---------|
127
+ | `/auth/login` | 5 requests | 1 min per IP | Brute force prevention |
128
+ | `/auth/forgot-password` | 3 requests | 15 min per email | Spam prevention |
129
+ | `/auth/register` | 3 requests | 1 hour per IP | Abuse prevention |
130
+ | `/webhooks/*` | 100 requests | 1 min per IP | Webhook flooding |
131
+ | Global API | 200 requests | 1 min per user | General abuse |
132
+
133
+ ---
134
+
135
+ ## Secrets Management
136
+
137
+ ### Encryption Keys
138
+
139
+ | Secret | Storage | Rotation Strategy |
140
+ |--------|---------|-------------------|
141
+ | `GOOGLE_TOKEN_ENCRYPTION_KEY` | Env var / Docker secret | Re-encryption migration for all stored refresh tokens |
142
+ | `META_TOKEN_ENCRYPTION_KEY` | Env var / Docker secret | Re-encrypt all stored Meta access tokens |
143
+ | `TEKTIPPAY_ENCRYPTION_KEY` | Env var / Docker secret | Re-encrypt stored TekTipPay credentials |
144
+ | `MESSAGE_ENCRYPTION_KEY` | Env var / Docker secret | Re-encrypt all `msg_text`, `msg_quoted_text`, operator request text |
145
+ | `PATIENT_PII_ENCRYPTION_KEY` | Env var / Docker secret | Re-encrypt all TC Kimlik, medical history, exam records, clinical notes, document notes, photo set notes |
146
+ | `PATIENT_SUMMARY_ENCRYPTION_KEY` | Env var / Docker secret | Re-encrypt all `patient_ai_summary` fields |
147
+
148
+ ### Other Secrets
149
+
150
+ | Secret | Storage | Rotation |
151
+ |--------|---------|----------|
152
+ | JWT secret (`JWT_SECRET`) | Env var | Rotate quarterly. JWTs are server-side only (stored in Redis), so rotation affects only new tokens. Old opaque sessions expire naturally. |
153
+ | Database password | Env var / Docker secret | Rotate periodically. Update `DATABASE_URL`. |
154
+ | Redis password | Env var / Docker secret | Rotate periodically. Update `REDIS_URL`. |
155
+ | MinIO credentials (`MINIO_ACCESS_KEY`, `MINIO_SECRET_KEY`) | Env var / Docker secret | Rotate periodically. Update MinIO config and app env simultaneously. |
156
+ | External API keys (ElevenLabs, NetGSM, etc.) | Env var | Per provider policy. |
157
+ | Tenant API keys | bcrypt hash in DB | Tenant can regenerate anytime via dashboard. |
158
+
159
+ All encryption keys: 32-byte hex strings generated with `openssl rand -hex 32`.
160
+
161
+ ---
162
+
163
+ ## Network Security
164
+
165
+ ### Docker Internal Network
166
+
167
+ ```
168
+ +--------------------------------------------------+
169
+ | asistan724-net (internal) |
170
+ | |
171
+ | NestJS <--TLS--> PostgreSQL (port 5432, internal)|
172
+ | NestJS <--TLS--> Redis (port 6379, internal) |
173
+ | NestJS <--TLS--> MinIO (port 9000, internal) |
174
+ | |
175
+ | Only NestJS + React exposed to host network |
176
+ +--------------------------------------------------+
177
+ ```
178
+
179
+ ### Exposure Rules
180
+
181
+ | Service | Host Port Binding | Access |
182
+ |---------|------------------|--------|
183
+ | NestJS | `PORT` (3005) | Behind reverse proxy with TLS termination |
184
+ | React | 3020 | Behind same reverse proxy |
185
+ | PostgreSQL | **None** | Internal network only |
186
+ | Redis | **None** | Internal network only |
187
+ | MinIO | **None** | Internal network only |
188
+
189
+ ### TLS Requirements
190
+
191
+ - PostgreSQL: TLS for all connections from NestJS.
192
+ - Redis: `requirepass` + TLS.
193
+ - MinIO: SSE-S3 (server-side encryption) + TLS for API calls.
194
+ - External APIs: All outbound HTTPS (ElevenLabs, Google, Meta, NetGSM, TekTipPay).
195
+
196
+ ---
197
+
198
+ ## Security per Migration Phase
199
+
200
+ | Phase | Security Tasks |
201
+ |-------|---------------|
202
+ | **Phase 1** (Config, DB, Redis, MinIO) | `EncryptionService` shared module. PostgreSQL TLS + strong password. Redis `requirepass` + TLS. MinIO SSE-S3 + access policy. Docker network isolation. `@fastify/helmet`. |
203
+ | **Phase 2** (Auth) | Opaque session tokens + Redis (no JWT exposed to client, delete key = revoke). bcrypt for passwords. `@nestjs/throttler` rate limiting with Redis storage. Hashed password reset tokens. CORS whitelist. |
204
+ | **Phase 3** (Tenants, Users, Clinics) | Prisma tenant-scoping middleware. RBAC guards. Clinic access guard. Audit logging on all mutations. |
205
+ | **Phase 4** (Agents) | Tenant-scoped queries. RBAC enforcement. |
206
+ | **Phase 5** (Integrations) | Google token encryption (exists, verify). Meta token encryption (new). ElevenLabs webhook HMAC verification. API key rotation support. |
207
+ | **Phase 6** (Client Tools) | Feature-flag gating on all tools. Tool execution logging. Tenant/clinic context validation in every tool call. |
208
+ | **Phase 7** (Calls, Leads, Billing) | Tenant-scoped and clinic-scoped queries. RBAC on all billing endpoints. `clinic_id` on `billing_events`, `stt_usages`, `tool_execution_logs`. |
209
+ | **Phase 8** (Outbound Campaigns) | Tenant-scoped. RBAC. Call dispatch respects time windows. |
210
+ | **Phase 9** (WhatsApp) | **Message content encryption (AES-256-GCM with `MESSAGE_ENCRYPTION_KEY`).** All media stored in MinIO (not DB). Signed URLs for all media access. WS auth (opaque token on connect). |
211
+ | **Phase 10** (Google Calendar) | Token encryption (verify). OAuth state HMAC signing. |
212
+ | **Phase 11** (Appointment Validation) | Tenant-scoped. RBAC. |
213
+ | **Phase 12** (Inbound Call Schedule) | Tenant-scoped. |
214
+ | **Phase 13** (Webhooks) | HMAC signature verification on all inbound webhooks. Signed outgoing webhooks with per-tenant secret. |
215
+ | **Phase 14** (Admin, Logs, KVKK) | Encrypted data exports (ZIP + password). Crypto-erasure on deletion for encrypted fields. Retention policy enforcement. **Patient PII encryption** (`PATIENT_PII_ENCRYPTION_KEY`). **Patient summary encryption** (`PATIENT_SUMMARY_ENCRYPTION_KEY`). |
216
+ | **Phase 15** (Meta Business API, TekTipPay) | **Meta token encryption.** Webhook signature verification (Meta). **TekTipPay credential encryption.** Payment link tokenization (TekTipPay is a stub -- deferred). |