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.
- package/.claude/settings.local.json +27 -0
- package/.dockerignore +6 -0
- package/.env.example +43 -0
- package/BEFORE-PRODUCTION.md +32 -0
- package/Dockerfile +23 -0
- package/SYSTEM_OVERVIEW.md +942 -0
- package/SYSTEM_STATUS.md +332 -0
- package/backup_script/main.py +146 -0
- package/baileys/.dockerignore +7 -0
- package/baileys/Dockerfile +13 -0
- package/baileys/README.md +412 -0
- package/baileys/index.js +499 -0
- package/baileys/package-lock.json +2532 -0
- package/baileys/package.json +25 -0
- package/baileys/server.js +96 -0
- package/baileys/src/config.js +55 -0
- package/baileys/src/middleware/api-key.js +16 -0
- package/baileys/src/routes/accounts.js +51 -0
- package/baileys/src/routes/chats.js +103 -0
- package/baileys/src/routes/webhooks.js +34 -0
- package/baileys/src/services/account-store.js +259 -0
- package/baileys/src/services/webhook-dispatcher.js +161 -0
- package/baileys/src/services/worker-manager.js +597 -0
- package/baileys/src/utils/jid.js +79 -0
- package/baileys/src/utils/logger.js +16 -0
- package/baileys/src/utils/use-mongodb-auth-state.js +122 -0
- package/baileys/worker.js +721 -0
- package/dist/app.d.ts +1 -0
- package/dist/app.js +84 -0
- package/dist/app.js.map +1 -0
- package/dist/config/agentPrompts.json +19 -0
- package/dist/config/database.d.ts +1 -0
- package/dist/config/database.js +26 -0
- package/dist/config/database.js.map +1 -0
- package/dist/config/env.d.ts +41 -0
- package/dist/config/env.js +81 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +73 -0
- package/dist/config/index.js.map +1 -0
- package/dist/controllers/webhook.controller.d.ts +10 -0
- package/dist/controllers/webhook.controller.js +128 -0
- package/dist/controllers/webhook.controller.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.js +13 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/hooks/webhookValidator.d.ts +2 -0
- package/dist/hooks/webhookValidator.js +47 -0
- package/dist/hooks/webhookValidator.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/001_session-architecture.d.ts +3 -0
- package/dist/migrations/001_session-architecture.js +119 -0
- package/dist/migrations/001_session-architecture.js.map +1 -0
- package/dist/migrations/002_agent-ref.d.ts +3 -0
- package/dist/migrations/002_agent-ref.js +55 -0
- package/dist/migrations/002_agent-ref.js.map +1 -0
- package/dist/migrations/003_shift-schedule.d.ts +3 -0
- package/dist/migrations/003_shift-schedule.js +48 -0
- package/dist/migrations/003_shift-schedule.js.map +1 -0
- package/dist/migrations/004_invert-shift-to-clinic-hours.d.ts +3 -0
- package/dist/migrations/004_invert-shift-to-clinic-hours.js +27 -0
- package/dist/migrations/004_invert-shift-to-clinic-hours.js.map +1 -0
- package/dist/migrations/005_composite-baileys-chat-ids.d.ts +3 -0
- package/dist/migrations/005_composite-baileys-chat-ids.js +47 -0
- package/dist/migrations/005_composite-baileys-chat-ids.js.map +1 -0
- package/dist/migrations/migration.model.d.ts +18 -0
- package/dist/migrations/migration.model.js +45 -0
- package/dist/migrations/migration.model.js.map +1 -0
- package/dist/migrations/migration.routes.d.ts +2 -0
- package/dist/migrations/migration.routes.js +37 -0
- package/dist/migrations/migration.routes.js.map +1 -0
- package/dist/migrations/migration.runner.d.ts +19 -0
- package/dist/migrations/migration.runner.js +74 -0
- package/dist/migrations/migration.runner.js.map +1 -0
- package/dist/models/ConversationClaim.d.ts +13 -0
- package/dist/models/ConversationClaim.js +44 -0
- package/dist/models/ConversationClaim.js.map +1 -0
- package/dist/models/ConversationEvaluation.d.ts +23 -0
- package/dist/models/ConversationEvaluation.js +92 -0
- package/dist/models/ConversationEvaluation.js.map +1 -0
- package/dist/models/Summary.d.ts +37 -0
- package/dist/models/Summary.js +78 -0
- package/dist/models/Summary.js.map +1 -0
- package/dist/models/Transcription.d.ts +34 -0
- package/dist/models/Transcription.js +71 -0
- package/dist/models/Transcription.js.map +1 -0
- package/dist/models/WhatsAppRecipient.d.ts +23 -0
- package/dist/models/WhatsAppRecipient.js +53 -0
- package/dist/models/WhatsAppRecipient.js.map +1 -0
- package/dist/modules/admin/admin.routes.d.ts +2 -0
- package/dist/modules/admin/admin.routes.js +1966 -0
- package/dist/modules/admin/admin.routes.js.map +1 -0
- package/dist/modules/admin/elevenlabs-test-chat.routes.d.ts +2 -0
- package/dist/modules/admin/elevenlabs-test-chat.routes.js +158 -0
- package/dist/modules/admin/elevenlabs-test-chat.routes.js.map +1 -0
- package/dist/modules/admin/whatsapp-test-chat.routes.d.ts +2 -0
- package/dist/modules/admin/whatsapp-test-chat.routes.js +204 -0
- package/dist/modules/admin/whatsapp-test-chat.routes.js.map +1 -0
- package/dist/modules/agents/agent.model.d.ts +38 -0
- package/dist/modules/agents/agent.model.js +92 -0
- package/dist/modules/agents/agent.model.js.map +1 -0
- package/dist/modules/agents/agent.routes.d.ts +2 -0
- package/dist/modules/agents/agent.routes.js +61 -0
- package/dist/modules/agents/agent.routes.js.map +1 -0
- package/dist/modules/appointment-validation/appointment-validation.model.d.ts +76 -0
- package/dist/modules/appointment-validation/appointment-validation.model.js +118 -0
- package/dist/modules/appointment-validation/appointment-validation.model.js.map +1 -0
- package/dist/modules/appointment-validation/appointment-validation.routes.d.ts +2 -0
- package/dist/modules/appointment-validation/appointment-validation.routes.js +202 -0
- package/dist/modules/appointment-validation/appointment-validation.routes.js.map +1 -0
- package/dist/modules/appointment-validation/appointment-validation.service.d.ts +53 -0
- package/dist/modules/appointment-validation/appointment-validation.service.js +827 -0
- package/dist/modules/appointment-validation/appointment-validation.service.js.map +1 -0
- package/dist/modules/auth/auth.model.d.ts +17 -0
- package/dist/modules/auth/auth.model.js +64 -0
- package/dist/modules/auth/auth.model.js.map +1 -0
- package/dist/modules/auth/auth.routes.d.ts +2 -0
- package/dist/modules/auth/auth.routes.js +202 -0
- package/dist/modules/auth/auth.routes.js.map +1 -0
- package/dist/modules/auth/auth.service.d.ts +28 -0
- package/dist/modules/auth/auth.service.js +183 -0
- package/dist/modules/auth/auth.service.js.map +1 -0
- package/dist/modules/auth/refresh-token.model.d.ts +13 -0
- package/dist/modules/auth/refresh-token.model.js +52 -0
- package/dist/modules/auth/refresh-token.model.js.map +1 -0
- package/dist/modules/billing/billing-alert.model.d.ts +16 -0
- package/dist/modules/billing/billing-alert.model.js +47 -0
- package/dist/modules/billing/billing-alert.model.js.map +1 -0
- package/dist/modules/billing/billing-period-snapshot.model.d.ts +35 -0
- package/dist/modules/billing/billing-period-snapshot.model.js +68 -0
- package/dist/modules/billing/billing-period-snapshot.model.js.map +1 -0
- package/dist/modules/billing/billing.model.d.ts +18 -0
- package/dist/modules/billing/billing.model.js +62 -0
- package/dist/modules/billing/billing.model.js.map +1 -0
- package/dist/modules/billing/billing.routes.d.ts +2 -0
- package/dist/modules/billing/billing.routes.js +63 -0
- package/dist/modules/billing/billing.routes.js.map +1 -0
- package/dist/modules/billing/billing.service.d.ts +69 -0
- package/dist/modules/billing/billing.service.js +498 -0
- package/dist/modules/billing/billing.service.js.map +1 -0
- package/dist/modules/billing/payment.model.d.ts +24 -0
- package/dist/modules/billing/payment.model.js +57 -0
- package/dist/modules/billing/payment.model.js.map +1 -0
- package/dist/modules/calls/call.model.d.ts +41 -0
- package/dist/modules/calls/call.model.js +97 -0
- package/dist/modules/calls/call.model.js.map +1 -0
- package/dist/modules/calls/call.routes.d.ts +2 -0
- package/dist/modules/calls/call.routes.js +103 -0
- package/dist/modules/calls/call.routes.js.map +1 -0
- package/dist/modules/campaigns/campaign.model.d.ts +45 -0
- package/dist/modules/campaigns/campaign.model.js +98 -0
- package/dist/modules/campaigns/campaign.model.js.map +1 -0
- package/dist/modules/campaigns/campaign.routes.d.ts +2 -0
- package/dist/modules/campaigns/campaign.routes.js +323 -0
- package/dist/modules/campaigns/campaign.routes.js.map +1 -0
- package/dist/modules/campaigns/campaign.service.d.ts +11 -0
- package/dist/modules/campaigns/campaign.service.js +86 -0
- package/dist/modules/campaigns/campaign.service.js.map +1 -0
- package/dist/modules/google-calendar/google-calendar.routes.d.ts +2 -0
- package/dist/modules/google-calendar/google-calendar.routes.js +32 -0
- package/dist/modules/google-calendar/google-calendar.routes.js.map +1 -0
- package/dist/modules/inbound-call/inbound-call-config.model.d.ts +20 -0
- package/dist/modules/inbound-call/inbound-call-config.model.js +68 -0
- package/dist/modules/inbound-call/inbound-call-config.model.js.map +1 -0
- package/dist/modules/inbound-call/inbound-call.routes.d.ts +2 -0
- package/dist/modules/inbound-call/inbound-call.routes.js +243 -0
- package/dist/modules/inbound-call/inbound-call.routes.js.map +1 -0
- package/dist/modules/leads/lead.model.d.ts +24 -0
- package/dist/modules/leads/lead.model.js +54 -0
- package/dist/modules/leads/lead.model.js.map +1 -0
- package/dist/modules/leads/lead.routes.d.ts +2 -0
- package/dist/modules/leads/lead.routes.js +201 -0
- package/dist/modules/leads/lead.routes.js.map +1 -0
- package/dist/modules/plans/plan.model.d.ts +25 -0
- package/dist/modules/plans/plan.model.js +59 -0
- package/dist/modules/plans/plan.model.js.map +1 -0
- package/dist/modules/surveys/survey.model.d.ts +30 -0
- package/dist/modules/surveys/survey.model.js +75 -0
- package/dist/modules/surveys/survey.model.js.map +1 -0
- package/dist/modules/surveys/survey.routes.d.ts +2 -0
- package/dist/modules/surveys/survey.routes.js +153 -0
- package/dist/modules/surveys/survey.routes.js.map +1 -0
- package/dist/modules/tenants/tenant.model.d.ts +86 -0
- package/dist/modules/tenants/tenant.model.js +127 -0
- package/dist/modules/tenants/tenant.model.js.map +1 -0
- package/dist/modules/tenants/tenant.routes.d.ts +2 -0
- package/dist/modules/tenants/tenant.routes.js +65 -0
- package/dist/modules/tenants/tenant.routes.js.map +1 -0
- package/dist/modules/users/user.routes.d.ts +2 -0
- package/dist/modules/users/user.routes.js +106 -0
- package/dist/modules/users/user.routes.js.map +1 -0
- package/dist/modules/webhooks/elevenlabs-tool.routes.d.ts +20 -0
- package/dist/modules/webhooks/elevenlabs-tool.routes.js +85 -0
- package/dist/modules/webhooks/elevenlabs-tool.routes.js.map +1 -0
- package/dist/modules/webhooks/elevenlabs-tool.service.d.ts +11 -0
- package/dist/modules/webhooks/elevenlabs-tool.service.js +360 -0
- package/dist/modules/webhooks/elevenlabs-tool.service.js.map +1 -0
- package/dist/modules/webhooks/elevenlabs.routes.d.ts +2 -0
- package/dist/modules/webhooks/elevenlabs.routes.js +34 -0
- package/dist/modules/webhooks/elevenlabs.routes.js.map +1 -0
- package/dist/modules/webhooks/elevenlabs.service.d.ts +6 -0
- package/dist/modules/webhooks/elevenlabs.service.js +512 -0
- package/dist/modules/webhooks/elevenlabs.service.js.map +1 -0
- package/dist/modules/webhooks/unipile.routes.d.ts +2 -0
- package/dist/modules/webhooks/unipile.routes.js +780 -0
- package/dist/modules/webhooks/unipile.routes.js.map +1 -0
- package/dist/modules/whatsapp/appointment.model.d.ts +27 -0
- package/dist/modules/whatsapp/appointment.model.js +58 -0
- package/dist/modules/whatsapp/appointment.model.js.map +1 -0
- package/dist/modules/whatsapp/operator-request.model.d.ts +29 -0
- package/dist/modules/whatsapp/operator-request.model.js +65 -0
- package/dist/modules/whatsapp/operator-request.model.js.map +1 -0
- package/dist/modules/whatsapp/stt-usage.model.d.ts +16 -0
- package/dist/modules/whatsapp/stt-usage.model.js +53 -0
- package/dist/modules/whatsapp/stt-usage.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp-chat.model.d.ts +23 -0
- package/dist/modules/whatsapp/whatsapp-chat.model.js +55 -0
- package/dist/modules/whatsapp/whatsapp-chat.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp-contact-profile.model.d.ts +23 -0
- package/dist/modules/whatsapp/whatsapp-contact-profile.model.js +54 -0
- package/dist/modules/whatsapp/whatsapp-contact-profile.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp-message.model.d.ts +30 -0
- package/dist/modules/whatsapp/whatsapp-message.model.js +52 -0
- package/dist/modules/whatsapp/whatsapp-message.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp-session.model.d.ts +33 -0
- package/dist/modules/whatsapp/whatsapp-session.model.js +65 -0
- package/dist/modules/whatsapp/whatsapp-session.model.js.map +1 -0
- package/dist/modules/whatsapp/whatsapp.routes.d.ts +2 -0
- package/dist/modules/whatsapp/whatsapp.routes.js +1237 -0
- package/dist/modules/whatsapp/whatsapp.routes.js.map +1 -0
- package/dist/plugins/cors.d.ts +3 -0
- package/dist/plugins/cors.js +11 -0
- package/dist/plugins/cors.js.map +1 -0
- package/dist/plugins/jwt.d.ts +3 -0
- package/dist/plugins/jwt.js +22 -0
- package/dist/plugins/jwt.js.map +1 -0
- package/dist/plugins/rawBody.d.ts +3 -0
- package/dist/plugins/rawBody.js +16 -0
- package/dist/plugins/rawBody.js.map +1 -0
- package/dist/plugins/rbac.d.ts +5 -0
- package/dist/plugins/rbac.js +29 -0
- package/dist/plugins/rbac.js.map +1 -0
- package/dist/routes/admin.routes.d.ts +2 -0
- package/dist/routes/admin.routes.js +169 -0
- package/dist/routes/admin.routes.js.map +1 -0
- package/dist/routes/health.routes.d.ts +2 -0
- package/dist/routes/health.routes.js +16 -0
- package/dist/routes/health.routes.js.map +1 -0
- package/dist/routes/webhook.routes.d.ts +2 -0
- package/dist/routes/webhook.routes.js +17 -0
- package/dist/routes/webhook.routes.js.map +1 -0
- package/dist/services/ai/base.ai.d.ts +19 -0
- package/dist/services/ai/base.ai.js +120 -0
- package/dist/services/ai/base.ai.js.map +1 -0
- package/dist/services/ai/gemini.service.d.ts +11 -0
- package/dist/services/ai/gemini.service.js +43 -0
- package/dist/services/ai/gemini.service.js.map +1 -0
- package/dist/services/ai/index.d.ts +2 -0
- package/dist/services/ai/index.js +26 -0
- package/dist/services/ai/index.js.map +1 -0
- package/dist/services/ai/openai.service.d.ts +11 -0
- package/dist/services/ai/openai.service.js +50 -0
- package/dist/services/ai/openai.service.js.map +1 -0
- package/dist/services/elevenlabs.service.d.ts +52 -0
- package/dist/services/elevenlabs.service.js +447 -0
- package/dist/services/elevenlabs.service.js.map +1 -0
- package/dist/services/google-calendar.service.d.ts +60 -0
- package/dist/services/google-calendar.service.js +494 -0
- package/dist/services/google-calendar.service.js.map +1 -0
- package/dist/services/inbound-call-schedule.service.d.ts +11 -0
- package/dist/services/inbound-call-schedule.service.js +162 -0
- package/dist/services/inbound-call-schedule.service.js.map +1 -0
- package/dist/services/netgsm.service.d.ts +41 -0
- package/dist/services/netgsm.service.js +89 -0
- package/dist/services/netgsm.service.js.map +1 -0
- package/dist/services/unipile.service.d.ts +41 -0
- package/dist/services/unipile.service.js +149 -0
- package/dist/services/unipile.service.js.map +1 -0
- package/dist/services/whatsapp-agent.service.d.ts +139 -0
- package/dist/services/whatsapp-agent.service.js +2055 -0
- package/dist/services/whatsapp-agent.service.js.map +1 -0
- package/dist/services/whatsapp.service.d.ts +26 -0
- package/dist/services/whatsapp.service.js +206 -0
- package/dist/services/whatsapp.service.js.map +1 -0
- package/dist/templates/index.d.ts +39 -0
- package/dist/templates/index.js +35 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/receptionist.d.ts +2 -0
- package/dist/templates/receptionist.js +39 -0
- package/dist/templates/receptionist.js.map +1 -0
- package/dist/templates/survey.d.ts +2 -0
- package/dist/templates/survey.js +41 -0
- package/dist/templates/survey.js.map +1 -0
- package/dist/types/index.d.ts +173 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.js +105 -0
- package/dist/utils/logger.js.map +1 -0
- package/docker-compose.nestjs.yml +89 -0
- package/docker-compose.yml +78 -0
- package/docs/AI_AGENT_ENHANCEMENT_PLAN.md +164 -0
- package/docs/API.md +1193 -0
- package/docs/API_ENDPOINTS.md +344 -0
- package/docs/ARCHITECTURE.md +305 -0
- package/docs/AUTH_API.md +252 -0
- package/docs/BILLING_SMS_ALERTS.md +94 -0
- package/docs/CHAT_ASSIGNMENT_SYSTEM.md +118 -0
- package/docs/CLIENT_TOOLS_AND_FEATURES.md +337 -0
- package/docs/ELEVENLABS_WEBHOOK_TOOLS.md +644 -0
- package/docs/FRONTEND_CHECKLIST.md +227 -0
- package/docs/IMPLEMENTATION_STATUS.md +470 -0
- package/docs/MIGRATION_GUIDE.md +96 -0
- package/docs/MISSINGS_REPORT.md +507 -0
- package/docs/NESTJS_MIGRATION_REFERENCE.md +5136 -0
- package/docs/PROJECT_DESCRIPTION.md +1038 -0
- package/docs/SCALING.md +148 -0
- package/docs/SESSION_SUMMARY_2026_03_17.md +135 -0
- package/docs/WHATSAPP_AGENT.md +1086 -0
- package/docs/architecture/00-SYSTEM-OVERVIEW.md +318 -0
- package/docs/architecture/01-DATABASE-SCHEMA.md +2564 -0
- package/docs/architecture/02-AUTHENTICATION.md +1040 -0
- package/docs/architecture/03-MULTI-CLINIC.md +742 -0
- package/docs/architecture/04-WHATSAPP-AGENT.md +608 -0
- package/docs/architecture/05-OPERATOR-WORKFLOW.md +444 -0
- package/docs/architecture/06-BAILEYS-MICROSERVICE.md +616 -0
- package/docs/architecture/07-APPOINTMENTS.md +849 -0
- package/docs/architecture/08-VOICE-CALLS.md +470 -0
- package/docs/architecture/09-OUTBOUND-CAMPAIGNS.md +542 -0
- package/docs/architecture/10-CLIENT-TOOLS.md +665 -0
- package/docs/architecture/11-BILLING.md +458 -0
- package/docs/architecture/12-SECURITY.md +216 -0
- package/docs/architecture/13-LOGGING-AUDIT.md +549 -0
- package/docs/architecture/14-META-BUSINESS-API.md +454 -0
- package/docs/architecture/15-AI-MODULE.md +479 -0
- package/docs/architecture/16-BACKGROUND-JOBS.md +469 -0
- package/docs/architecture/17-REALTIME-LIVECHAT.md +447 -0
- package/docs/architecture/18-FILE-STORAGE.md +410 -0
- package/docs/architecture/19-PATIENTS.md +1034 -0
- package/docs/architecture/20-TREATMENTS-AND-PLANS.md +774 -0
- package/docs/architecture/21-BEFORE-AFTER-PHOTOS.md +519 -0
- package/docs/database.md +456 -0
- package/docs/ornek-randevu-onay.csv +3 -0
- package/ecosystem.config.js +16 -0
- package/elevenlabs-convai-api-reference.md +1171 -0
- package/frontend/.dockerignore +2 -0
- package/frontend/Dockerfile +24 -0
- package/frontend/README.md +75 -0
- package/frontend/components.json +25 -0
- package/frontend/eslint.config.js +23 -0
- package/frontend/index.html +13 -0
- package/frontend/nginx.conf +37 -0
- package/frontend/package-lock.json +8709 -0
- package/frontend/package.json +71 -0
- package/frontend/public/favicon.svg +1 -0
- package/frontend/public/icons.svg +24 -0
- package/frontend/src/App.tsx +125 -0
- package/frontend/src/components/error-boundary.tsx +50 -0
- package/frontend/src/components/shared/activity-timeline.tsx +66 -0
- package/frontend/src/components/shared/appointment-calendar.css +80 -0
- package/frontend/src/components/shared/appointment-calendar.tsx +245 -0
- package/frontend/src/components/shared/chat-bubble.tsx +72 -0
- package/frontend/src/components/shared/combobox.tsx +119 -0
- package/frontend/src/components/shared/confirm-dialog.tsx +57 -0
- package/frontend/src/components/shared/data-table-pagination.tsx +97 -0
- package/frontend/src/components/shared/data-table-toolbar.tsx +39 -0
- package/frontend/src/components/shared/empty-state.tsx +27 -0
- package/frontend/src/components/shared/file-upload.tsx +140 -0
- package/frontend/src/components/shared/index.ts +20 -0
- package/frontend/src/components/shared/language-switcher.tsx +29 -0
- package/frontend/src/components/shared/notification-dropdown.tsx +115 -0
- package/frontend/src/components/shared/page-header.tsx +23 -0
- package/frontend/src/components/shared/stat-card.tsx +37 -0
- package/frontend/src/components/shared/status-badge.tsx +70 -0
- package/frontend/src/components/shared/status-dot.tsx +43 -0
- package/frontend/src/components/ui/alert-dialog.tsx +187 -0
- package/frontend/src/components/ui/alert.tsx +76 -0
- package/frontend/src/components/ui/avatar.tsx +109 -0
- package/frontend/src/components/ui/badge.tsx +52 -0
- package/frontend/src/components/ui/breadcrumb.tsx +125 -0
- package/frontend/src/components/ui/button.tsx +60 -0
- package/frontend/src/components/ui/calendar.tsx +219 -0
- package/frontend/src/components/ui/card.tsx +103 -0
- package/frontend/src/components/ui/chart.tsx +371 -0
- package/frontend/src/components/ui/checkbox.tsx +29 -0
- package/frontend/src/components/ui/collapsible.tsx +19 -0
- package/frontend/src/components/ui/command.tsx +194 -0
- package/frontend/src/components/ui/dialog.tsx +158 -0
- package/frontend/src/components/ui/dropdown-menu.tsx +268 -0
- package/frontend/src/components/ui/input-group.tsx +156 -0
- package/frontend/src/components/ui/input.tsx +20 -0
- package/frontend/src/components/ui/label.tsx +20 -0
- package/frontend/src/components/ui/pagination.tsx +130 -0
- package/frontend/src/components/ui/popover.tsx +90 -0
- package/frontend/src/components/ui/progress.tsx +83 -0
- package/frontend/src/components/ui/radio-group.tsx +36 -0
- package/frontend/src/components/ui/scroll-area.tsx +54 -0
- package/frontend/src/components/ui/select.tsx +199 -0
- package/frontend/src/components/ui/separator.tsx +23 -0
- package/frontend/src/components/ui/sheet.tsx +138 -0
- package/frontend/src/components/ui/sidebar.tsx +723 -0
- package/frontend/src/components/ui/skeleton.tsx +13 -0
- package/frontend/src/components/ui/sonner.tsx +47 -0
- package/frontend/src/components/ui/switch.tsx +30 -0
- package/frontend/src/components/ui/table.tsx +114 -0
- package/frontend/src/components/ui/tabs.tsx +82 -0
- package/frontend/src/components/ui/textarea.tsx +18 -0
- package/frontend/src/components/ui/toggle-group.tsx +89 -0
- package/frontend/src/components/ui/toggle.tsx +43 -0
- package/frontend/src/components/ui/tooltip.tsx +64 -0
- package/frontend/src/hooks/use-mobile.ts +19 -0
- package/frontend/src/i18n/index.ts +20 -0
- package/frontend/src/i18n/locales/en.json +786 -0
- package/frontend/src/i18n/locales/tr.json +786 -0
- package/frontend/src/index.css +134 -0
- package/frontend/src/layouts/admin-layout.tsx +111 -0
- package/frontend/src/layouts/app-header.tsx +130 -0
- package/frontend/src/layouts/app-layout.tsx +19 -0
- package/frontend/src/layouts/app-sidebar.tsx +212 -0
- package/frontend/src/layouts/auth-guard.tsx +31 -0
- package/frontend/src/layouts/mobile-sidebar.tsx +120 -0
- package/frontend/src/lib/api.ts +68 -0
- package/frontend/src/lib/hooks/use-appointments.ts +224 -0
- package/frontend/src/lib/hooks/use-availability-blocks.ts +83 -0
- package/frontend/src/lib/hooks/use-chats.ts +236 -0
- package/frontend/src/lib/hooks/use-clinic-detail.ts +171 -0
- package/frontend/src/lib/hooks/use-clinics.ts +37 -0
- package/frontend/src/lib/hooks/use-doctor-calendar.ts +80 -0
- package/frontend/src/lib/hooks/use-examinations.ts +89 -0
- package/frontend/src/lib/hooks/use-medical-history.ts +52 -0
- package/frontend/src/lib/hooks/use-patients.ts +296 -0
- package/frontend/src/lib/hooks/use-photo-sets.ts +118 -0
- package/frontend/src/lib/hooks/use-treatment-plans.ts +152 -0
- package/frontend/src/lib/hooks/use-treatments.ts +125 -0
- package/frontend/src/lib/hooks/use-users.ts +172 -0
- package/frontend/src/lib/utils.ts +6 -0
- package/frontend/src/main.tsx +17 -0
- package/frontend/src/pages/admin/agents/detail.tsx +774 -0
- package/frontend/src/pages/admin/agents/import.tsx +280 -0
- package/frontend/src/pages/admin/agents/index.tsx +245 -0
- package/frontend/src/pages/admin/ai-playground.tsx +543 -0
- package/frontend/src/pages/appointments/create-appointment-dialog.tsx +390 -0
- package/frontend/src/pages/appointments/index.tsx +860 -0
- package/frontend/src/pages/audit/index.tsx +24 -0
- package/frontend/src/pages/auth/login.tsx +194 -0
- package/frontend/src/pages/billing/index.tsx +24 -0
- package/frontend/src/pages/calendar/index.tsx +704 -0
- package/frontend/src/pages/calendar-connections/index.tsx +295 -0
- package/frontend/src/pages/calls/index.tsx +24 -0
- package/frontend/src/pages/campaigns/index.tsx +24 -0
- package/frontend/src/pages/chats/index.tsx +981 -0
- package/frontend/src/pages/clinics/index.tsx +224 -0
- package/frontend/src/pages/clinics/settings.tsx +412 -0
- package/frontend/src/pages/components-showcase.tsx +773 -0
- package/frontend/src/pages/connections/index.tsx +328 -0
- package/frontend/src/pages/dashboard.tsx +50 -0
- package/frontend/src/pages/leads/index.tsx +24 -0
- package/frontend/src/pages/my-schedule/index.tsx +496 -0
- package/frontend/src/pages/patients/create-patient-dialog.tsx +358 -0
- package/frontend/src/pages/patients/detail.tsx +1195 -0
- package/frontend/src/pages/patients/edit-patient-dialog.tsx +387 -0
- package/frontend/src/pages/patients/examinations-tab.tsx +460 -0
- package/frontend/src/pages/patients/index.tsx +381 -0
- package/frontend/src/pages/patients/medical-history-dialog.tsx +207 -0
- package/frontend/src/pages/patients/photo-sets-tab.tsx +616 -0
- package/frontend/src/pages/patients/timeline-tab.tsx +164 -0
- package/frontend/src/pages/patients/treatment-plans-tab.tsx +598 -0
- package/frontend/src/pages/phone-numbers/detail.tsx +427 -0
- package/frontend/src/pages/phone-numbers/index.tsx +455 -0
- package/frontend/src/pages/platform/index.tsx +454 -0
- package/frontend/src/pages/settings/index.tsx +126 -0
- package/frontend/src/pages/treatments/index.tsx +487 -0
- package/frontend/src/pages/users/doctor-profile.tsx +672 -0
- package/frontend/src/pages/users/edit.tsx +329 -0
- package/frontend/src/pages/users/index.tsx +407 -0
- package/frontend/src/pages/validation/index.tsx +24 -0
- package/frontend/src/stores/auth.store.ts +108 -0
- package/frontend/src/stores/ui.store.ts +41 -0
- package/frontend/tsconfig.app.json +32 -0
- package/frontend/tsconfig.json +13 -0
- package/frontend/tsconfig.node.json +26 -0
- package/frontend/vite.config.ts +29 -0
- package/nestjs/.dockerignore +5 -0
- package/nestjs/.env.docker +64 -0
- package/nestjs/.prettierrc +4 -0
- package/nestjs/Dockerfile +36 -0
- package/nestjs/README.md +98 -0
- package/nestjs/eslint.config.mjs +35 -0
- package/nestjs/nest-cli.json +8 -0
- package/nestjs/package-lock.json +13390 -0
- package/nestjs/package.json +114 -0
- package/nestjs/prisma/migrations/20260409161536_add_message_metadata_fields/migration.sql +1746 -0
- package/nestjs/prisma/migrations/20260410140436_add_agent_ai_fields/migration.sql +36 -0
- package/nestjs/prisma/migrations/20260410175519_add_agent_clinic_assignments/migration.sql +21 -0
- package/nestjs/prisma/migrations/20260412094344_make_agent_tenant_optional/migration.sql +2 -0
- package/nestjs/prisma/migrations/20260412110008_add_admin_chat_sessions/migration.sql +47 -0
- package/nestjs/prisma/migrations/migration_lock.toml +3 -0
- package/nestjs/prisma/schema.prisma +1843 -0
- package/nestjs/prisma/seed.ts +375 -0
- package/nestjs/prisma.config.ts +14 -0
- package/nestjs/src/admin/admin.controller.ts +27 -0
- package/nestjs/src/admin/admin.module.ts +16 -0
- package/nestjs/src/admin/admin.service.ts +91 -0
- package/nestjs/src/admin/ai-chat-session.service.ts +454 -0
- package/nestjs/src/admin/ai-test.controller.ts +191 -0
- package/nestjs/src/admin/superadmin.controller.ts +106 -0
- package/nestjs/src/agents/agents.controller.ts +262 -0
- package/nestjs/src/agents/agents.module.ts +13 -0
- package/nestjs/src/agents/agents.service.ts +733 -0
- package/nestjs/src/agents/dto/create-agent.dto.ts +99 -0
- package/nestjs/src/agents/dto/index.ts +2 -0
- package/nestjs/src/agents/dto/update-agent.dto.ts +148 -0
- package/nestjs/src/app.module.ts +115 -0
- package/nestjs/src/appointment-validation/appointment-validation.controller.ts +194 -0
- package/nestjs/src/appointment-validation/appointment-validation.module.ts +16 -0
- package/nestjs/src/appointment-validation/appointment-validation.service.ts +450 -0
- package/nestjs/src/appointment-validation/dto/create-batch.dto.ts +105 -0
- package/nestjs/src/appointment-validation/dto/index.ts +1 -0
- package/nestjs/src/appointment-validation/processors/validation-dispatch.processor.ts +26 -0
- package/nestjs/src/appointment-validation/processors/validation-sync.processor.ts +23 -0
- package/nestjs/src/appointments/appointments.controller.ts +268 -0
- package/nestjs/src/appointments/appointments.module.ts +13 -0
- package/nestjs/src/appointments/appointments.service.ts +773 -0
- package/nestjs/src/appointments/dto/create-appointment.dto.ts +72 -0
- package/nestjs/src/appointments/dto/index.ts +4 -0
- package/nestjs/src/appointments/dto/query-appointments.dto.ts +60 -0
- package/nestjs/src/appointments/dto/update-appointment.dto.ts +43 -0
- package/nestjs/src/appointments/dto/update-status.dto.ts +18 -0
- package/nestjs/src/appointments/processors/reminder.processor.ts +243 -0
- package/nestjs/src/audit/audit.controller.ts +84 -0
- package/nestjs/src/audit/audit.decorator.ts +20 -0
- package/nestjs/src/audit/audit.interceptor.ts +67 -0
- package/nestjs/src/audit/audit.interfaces.ts +15 -0
- package/nestjs/src/audit/audit.module.ts +12 -0
- package/nestjs/src/audit/audit.service.ts +177 -0
- package/nestjs/src/auth/auth.controller.ts +116 -0
- package/nestjs/src/auth/auth.module.ts +25 -0
- package/nestjs/src/auth/auth.service.ts +612 -0
- package/nestjs/src/auth/dto/change-password.dto.ts +13 -0
- package/nestjs/src/auth/dto/forgot-password.dto.ts +8 -0
- package/nestjs/src/auth/dto/index.ts +6 -0
- package/nestjs/src/auth/dto/login.dto.ts +13 -0
- package/nestjs/src/auth/dto/refresh.dto.ts +8 -0
- package/nestjs/src/auth/dto/register.dto.ts +28 -0
- package/nestjs/src/auth/dto/reset-password.dto.ts +13 -0
- package/nestjs/src/auth/permissions.config.ts +85 -0
- package/nestjs/src/availability-blocks/availability-blocks.controller.ts +83 -0
- package/nestjs/src/availability-blocks/availability-blocks.module.ts +10 -0
- package/nestjs/src/availability-blocks/availability-blocks.service.ts +202 -0
- package/nestjs/src/billing/billing.controller.ts +104 -0
- package/nestjs/src/billing/billing.module.ts +12 -0
- package/nestjs/src/billing/billing.service.ts +398 -0
- package/nestjs/src/billing/dto/index.ts +2 -0
- package/nestjs/src/billing/dto/query-billing.dto.ts +29 -0
- package/nestjs/src/billing/dto/record-payment.dto.ts +60 -0
- package/nestjs/src/billing/processors/alerts.processor.ts +216 -0
- package/nestjs/src/billing/processors/snapshot.processor.ts +181 -0
- package/nestjs/src/calls/calls.controller.ts +92 -0
- package/nestjs/src/calls/calls.module.ts +10 -0
- package/nestjs/src/calls/calls.service.ts +359 -0
- package/nestjs/src/calls/dto/index.ts +1 -0
- package/nestjs/src/calls/dto/query-calls.dto.ts +46 -0
- package/nestjs/src/clinics/clinics.controller.ts +226 -0
- package/nestjs/src/clinics/clinics.module.ts +11 -0
- package/nestjs/src/clinics/clinics.service.ts +203 -0
- package/nestjs/src/clinics/dto/create-clinic.dto.ts +40 -0
- package/nestjs/src/clinics/dto/create-meta-connection.dto.ts +44 -0
- package/nestjs/src/clinics/dto/index.ts +4 -0
- package/nestjs/src/clinics/dto/update-clinic.dto.ts +133 -0
- package/nestjs/src/clinics/dto/update-meta-connection.dto.ts +22 -0
- package/nestjs/src/clinics/meta-connections.service.ts +210 -0
- package/nestjs/src/common/decorators/accessible-clinics.decorator.ts +9 -0
- package/nestjs/src/common/decorators/current-user.decorator.ts +10 -0
- package/nestjs/src/common/decorators/features.decorator.ts +7 -0
- package/nestjs/src/common/decorators/index.ts +4 -0
- package/nestjs/src/common/decorators/permissions.decorator.ts +13 -0
- package/nestjs/src/common/gateways/events.gateway.ts +157 -0
- package/nestjs/src/common/guards/clinic-access.guard.ts +40 -0
- package/nestjs/src/common/guards/features.guard.ts +38 -0
- package/nestjs/src/common/guards/index.ts +5 -0
- package/nestjs/src/common/guards/jwt-auth.guard.ts +54 -0
- package/nestjs/src/common/guards/permissions.guard.ts +50 -0
- package/nestjs/src/common/guards/superadmin.guard.ts +35 -0
- package/nestjs/src/common/interceptors/request-context.interceptor.ts +32 -0
- package/nestjs/src/common/interceptors/superadmin-tenant.interceptor.ts +42 -0
- package/nestjs/src/common/interfaces/jwt-payload.interface.ts +11 -0
- package/nestjs/src/config/config.module.ts +13 -0
- package/nestjs/src/database/database.module.ts +9 -0
- package/nestjs/src/database/prisma.service.ts +20 -0
- package/nestjs/src/database/tenant-context.ts +27 -0
- package/nestjs/src/google-calendar/google-calendar.controller.ts +259 -0
- package/nestjs/src/google-calendar/google-calendar.module.ts +10 -0
- package/nestjs/src/google-calendar/google-calendar.service.ts +811 -0
- package/nestjs/src/integrations/ai/ai.interface.ts +74 -0
- package/nestjs/src/integrations/ai/ai.module.ts +11 -0
- package/nestjs/src/integrations/ai/ai.service.ts +148 -0
- package/nestjs/src/integrations/ai/providers/anthropic.provider.ts +146 -0
- package/nestjs/src/integrations/ai/providers/openai.provider.ts +158 -0
- package/nestjs/src/integrations/elevenlabs/elevenlabs.module.ts +8 -0
- package/nestjs/src/integrations/elevenlabs/elevenlabs.service.ts +226 -0
- package/nestjs/src/integrations/encryption/encryption.module.ts +9 -0
- package/nestjs/src/integrations/encryption/encryption.service.ts +31 -0
- package/nestjs/src/integrations/image/image.module.ts +9 -0
- package/nestjs/src/integrations/image/image.service.ts +61 -0
- package/nestjs/src/integrations/meta-business/meta-business.module.ts +10 -0
- package/nestjs/src/integrations/meta-business/meta-instagram.service.ts +94 -0
- package/nestjs/src/integrations/meta-business/meta-webhook.service.ts +52 -0
- package/nestjs/src/integrations/meta-business/meta-whatsapp.service.ts +254 -0
- package/nestjs/src/integrations/minio/minio.module.ts +9 -0
- package/nestjs/src/integrations/minio/minio.service.ts +88 -0
- package/nestjs/src/integrations/netgsm/netgsm.module.ts +8 -0
- package/nestjs/src/integrations/netgsm/netgsm.service.ts +17 -0
- package/nestjs/src/integrations/tektippay/tektippay.module.ts +8 -0
- package/nestjs/src/integrations/tektippay/tektippay.service.ts +23 -0
- package/nestjs/src/leads/dto/index.ts +2 -0
- package/nestjs/src/leads/dto/query-leads.dto.ts +50 -0
- package/nestjs/src/leads/dto/update-lead.dto.ts +26 -0
- package/nestjs/src/leads/leads.controller.ts +184 -0
- package/nestjs/src/leads/leads.module.ts +10 -0
- package/nestjs/src/leads/leads.service.ts +375 -0
- package/nestjs/src/logging/logging.controller.ts +82 -0
- package/nestjs/src/logging/logging.module.ts +11 -0
- package/nestjs/src/logging/logging.service.ts +180 -0
- package/nestjs/src/main.ts +86 -0
- package/nestjs/src/outbound-campaigns/dto/create-campaign.dto.ts +47 -0
- package/nestjs/src/outbound-campaigns/dto/index.ts +3 -0
- package/nestjs/src/outbound-campaigns/dto/update-campaign.dto.ts +31 -0
- package/nestjs/src/outbound-campaigns/dto/upload-entries.dto.ts +35 -0
- package/nestjs/src/outbound-campaigns/outbound-campaigns.controller.ts +307 -0
- package/nestjs/src/outbound-campaigns/outbound-campaigns.module.ts +13 -0
- package/nestjs/src/outbound-campaigns/outbound-campaigns.service.ts +471 -0
- package/nestjs/src/outbound-campaigns/processors/campaign-dispatch.processor.ts +366 -0
- package/nestjs/src/patients/documents.service.ts +231 -0
- package/nestjs/src/patients/dto/create-examination.dto.ts +34 -0
- package/nestjs/src/patients/dto/create-note.dto.ts +14 -0
- package/nestjs/src/patients/dto/create-patient.dto.ts +86 -0
- package/nestjs/src/patients/dto/create-photo-set.dto.ts +32 -0
- package/nestjs/src/patients/dto/index.ts +10 -0
- package/nestjs/src/patients/dto/update-examination.dto.ts +29 -0
- package/nestjs/src/patients/dto/update-medical-history.dto.ts +47 -0
- package/nestjs/src/patients/dto/update-patient.dto.ts +87 -0
- package/nestjs/src/patients/dto/update-photo-set.dto.ts +28 -0
- package/nestjs/src/patients/dto/upload-document.dto.ts +31 -0
- package/nestjs/src/patients/dto/upload-photo.dto.ts +27 -0
- package/nestjs/src/patients/examinations.service.ts +271 -0
- package/nestjs/src/patients/medical-history.service.ts +149 -0
- package/nestjs/src/patients/notes.service.ts +172 -0
- package/nestjs/src/patients/patients.controller.ts +485 -0
- package/nestjs/src/patients/patients.module.ts +22 -0
- package/nestjs/src/patients/patients.service.ts +412 -0
- package/nestjs/src/patients/photo-sets.service.ts +389 -0
- package/nestjs/src/phone-numbers/dto/create-phone-number.dto.ts +57 -0
- package/nestjs/src/phone-numbers/dto/index.ts +3 -0
- package/nestjs/src/phone-numbers/dto/update-phone-number.dto.ts +38 -0
- package/nestjs/src/phone-numbers/dto/update-schedule.dto.ts +39 -0
- package/nestjs/src/phone-numbers/phone-numbers.controller.ts +125 -0
- package/nestjs/src/phone-numbers/phone-numbers.module.ts +10 -0
- package/nestjs/src/phone-numbers/phone-numbers.service.ts +209 -0
- package/nestjs/src/plans/dto/create-plan.dto.ts +70 -0
- package/nestjs/src/plans/dto/index.ts +2 -0
- package/nestjs/src/plans/dto/update-plan.dto.ts +80 -0
- package/nestjs/src/plans/plans.controller.ts +50 -0
- package/nestjs/src/plans/plans.module.ts +10 -0
- package/nestjs/src/plans/plans.service.ts +115 -0
- package/nestjs/src/platform/dto/create-tenant.dto.ts +36 -0
- package/nestjs/src/platform/dto/index.ts +2 -0
- package/nestjs/src/platform/dto/update-tenant-platform.dto.ts +44 -0
- package/nestjs/src/platform/platform.controller.ts +79 -0
- package/nestjs/src/platform/platform.module.ts +10 -0
- package/nestjs/src/platform/platform.service.ts +301 -0
- package/nestjs/src/queue/queue.module.ts +56 -0
- package/nestjs/src/redis/redis.module.ts +20 -0
- package/nestjs/src/tenants/dto/index.ts +1 -0
- package/nestjs/src/tenants/dto/update-tenant.dto.ts +15 -0
- package/nestjs/src/tenants/tenants.controller.ts +45 -0
- package/nestjs/src/tenants/tenants.module.ts +10 -0
- package/nestjs/src/tenants/tenants.service.ts +41 -0
- package/nestjs/src/tools/adapters/elevenlabs-http.adapter.ts +51 -0
- package/nestjs/src/tools/adapters/elevenlabs-ws.adapter.ts +59 -0
- package/nestjs/src/tools/handlers/calendar.tools.ts +441 -0
- package/nestjs/src/tools/handlers/notification.tools.ts +34 -0
- package/nestjs/src/tools/handlers/operator.tools.ts +303 -0
- package/nestjs/src/tools/handlers/patient.tools.ts +242 -0
- package/nestjs/src/tools/handlers/payment.tools.ts +43 -0
- package/nestjs/src/tools/handlers/validation.tools.ts +152 -0
- package/nestjs/src/tools/tool-registry.service.ts +221 -0
- package/nestjs/src/tools/tool.decorator.ts +16 -0
- package/nestjs/src/tools/tool.interfaces.ts +26 -0
- package/nestjs/src/tools/tools.module.ts +50 -0
- package/nestjs/src/treatments/dto/create-plan-item.dto.ts +27 -0
- package/nestjs/src/treatments/dto/create-treatment-plan.dto.ts +69 -0
- package/nestjs/src/treatments/dto/create-treatment.dto.ts +59 -0
- package/nestjs/src/treatments/dto/index.ts +6 -0
- package/nestjs/src/treatments/dto/update-plan-item.dto.ts +23 -0
- package/nestjs/src/treatments/dto/update-treatment-plan.dto.ts +22 -0
- package/nestjs/src/treatments/dto/update-treatment.dto.ts +70 -0
- package/nestjs/src/treatments/treatment-plans.service.ts +362 -0
- package/nestjs/src/treatments/treatments.controller.ts +265 -0
- package/nestjs/src/treatments/treatments.module.ts +14 -0
- package/nestjs/src/treatments/treatments.service.ts +165 -0
- package/nestjs/src/users/doctor-profiles.service.ts +202 -0
- package/nestjs/src/users/dto/index.ts +4 -0
- package/nestjs/src/users/dto/invite-user.dto.ts +52 -0
- package/nestjs/src/users/dto/update-clinic-assignments.dto.ts +9 -0
- package/nestjs/src/users/dto/update-doctor-profile.dto.ts +49 -0
- package/nestjs/src/users/dto/update-user.dto.ts +41 -0
- package/nestjs/src/users/users.controller.ts +142 -0
- package/nestjs/src/users/users.module.ts +11 -0
- package/nestjs/src/users/users.service.ts +250 -0
- package/nestjs/src/webhooks/elevenlabs-tool.controller.ts +66 -0
- package/nestjs/src/webhooks/elevenlabs-webhook.controller.ts +60 -0
- package/nestjs/src/webhooks/meta-webhook.controller.ts +178 -0
- package/nestjs/src/webhooks/processors/elevenlabs-webhook.processor.ts +28 -0
- package/nestjs/src/webhooks/webhooks.module.ts +17 -0
- package/nestjs/src/whatsapp/chat-context.service.ts +281 -0
- package/nestjs/src/whatsapp/dto/add-blacklist.dto.ts +13 -0
- package/nestjs/src/whatsapp/dto/index.ts +2 -0
- package/nestjs/src/whatsapp/dto/send-message.dto.ts +14 -0
- package/nestjs/src/whatsapp/listeners/meta-message.listener.ts +579 -0
- package/nestjs/src/whatsapp/meta-auth.controller.ts +268 -0
- package/nestjs/src/whatsapp/meta-instagram-auth.controller.ts +244 -0
- package/nestjs/src/whatsapp/operator.service.ts +692 -0
- package/nestjs/src/whatsapp/processors/cost-sweep.processor.ts +130 -0
- package/nestjs/src/whatsapp/processors/grace.processor.ts +191 -0
- package/nestjs/src/whatsapp/processors/message-buffer.processor.ts +138 -0
- package/nestjs/src/whatsapp/processors/message-cleanup.processor.ts +148 -0
- package/nestjs/src/whatsapp/processors/meta-token-refresh.processor.ts +114 -0
- package/nestjs/src/whatsapp/processors/operator-expiry.processor.ts +105 -0
- package/nestjs/src/whatsapp/processors/profile-update.processor.ts +234 -0
- package/nestjs/src/whatsapp/processors/session-cleanup.processor.ts +178 -0
- package/nestjs/src/whatsapp/processors/session-labels.processor.ts +248 -0
- package/nestjs/src/whatsapp/whatsapp-agent.service.ts +2506 -0
- package/nestjs/src/whatsapp/whatsapp-recovery.service.ts +117 -0
- package/nestjs/src/whatsapp/whatsapp.controller.ts +398 -0
- package/nestjs/src/whatsapp/whatsapp.module.ts +51 -0
- package/nestjs/src/whatsapp/whatsapp.service.ts +592 -0
- package/nestjs/test/app.e2e-spec.ts +25 -0
- package/nestjs/test/jest-e2e.json +9 -0
- package/nestjs/tsconfig.build.json +4 -0
- package/nestjs/tsconfig.json +25 -0
- package/nginx.example.conf +18 -0
- package/package.json +47 -0
- package/scripts/addRecipient.ts +48 -0
- package/scripts/listRecipients.ts +31 -0
- package/scripts/migrate-agent-ref.ts +86 -0
- package/scripts/migrate-sessions.ts +183 -0
- package/scripts/promote.ts +27 -0
- package/scripts/retrigger.ts +84 -0
- package/scripts/seed.ts +435 -0
- package/scripts/testSend.ts +63 -0
- package/src/app.ts +85 -0
- package/src/config/agentPrompts.json +19 -0
- package/src/config/database.ts +21 -0
- package/src/config/env.ts +94 -0
- package/src/config/index.ts +86 -0
- package/src/controllers/webhook.controller.ts +150 -0
- package/src/errors/index.ts +9 -0
- package/src/hooks/webhookValidator.ts +55 -0
- package/src/index.ts +68 -0
- package/src/migrations/001_session-architecture.ts +138 -0
- package/src/migrations/002_agent-ref.ts +65 -0
- package/src/migrations/003_shift-schedule.ts +55 -0
- package/src/migrations/004_invert-shift-to-clinic-hours.ts +30 -0
- package/src/migrations/005_composite-baileys-chat-ids.ts +60 -0
- package/src/migrations/migration.model.ts +27 -0
- package/src/migrations/migration.routes.ts +40 -0
- package/src/migrations/migration.runner.ts +112 -0
- package/src/models/ConversationClaim.ts +17 -0
- package/src/models/ConversationEvaluation.ts +91 -0
- package/src/models/Summary.ts +77 -0
- package/src/models/Transcription.ts +68 -0
- package/src/models/WhatsAppRecipient.ts +37 -0
- package/src/modules/admin/admin.routes.ts +2385 -0
- package/src/modules/admin/elevenlabs-test-chat.routes.ts +193 -0
- package/src/modules/admin/whatsapp-test-chat.routes.ts +244 -0
- package/src/modules/agents/agent.model.ts +93 -0
- package/src/modules/agents/agent.routes.ts +65 -0
- package/src/modules/appointment-validation/appointment-validation.model.ts +163 -0
- package/src/modules/appointment-validation/appointment-validation.routes.ts +275 -0
- package/src/modules/appointment-validation/appointment-validation.service.ts +1028 -0
- package/src/modules/auth/auth.model.ts +42 -0
- package/src/modules/auth/auth.routes.ts +199 -0
- package/src/modules/auth/auth.service.ts +210 -0
- package/src/modules/auth/refresh-token.model.ts +26 -0
- package/src/modules/billing/billing-alert.model.ts +28 -0
- package/src/modules/billing/billing-period-snapshot.model.ts +68 -0
- package/src/modules/billing/billing.model.ts +42 -0
- package/src/modules/billing/billing.routes.ts +67 -0
- package/src/modules/billing/billing.service.ts +562 -0
- package/src/modules/billing/payment.model.ts +42 -0
- package/src/modules/calls/call.model.ts +102 -0
- package/src/modules/calls/call.routes.ts +118 -0
- package/src/modules/campaigns/campaign.model.ts +111 -0
- package/src/modules/campaigns/campaign.routes.ts +402 -0
- package/src/modules/campaigns/campaign.service.ts +99 -0
- package/src/modules/google-calendar/google-calendar.routes.ts +31 -0
- package/src/modules/inbound-call/inbound-call-config.model.ts +49 -0
- package/src/modules/inbound-call/inbound-call.routes.ts +289 -0
- package/src/modules/leads/lead.model.ts +40 -0
- package/src/modules/leads/lead.routes.ts +246 -0
- package/src/modules/logs/log.model.ts +27 -0
- package/src/modules/logs/log.routes.ts +102 -0
- package/src/modules/plans/plan.model.ts +45 -0
- package/src/modules/surveys/survey.model.ts +70 -0
- package/src/modules/surveys/survey.routes.ts +187 -0
- package/src/modules/tenants/tenant.model.ts +181 -0
- package/src/modules/tenants/tenant.routes.ts +78 -0
- package/src/modules/users/user.routes.ts +126 -0
- package/src/modules/webhooks/elevenlabs-tool.routes.ts +94 -0
- package/src/modules/webhooks/elevenlabs-tool.service.ts +491 -0
- package/src/modules/webhooks/elevenlabs.routes.ts +34 -0
- package/src/modules/webhooks/elevenlabs.service.ts +565 -0
- package/src/modules/webhooks/unipile.routes.ts +917 -0
- package/src/modules/whatsapp/appointment.model.ts +47 -0
- package/src/modules/whatsapp/operator-request.model.ts +58 -0
- package/src/modules/whatsapp/stt-usage.model.ts +30 -0
- package/src/modules/whatsapp/whatsapp-chat.model.ts +39 -0
- package/src/modules/whatsapp/whatsapp-contact-profile.model.ts +41 -0
- package/src/modules/whatsapp/whatsapp-message.model.ts +41 -0
- package/src/modules/whatsapp/whatsapp-session.model.ts +60 -0
- package/src/modules/whatsapp/whatsapp.routes.ts +1435 -0
- package/src/plugins/cors.ts +7 -0
- package/src/plugins/jwt.ts +18 -0
- package/src/plugins/rawBody.ts +12 -0
- package/src/plugins/rbac.ts +24 -0
- package/src/routes/admin.routes.ts +208 -0
- package/src/routes/health.routes.ts +12 -0
- package/src/routes/webhook.routes.ts +12 -0
- package/src/services/ai/base.ai.ts +132 -0
- package/src/services/ai/gemini.service.ts +41 -0
- package/src/services/ai/index.ts +24 -0
- package/src/services/ai/openai.service.ts +48 -0
- package/src/services/elevenlabs.service.ts +532 -0
- package/src/services/google-calendar.service.ts +656 -0
- package/src/services/inbound-call-schedule.service.ts +174 -0
- package/src/services/netgsm.service.ts +128 -0
- package/src/services/unipile.service.ts +200 -0
- package/src/services/whatsapp-agent.service.ts +2479 -0
- package/src/services/whatsapp.service.ts +245 -0
- package/src/templates/index.ts +71 -0
- package/src/templates/receptionist.ts +44 -0
- package/src/templates/survey.ts +44 -0
- package/src/types/index.ts +218 -0
- package/src/utils/logger.ts +83 -0
- package/tsconfig.json +19 -0
- package/web/.dockerignore +4 -0
- package/web/Dockerfile +18 -0
- package/web/README.md +73 -0
- package/web/components.json +23 -0
- package/web/eslint.config.js +23 -0
- package/web/index.html +14 -0
- package/web/nginx.conf +18 -0
- package/web/package-lock.json +10292 -0
- package/web/package.json +48 -0
- package/web/public/favicon.ico +0 -0
- package/web/public/vite.svg +1 -0
- package/web/src/App.tsx +191 -0
- package/web/src/assets/react.svg +1 -0
- package/web/src/components/Layout.tsx +261 -0
- package/web/src/components/LeadConversation.tsx +251 -0
- package/web/src/components/ProtectedRoute.tsx +20 -0
- package/web/src/components/conversation-review/CardAudioPlayer.tsx +200 -0
- package/web/src/components/conversation-review/CardEvaluation.tsx +351 -0
- package/web/src/components/conversation-review/CardMetadata.tsx +44 -0
- package/web/src/components/conversation-review/ConversationCard.tsx +95 -0
- package/web/src/components/conversation-review/ReviewContainer.tsx +120 -0
- package/web/src/components/conversation-review/ReviewFilters.tsx +88 -0
- package/web/src/components/empty-state.tsx +15 -0
- package/web/src/components/page-header.tsx +19 -0
- package/web/src/components/page-loader.tsx +32 -0
- package/web/src/components/pagination.tsx +38 -0
- package/web/src/components/stat-card.tsx +27 -0
- package/web/src/components/status-badge.tsx +125 -0
- package/web/src/components/ui/alert.tsx +66 -0
- package/web/src/components/ui/badge.tsx +48 -0
- package/web/src/components/ui/button.tsx +64 -0
- package/web/src/components/ui/card.tsx +92 -0
- package/web/src/components/ui/checkbox.tsx +32 -0
- package/web/src/components/ui/dialog.tsx +158 -0
- package/web/src/components/ui/dropdown-menu.tsx +255 -0
- package/web/src/components/ui/input.tsx +21 -0
- package/web/src/components/ui/label.tsx +22 -0
- package/web/src/components/ui/progress.tsx +29 -0
- package/web/src/components/ui/select.tsx +188 -0
- package/web/src/components/ui/separator.tsx +28 -0
- package/web/src/components/ui/sheet.tsx +123 -0
- package/web/src/components/ui/skeleton.tsx +13 -0
- package/web/src/components/ui/sonner.tsx +35 -0
- package/web/src/components/ui/table.tsx +116 -0
- package/web/src/components/ui/tabs.tsx +89 -0
- package/web/src/components/ui/textarea.tsx +18 -0
- package/web/src/components/ui/tooltip.tsx +57 -0
- package/web/src/components/whatsapp/ChatDetail.tsx +417 -0
- package/web/src/components/whatsapp/ChatHeader.tsx +78 -0
- package/web/src/components/whatsapp/ChatList.tsx +107 -0
- package/web/src/components/whatsapp/ChatListItem.tsx +60 -0
- package/web/src/components/whatsapp/MessageBubble.tsx +46 -0
- package/web/src/components/whatsapp/MessageInput.tsx +63 -0
- package/web/src/components/whatsapp/MessageStream.tsx +135 -0
- package/web/src/components/whatsapp/SessionDivider.tsx +65 -0
- package/web/src/components/whatsapp/SessionHistory.tsx +119 -0
- package/web/src/components/whatsapp/settings/AiSettingsTab.tsx +268 -0
- package/web/src/components/whatsapp/settings/CalendarTab.tsx +339 -0
- package/web/src/components/whatsapp/settings/ConnectionTab.tsx +236 -0
- package/web/src/components/whatsapp/settings/NotificationsTab.tsx +109 -0
- package/web/src/components/whatsapp/settings/OperatorTab.tsx +303 -0
- package/web/src/contexts/AuthContext.tsx +103 -0
- package/web/src/index.css +130 -0
- package/web/src/lib/api.ts +92 -0
- package/web/src/lib/utils.ts +6 -0
- package/web/src/main.tsx +10 -0
- package/web/src/pages/AppointmentDetail.tsx +206 -0
- package/web/src/pages/AppointmentValidation.tsx +157 -0
- package/web/src/pages/AppointmentValidationDetail.tsx +617 -0
- package/web/src/pages/AppointmentValidationNew.tsx +1005 -0
- package/web/src/pages/Appointments.tsx +283 -0
- package/web/src/pages/Billing.tsx +126 -0
- package/web/src/pages/CallDetail.tsx +293 -0
- package/web/src/pages/CallSettings.tsx +313 -0
- package/web/src/pages/Calls.tsx +188 -0
- package/web/src/pages/CampaignDetail.tsx +216 -0
- package/web/src/pages/CampaignNew.tsx +277 -0
- package/web/src/pages/CampaignResults.tsx +185 -0
- package/web/src/pages/Campaigns.tsx +171 -0
- package/web/src/pages/Dashboard.tsx +336 -0
- package/web/src/pages/InboundSchedule.tsx +246 -0
- package/web/src/pages/LeadDetail.tsx +183 -0
- package/web/src/pages/Leads.tsx +258 -0
- package/web/src/pages/Login.tsx +99 -0
- package/web/src/pages/Register.tsx +129 -0
- package/web/src/pages/Settings.tsx +133 -0
- package/web/src/pages/SurveyDetail.tsx +232 -0
- package/web/src/pages/SurveyPreview.tsx +179 -0
- package/web/src/pages/Surveys.tsx +207 -0
- package/web/src/pages/Users.tsx +199 -0
- package/web/src/pages/WhatsApp.tsx +147 -0
- package/web/src/pages/WhatsAppSettings.tsx +215 -0
- package/web/src/pages/admin/AdminBaileysMessageLog.tsx +331 -0
- package/web/src/pages/admin/AdminBaileysRawMessages.tsx +318 -0
- package/web/src/pages/admin/AdminConversationReview.tsx +116 -0
- package/web/src/pages/admin/AdminCredits.tsx +467 -0
- package/web/src/pages/admin/AdminElevenLabsAgentDetail.tsx +332 -0
- package/web/src/pages/admin/AdminElevenLabsAgents.tsx +164 -0
- package/web/src/pages/admin/AdminElevenLabsBatchCallDetail.tsx +214 -0
- package/web/src/pages/admin/AdminElevenLabsBatchCalls.tsx +293 -0
- package/web/src/pages/admin/AdminElevenLabsConversationDetail.tsx +230 -0
- package/web/src/pages/admin/AdminElevenLabsConversations.tsx +228 -0
- package/web/src/pages/admin/AdminElevenLabsInboundCalls.tsx +293 -0
- package/web/src/pages/admin/AdminElevenLabsPhoneNumbers.tsx +506 -0
- package/web/src/pages/admin/AdminElevenLabsTestChat.tsx +258 -0
- package/web/src/pages/admin/AdminElevenLabsWebhooks.tsx +289 -0
- package/web/src/pages/admin/AdminEvaluationDashboard.tsx +520 -0
- package/web/src/pages/admin/AdminLeads.tsx +339 -0
- package/web/src/pages/admin/AdminLogs.tsx +283 -0
- package/web/src/pages/admin/AdminMigrations.tsx +247 -0
- package/web/src/pages/admin/AdminPlans.tsx +313 -0
- package/web/src/pages/admin/AdminSystem.tsx +391 -0
- package/web/src/pages/admin/AdminTenantBillableItems.tsx +464 -0
- package/web/src/pages/admin/AdminTenantDetail.tsx +1317 -0
- package/web/src/pages/admin/AdminTenants.tsx +274 -0
- package/web/src/pages/admin/AdminWhatsApp.tsx +618 -0
- package/web/src/pages/admin/AdminWhatsAppTestChat.tsx +328 -0
- package/web/src/types/index.ts +242 -0
- package/web/tsconfig.app.json +32 -0
- package/web/tsconfig.json +13 -0
- package/web/tsconfig.node.json +26 -0
- package/web/vite.config.ts +23 -0
|
@@ -0,0 +1,1843 @@
|
|
|
1
|
+
// Portal Asistan 7/24 — Complete PostgreSQL Prisma Schema
|
|
2
|
+
// Source of truth: docs/architecture/01-DATABASE-SCHEMA.md
|
|
3
|
+
// 44 active tables (whatsapp_contact_profiles #19 and whatsapp_recipients #35 REMOVED)
|
|
4
|
+
|
|
5
|
+
generator client {
|
|
6
|
+
provider = "prisma-client-js"
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
datasource db {
|
|
10
|
+
provider = "postgresql"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// ─────────────────────────────────────────────
|
|
14
|
+
// ENUMS
|
|
15
|
+
// ─────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
enum UserRole {
|
|
18
|
+
superadmin
|
|
19
|
+
sales
|
|
20
|
+
owner
|
|
21
|
+
admin
|
|
22
|
+
doctor
|
|
23
|
+
receptionist
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
enum PostCallStrategy {
|
|
27
|
+
summarize
|
|
28
|
+
none
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
enum CallDirection {
|
|
32
|
+
inbound
|
|
33
|
+
outbound
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
enum CallStatus {
|
|
37
|
+
completed
|
|
38
|
+
failed
|
|
39
|
+
no_answer
|
|
40
|
+
voicemail
|
|
41
|
+
transferred
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
enum Sentiment {
|
|
45
|
+
positive
|
|
46
|
+
neutral
|
|
47
|
+
negative
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
enum OutboundCampaignStatus {
|
|
51
|
+
draft
|
|
52
|
+
scheduled
|
|
53
|
+
running
|
|
54
|
+
paused
|
|
55
|
+
completed
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
enum CampaignEntryStatus {
|
|
59
|
+
pending
|
|
60
|
+
calling
|
|
61
|
+
completed
|
|
62
|
+
failed
|
|
63
|
+
no_answer
|
|
64
|
+
voicemail
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
enum SessionStatus {
|
|
68
|
+
waiting
|
|
69
|
+
active
|
|
70
|
+
resolved
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
enum SessionResolvedBy {
|
|
74
|
+
human
|
|
75
|
+
ai_timeout
|
|
76
|
+
timeout
|
|
77
|
+
manual
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
enum MessageSender {
|
|
81
|
+
contact
|
|
82
|
+
ai
|
|
83
|
+
human
|
|
84
|
+
system
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
enum OperatorRequestStatus {
|
|
88
|
+
pending
|
|
89
|
+
responded
|
|
90
|
+
expired
|
|
91
|
+
cancelled
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
enum AcmRole {
|
|
95
|
+
user
|
|
96
|
+
assistant
|
|
97
|
+
system
|
|
98
|
+
tool_result
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
enum LeadStatus {
|
|
102
|
+
new_lead
|
|
103
|
+
contacted
|
|
104
|
+
appointment_scheduled
|
|
105
|
+
completed
|
|
106
|
+
lost
|
|
107
|
+
expired
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
enum AppointmentStatus {
|
|
111
|
+
scheduled
|
|
112
|
+
confirmed
|
|
113
|
+
in_progress
|
|
114
|
+
completed
|
|
115
|
+
cancelled
|
|
116
|
+
no_show
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
enum AppointmentSource {
|
|
120
|
+
whatsapp
|
|
121
|
+
voice_call
|
|
122
|
+
dashboard
|
|
123
|
+
walk_in
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
enum AppointmentType {
|
|
127
|
+
appointment
|
|
128
|
+
walk_in
|
|
129
|
+
follow_up
|
|
130
|
+
consultation
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
enum BatchStatus {
|
|
134
|
+
draft
|
|
135
|
+
submitted
|
|
136
|
+
in_progress
|
|
137
|
+
completed
|
|
138
|
+
cancelled
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
enum EntryCallStatus {
|
|
142
|
+
pending
|
|
143
|
+
calling
|
|
144
|
+
completed
|
|
145
|
+
failed
|
|
146
|
+
no_answer
|
|
147
|
+
voicemail
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
enum ValidationResult {
|
|
151
|
+
confirmed
|
|
152
|
+
cancelled
|
|
153
|
+
reschedule
|
|
154
|
+
unresolved
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
enum BillingEventType {
|
|
158
|
+
call_charge
|
|
159
|
+
subscription
|
|
160
|
+
top_up
|
|
161
|
+
refund
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
enum PaymentType {
|
|
165
|
+
subscription
|
|
166
|
+
top_up
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
enum PaymentMethod {
|
|
170
|
+
cash
|
|
171
|
+
bank_transfer
|
|
172
|
+
other
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
enum AlertType {
|
|
176
|
+
usage_75
|
|
177
|
+
usage_90
|
|
178
|
+
usage_100
|
|
179
|
+
period_expiring
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
enum AlertService {
|
|
183
|
+
inbound_minutes
|
|
184
|
+
inbound_calls
|
|
185
|
+
wa_chats
|
|
186
|
+
billing_period
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
enum ChatChannel {
|
|
190
|
+
whatsapp
|
|
191
|
+
instagram
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
enum PhoneNumberPurpose {
|
|
195
|
+
whatsapp
|
|
196
|
+
inbound_call
|
|
197
|
+
outbound_call
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
enum PhoneNumberProvider {
|
|
201
|
+
meta_business
|
|
202
|
+
elevenlabs
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
enum MigrationStatus {
|
|
206
|
+
success
|
|
207
|
+
failed
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
enum NotificationDeliveryStatus {
|
|
211
|
+
pending
|
|
212
|
+
sending
|
|
213
|
+
sent
|
|
214
|
+
failed
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
enum TranscriptionProcessingStatus {
|
|
218
|
+
pending
|
|
219
|
+
summarizing
|
|
220
|
+
summarized
|
|
221
|
+
notified
|
|
222
|
+
failed
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
enum AvailabilityBlockType {
|
|
226
|
+
holiday
|
|
227
|
+
leave
|
|
228
|
+
break_time
|
|
229
|
+
other
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
enum TreatmentPlanStatus {
|
|
233
|
+
active
|
|
234
|
+
completed
|
|
235
|
+
cancelled
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
enum TreatmentPlanItemStatus {
|
|
239
|
+
planned
|
|
240
|
+
scheduled
|
|
241
|
+
in_progress
|
|
242
|
+
completed
|
|
243
|
+
cancelled
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ─────────────────────────────────────────────
|
|
247
|
+
// 1. TENANTS
|
|
248
|
+
// ─────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
model Tenant {
|
|
251
|
+
tenant_id String @id @default(uuid())
|
|
252
|
+
tenant_name String
|
|
253
|
+
tenant_plan_id String?
|
|
254
|
+
tenant_enabled_features String[] @default([])
|
|
255
|
+
tenant_is_active Boolean @default(true)
|
|
256
|
+
tenant_deleted_at DateTime?
|
|
257
|
+
tenant_kvkk_consent Boolean @default(false)
|
|
258
|
+
tenant_max_clinics Int @default(1)
|
|
259
|
+
tenant_max_users Int @default(5)
|
|
260
|
+
tenant_max_doctors Int @default(2)
|
|
261
|
+
tenant_max_patients Int @default(500)
|
|
262
|
+
tenant_created_at DateTime @default(now())
|
|
263
|
+
tenant_updated_at DateTime @updatedAt
|
|
264
|
+
|
|
265
|
+
// Relations
|
|
266
|
+
plan Plan? @relation(fields: [tenant_plan_id], references: [plan_id])
|
|
267
|
+
|
|
268
|
+
clinics Clinic[]
|
|
269
|
+
users User[]
|
|
270
|
+
agents Agent[]
|
|
271
|
+
phone_numbers PhoneNumber[]
|
|
272
|
+
patients Patient[]
|
|
273
|
+
treatments Treatment[]
|
|
274
|
+
calls Call[]
|
|
275
|
+
leads Lead[]
|
|
276
|
+
outbound_campaigns OutboundCampaign[]
|
|
277
|
+
whatsapp_chats WhatsappChat[]
|
|
278
|
+
whatsapp_sessions WhatsappSession[]
|
|
279
|
+
whatsapp_messages WhatsappMessage[]
|
|
280
|
+
operator_requests OperatorRequest[]
|
|
281
|
+
appointments Appointment[]
|
|
282
|
+
appointment_validation_batches AppointmentValidationBatch[]
|
|
283
|
+
billing_events BillingEvent[]
|
|
284
|
+
payments Payment[]
|
|
285
|
+
billing_period_snapshots BillingPeriodSnapshot[]
|
|
286
|
+
billing_alerts BillingAlert[]
|
|
287
|
+
stt_usages SttUsage[]
|
|
288
|
+
treatment_plans TreatmentPlan[]
|
|
289
|
+
patient_documents PatientDocument[]
|
|
290
|
+
patient_notes PatientNote[]
|
|
291
|
+
patient_photo_sets PatientPhotoSet[]
|
|
292
|
+
examination_records ExaminationRecord[]
|
|
293
|
+
availability_blocks AvailabilityBlock[]
|
|
294
|
+
|
|
295
|
+
@@index([tenant_plan_id], name: "idx_tenants_plan")
|
|
296
|
+
@@map("tenants")
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ─────────────────────────────────────────────
|
|
300
|
+
// 2. CLINICS
|
|
301
|
+
// ─────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
model Clinic {
|
|
304
|
+
clinic_id String @id @default(uuid())
|
|
305
|
+
clinic_tenant_id String
|
|
306
|
+
clinic_name String
|
|
307
|
+
clinic_slug String
|
|
308
|
+
clinic_address String @default("")
|
|
309
|
+
clinic_phone String @default("")
|
|
310
|
+
clinic_email String @default("")
|
|
311
|
+
clinic_timezone String @default("Europe/Istanbul")
|
|
312
|
+
clinic_is_default Boolean @default(false)
|
|
313
|
+
clinic_is_active Boolean @default(true)
|
|
314
|
+
clinic_language String @default("tr")
|
|
315
|
+
clinic_ai_provider String @default("openai")
|
|
316
|
+
clinic_ai_model String @default("")
|
|
317
|
+
clinic_grace_period_seconds Int @default(180)
|
|
318
|
+
clinic_operator_phone String?
|
|
319
|
+
clinic_operator_prefix String @default("R")
|
|
320
|
+
clinic_operator_timeout_hours Int @default(24)
|
|
321
|
+
clinic_ai_shift_enabled Boolean @default(false)
|
|
322
|
+
clinic_ai_shift_schedule Json @default("[]")
|
|
323
|
+
clinic_blacklisted_numbers String[] @default([])
|
|
324
|
+
clinic_fixed_first_message String?
|
|
325
|
+
clinic_sms_enabled Boolean @default(false)
|
|
326
|
+
clinic_sms_phones String[] @default([])
|
|
327
|
+
clinic_notification_phones String[] @default([])
|
|
328
|
+
clinic_message_retention_days Int @default(7)
|
|
329
|
+
clinic_created_at DateTime @default(now())
|
|
330
|
+
clinic_updated_at DateTime @updatedAt
|
|
331
|
+
|
|
332
|
+
// Relations
|
|
333
|
+
tenant Tenant @relation(fields: [clinic_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
334
|
+
|
|
335
|
+
user_clinic_assignments UserClinicAssignment[]
|
|
336
|
+
calendar_connection ClinicCalendarConnection?
|
|
337
|
+
meta_connections ClinicMetaConnection[]
|
|
338
|
+
agents Agent[]
|
|
339
|
+
agent_assignments AgentClinicAssignment[]
|
|
340
|
+
phone_numbers PhoneNumber[]
|
|
341
|
+
patients Patient[]
|
|
342
|
+
treatments Treatment[]
|
|
343
|
+
calls Call[]
|
|
344
|
+
leads Lead[]
|
|
345
|
+
outbound_campaigns OutboundCampaign[]
|
|
346
|
+
whatsapp_chats WhatsappChat[]
|
|
347
|
+
whatsapp_sessions WhatsappSession[]
|
|
348
|
+
operator_requests OperatorRequest[]
|
|
349
|
+
appointments Appointment[]
|
|
350
|
+
appointment_validation_batches AppointmentValidationBatch[]
|
|
351
|
+
billing_events BillingEvent[]
|
|
352
|
+
stt_usages SttUsage[]
|
|
353
|
+
treatment_plans TreatmentPlan[]
|
|
354
|
+
patient_documents PatientDocument[]
|
|
355
|
+
patient_notes PatientNote[]
|
|
356
|
+
patient_photo_sets PatientPhotoSet[]
|
|
357
|
+
examination_records ExaminationRecord[]
|
|
358
|
+
availability_blocks AvailabilityBlock[]
|
|
359
|
+
|
|
360
|
+
@@unique([clinic_tenant_id, clinic_slug])
|
|
361
|
+
@@index([clinic_tenant_id], name: "idx_clinics_tenant")
|
|
362
|
+
@@index([clinic_tenant_id, clinic_operator_phone], name: "idx_clinics_operator")
|
|
363
|
+
@@map("clinics")
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ─────────────────────────────────────────────
|
|
367
|
+
// 3. CLINIC CALENDAR CONNECTIONS
|
|
368
|
+
// ─────────────────────────────────────────────
|
|
369
|
+
|
|
370
|
+
model ClinicCalendarConnection {
|
|
371
|
+
calcn_id String @id @default(uuid())
|
|
372
|
+
calcn_clinic_id String @unique
|
|
373
|
+
calcn_google_email String?
|
|
374
|
+
calcn_encrypted_refresh_token String?
|
|
375
|
+
calcn_calendar_id String?
|
|
376
|
+
calcn_calendar_name String?
|
|
377
|
+
calcn_appointment_duration Int @default(30)
|
|
378
|
+
calcn_working_hours Json @default("[]")
|
|
379
|
+
calcn_blocked_dates Json @default("[]")
|
|
380
|
+
calcn_connected_at DateTime?
|
|
381
|
+
calcn_created_at DateTime @default(now())
|
|
382
|
+
calcn_updated_at DateTime @updatedAt
|
|
383
|
+
|
|
384
|
+
// Relations
|
|
385
|
+
clinic Clinic @relation(fields: [calcn_clinic_id], references: [clinic_id], onDelete: Cascade)
|
|
386
|
+
|
|
387
|
+
@@map("clinic_calendar_connections")
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ─────────────────────────────────────────────
|
|
391
|
+
// 4. CLINIC META CONNECTIONS
|
|
392
|
+
// ─────────────────────────────────────────────
|
|
393
|
+
|
|
394
|
+
model ClinicMetaConnection {
|
|
395
|
+
meta_id String @id @default(uuid())
|
|
396
|
+
meta_clinic_id String
|
|
397
|
+
meta_type String
|
|
398
|
+
meta_label String @default("")
|
|
399
|
+
meta_waba_id String?
|
|
400
|
+
meta_phone_number_id String?
|
|
401
|
+
meta_display_phone String?
|
|
402
|
+
meta_instagram_page_id String? // Instagram Business Account ID
|
|
403
|
+
meta_facebook_page_id String? // Facebook Page ID (used for IG messaging API)
|
|
404
|
+
meta_encrypted_access_token String?
|
|
405
|
+
meta_token_expires_at DateTime?
|
|
406
|
+
meta_token_refreshed_at DateTime?
|
|
407
|
+
meta_is_active Boolean @default(true)
|
|
408
|
+
meta_connected_at DateTime?
|
|
409
|
+
meta_created_at DateTime @default(now())
|
|
410
|
+
meta_updated_at DateTime @updatedAt
|
|
411
|
+
|
|
412
|
+
// Relations
|
|
413
|
+
clinic Clinic @relation(fields: [meta_clinic_id], references: [clinic_id], onDelete: Cascade)
|
|
414
|
+
|
|
415
|
+
@@index([meta_clinic_id], name: "idx_meta_clinic")
|
|
416
|
+
@@index([meta_clinic_id, meta_type], name: "idx_meta_clinic_type")
|
|
417
|
+
@@index([meta_phone_number_id], name: "idx_meta_phone_number")
|
|
418
|
+
@@index([meta_instagram_page_id], name: "idx_meta_instagram_page")
|
|
419
|
+
@@map("clinic_meta_connections")
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// ─────────────────────────────────────────────
|
|
423
|
+
// 5. PHONE NUMBERS
|
|
424
|
+
// ─────────────────────────────────────────────
|
|
425
|
+
|
|
426
|
+
model PhoneNumber {
|
|
427
|
+
phone_id String @id @default(uuid())
|
|
428
|
+
phone_tenant_id String
|
|
429
|
+
phone_clinic_id String?
|
|
430
|
+
phone_number String
|
|
431
|
+
phone_label String @default("")
|
|
432
|
+
phone_purpose PhoneNumberPurpose
|
|
433
|
+
phone_provider PhoneNumberProvider
|
|
434
|
+
phone_external_account_id String?
|
|
435
|
+
phone_elevenlabs_phone_id String?
|
|
436
|
+
phone_elevenlabs_agent_id String?
|
|
437
|
+
phone_agent_id String?
|
|
438
|
+
phone_wa_connected Boolean @default(false)
|
|
439
|
+
phone_wa_connected_at DateTime?
|
|
440
|
+
phone_wa_bridge_provider String?
|
|
441
|
+
phone_schedule_enabled Boolean @default(false)
|
|
442
|
+
phone_schedule_mode String @default("active_hours")
|
|
443
|
+
phone_schedule Json @default("[]")
|
|
444
|
+
phone_agent_assigned Boolean @default(false)
|
|
445
|
+
phone_is_active Boolean @default(true)
|
|
446
|
+
phone_created_at DateTime @default(now())
|
|
447
|
+
phone_updated_at DateTime @updatedAt
|
|
448
|
+
|
|
449
|
+
// Relations
|
|
450
|
+
tenant Tenant @relation(fields: [phone_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
451
|
+
clinic Clinic? @relation(fields: [phone_clinic_id], references: [clinic_id])
|
|
452
|
+
agent Agent? @relation(fields: [phone_agent_id], references: [agent_id])
|
|
453
|
+
|
|
454
|
+
whatsapp_chats WhatsappChat[]
|
|
455
|
+
outbound_campaigns OutboundCampaign[]
|
|
456
|
+
appointment_validation_batches AppointmentValidationBatch[]
|
|
457
|
+
|
|
458
|
+
@@unique([phone_tenant_id, phone_number, phone_purpose])
|
|
459
|
+
@@index([phone_tenant_id, phone_purpose], name: "idx_phones_tenant_purpose")
|
|
460
|
+
@@index([phone_clinic_id], name: "idx_phones_clinic")
|
|
461
|
+
@@index([phone_provider, phone_external_account_id], name: "idx_phones_provider_external")
|
|
462
|
+
@@map("phone_numbers")
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// ─────────────────────────────────────────────
|
|
466
|
+
// 6. USERS
|
|
467
|
+
// ─────────────────────────────────────────────
|
|
468
|
+
|
|
469
|
+
model User {
|
|
470
|
+
user_id String @id @default(uuid())
|
|
471
|
+
user_tenant_id String?
|
|
472
|
+
user_email String @unique
|
|
473
|
+
user_password_hash String
|
|
474
|
+
user_role UserRole @default(receptionist)
|
|
475
|
+
user_first_name String
|
|
476
|
+
user_last_name String
|
|
477
|
+
user_phone String?
|
|
478
|
+
user_is_active Boolean @default(true)
|
|
479
|
+
user_custom_permissions Json @default("[]")
|
|
480
|
+
user_last_login_at DateTime?
|
|
481
|
+
user_created_at DateTime @default(now())
|
|
482
|
+
user_updated_at DateTime @updatedAt
|
|
483
|
+
|
|
484
|
+
// Relations
|
|
485
|
+
tenant Tenant? @relation(fields: [user_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
486
|
+
|
|
487
|
+
doctor_profile DoctorProfile?
|
|
488
|
+
clinic_assignments UserClinicAssignment[]
|
|
489
|
+
refresh_tokens RefreshToken[]
|
|
490
|
+
whatsapp_messages WhatsappMessage[]
|
|
491
|
+
sessions_taken_over WhatsappSession[] @relation("TakenOverBy")
|
|
492
|
+
chats_assigned_to WhatsappChat[] @relation("ChatAssignedTo")
|
|
493
|
+
chats_assigned_by WhatsappChat[] @relation("ChatAssignedBy")
|
|
494
|
+
availability_blocks AvailabilityBlock[] @relation("BlockDoctor")
|
|
495
|
+
blocks_created AvailabilityBlock[] @relation("BlockCreatedBy")
|
|
496
|
+
payments_recorded Payment[] @relation("RecordedBy")
|
|
497
|
+
batches_created AppointmentValidationBatch[] @relation("CreatedBy")
|
|
498
|
+
treatment_plans_as_doctor TreatmentPlan[] @relation("PlanDoctor")
|
|
499
|
+
patient_notes_authored PatientNote[] @relation("NoteAuthor")
|
|
500
|
+
patient_documents_uploaded PatientDocument[] @relation("DocUploader")
|
|
501
|
+
patient_photo_sets_taken PatientPhotoSet[] @relation("PhotoTaker")
|
|
502
|
+
examination_records ExaminationRecord[] @relation("ExamDoctor")
|
|
503
|
+
appointments_as_doctor Appointment[] @relation("AppointmentDoctor")
|
|
504
|
+
prompt_versions_changed AgentPromptVersion[]
|
|
505
|
+
admin_chat_sessions AdminChatSession[]
|
|
506
|
+
|
|
507
|
+
@@index([user_tenant_id], name: "idx_users_tenant")
|
|
508
|
+
@@map("users")
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// ─────────────────────────────────────────────
|
|
512
|
+
// 7. USER CLINIC ASSIGNMENTS
|
|
513
|
+
// ─────────────────────────────────────────────
|
|
514
|
+
|
|
515
|
+
model UserClinicAssignment {
|
|
516
|
+
assign_id String @id @default(uuid())
|
|
517
|
+
assign_user_id String
|
|
518
|
+
assign_clinic_id String
|
|
519
|
+
assign_created_at DateTime @default(now())
|
|
520
|
+
|
|
521
|
+
// Relations
|
|
522
|
+
user User @relation(fields: [assign_user_id], references: [user_id], onDelete: Cascade)
|
|
523
|
+
clinic Clinic @relation(fields: [assign_clinic_id], references: [clinic_id], onDelete: Cascade)
|
|
524
|
+
|
|
525
|
+
@@unique([assign_user_id, assign_clinic_id])
|
|
526
|
+
@@index([assign_user_id], name: "idx_assign_user")
|
|
527
|
+
@@index([assign_clinic_id], name: "idx_assign_clinic")
|
|
528
|
+
@@map("user_clinic_assignments")
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// ─────────────────────────────────────────────
|
|
532
|
+
// 8. REFRESH TOKENS
|
|
533
|
+
// ─────────────────────────────────────────────
|
|
534
|
+
|
|
535
|
+
model RefreshToken {
|
|
536
|
+
token_id String @id @default(uuid())
|
|
537
|
+
token_user_id String
|
|
538
|
+
token_value String @unique
|
|
539
|
+
token_expires_at DateTime
|
|
540
|
+
token_created_at DateTime @default(now())
|
|
541
|
+
|
|
542
|
+
// Relations
|
|
543
|
+
user User @relation(fields: [token_user_id], references: [user_id], onDelete: Cascade)
|
|
544
|
+
|
|
545
|
+
@@index([token_user_id], name: "idx_tokens_user")
|
|
546
|
+
@@index([token_expires_at], name: "idx_tokens_expires")
|
|
547
|
+
@@map("refresh_tokens")
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// ─────────────────────────────────────────────
|
|
551
|
+
// 9. PLANS
|
|
552
|
+
// ─────────────────────────────────────────────
|
|
553
|
+
|
|
554
|
+
model Plan {
|
|
555
|
+
plan_id String @id @default(uuid())
|
|
556
|
+
plan_name String
|
|
557
|
+
plan_slug String @unique
|
|
558
|
+
plan_price Decimal
|
|
559
|
+
plan_overage_rate Decimal
|
|
560
|
+
plan_included_inbound_minutes Int @default(0)
|
|
561
|
+
plan_included_inbound_calls Int @default(0)
|
|
562
|
+
plan_included_outbound_minutes Int @default(0)
|
|
563
|
+
plan_included_outbound_calls Int @default(0)
|
|
564
|
+
plan_included_wa_chats Int @default(0)
|
|
565
|
+
plan_is_active Boolean @default(true)
|
|
566
|
+
plan_sort_order Int @default(0)
|
|
567
|
+
plan_created_at DateTime @default(now())
|
|
568
|
+
plan_updated_at DateTime @updatedAt
|
|
569
|
+
|
|
570
|
+
// Relations
|
|
571
|
+
tenants Tenant[]
|
|
572
|
+
billing_period_snapshots BillingPeriodSnapshot[]
|
|
573
|
+
|
|
574
|
+
@@map("plans")
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// ─────────────────────────────────────────────
|
|
578
|
+
// 10. AGENTS
|
|
579
|
+
// ─────────────────────────────────────────────
|
|
580
|
+
|
|
581
|
+
model Agent {
|
|
582
|
+
agent_id String @id @default(uuid())
|
|
583
|
+
agent_tenant_id String?
|
|
584
|
+
agent_clinic_id String?
|
|
585
|
+
agent_elevenlabs_id String @default("")
|
|
586
|
+
agent_name String @default("")
|
|
587
|
+
agent_description String @default("")
|
|
588
|
+
agent_voice_id String @default("")
|
|
589
|
+
agent_language String @default("tr")
|
|
590
|
+
agent_greeting String @default("")
|
|
591
|
+
agent_system_prompt String @default("")
|
|
592
|
+
agent_ai_provider String? // "elevenlabs" | "anthropic" | "openai"
|
|
593
|
+
agent_ai_model String? // provider-specific model ID
|
|
594
|
+
agent_temperature Float @default(0.3)
|
|
595
|
+
agent_max_tokens Int @default(4096)
|
|
596
|
+
agent_post_call_strategy PostCallStrategy @default(summarize)
|
|
597
|
+
agent_post_call_wa_notify Boolean @default(true)
|
|
598
|
+
agent_post_call_sms_notify Boolean @default(false)
|
|
599
|
+
agent_summary_prompt String @default("")
|
|
600
|
+
agent_wa_message_template String @default("")
|
|
601
|
+
agent_enabled_tools String[] @default([]) // explicit tool whitelist (empty = all available)
|
|
602
|
+
agent_tags String[] @default([]) // free-form tags: ["receptionist", "sales", "appointment"]
|
|
603
|
+
agent_channels String[] @default([]) // channels: ["whatsapp", "instagram", "voice"] (empty = all)
|
|
604
|
+
agent_status String @default("draft") // "draft" | "testing" | "production" | "archived"
|
|
605
|
+
agent_metadata Json @default("{}") // free-form key-value pairs
|
|
606
|
+
agent_extra_config Json @default("{}")
|
|
607
|
+
agent_el_synced_at DateTime? // last ElevenLabs sync timestamp
|
|
608
|
+
agent_el_sync_error String? // last sync error message
|
|
609
|
+
agent_is_active Boolean @default(true)
|
|
610
|
+
agent_created_at DateTime @default(now())
|
|
611
|
+
agent_updated_at DateTime @updatedAt
|
|
612
|
+
|
|
613
|
+
// Relations
|
|
614
|
+
tenant Tenant? @relation(fields: [agent_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
615
|
+
clinic Clinic? @relation(fields: [agent_clinic_id], references: [clinic_id])
|
|
616
|
+
clinic_assignments AgentClinicAssignment[]
|
|
617
|
+
prompt_versions AgentPromptVersion[]
|
|
618
|
+
|
|
619
|
+
phone_numbers PhoneNumber[]
|
|
620
|
+
calls Call[]
|
|
621
|
+
outbound_campaigns OutboundCampaign[]
|
|
622
|
+
appointment_validation_batches AppointmentValidationBatch[]
|
|
623
|
+
|
|
624
|
+
@@index([agent_tenant_id], name: "idx_agents_tenant")
|
|
625
|
+
@@index([agent_clinic_id], name: "idx_agents_clinic")
|
|
626
|
+
@@index([agent_elevenlabs_id], name: "idx_agents_elevenlabs")
|
|
627
|
+
@@map("agents")
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
model AgentClinicAssignment {
|
|
631
|
+
aca_id String @id @default(uuid())
|
|
632
|
+
aca_agent_id String
|
|
633
|
+
aca_clinic_id String
|
|
634
|
+
aca_created_at DateTime @default(now())
|
|
635
|
+
|
|
636
|
+
agent Agent @relation(fields: [aca_agent_id], references: [agent_id], onDelete: Cascade)
|
|
637
|
+
clinic Clinic @relation(fields: [aca_clinic_id], references: [clinic_id], onDelete: Cascade)
|
|
638
|
+
|
|
639
|
+
@@unique([aca_agent_id, aca_clinic_id])
|
|
640
|
+
@@index([aca_clinic_id], name: "idx_aca_clinic")
|
|
641
|
+
@@map("agent_clinic_assignments")
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
model AgentPromptVersion {
|
|
645
|
+
pv_id String @id @default(uuid())
|
|
646
|
+
pv_agent_id String
|
|
647
|
+
pv_version Int
|
|
648
|
+
pv_prompt String // the full system prompt at this version
|
|
649
|
+
pv_change_note String @default("") // what changed and why
|
|
650
|
+
pv_changed_by String? // user ID who made the change
|
|
651
|
+
pv_created_at DateTime @default(now())
|
|
652
|
+
|
|
653
|
+
// Relations
|
|
654
|
+
agent Agent @relation(fields: [pv_agent_id], references: [agent_id], onDelete: Cascade)
|
|
655
|
+
changed_by User? @relation(fields: [pv_changed_by], references: [user_id])
|
|
656
|
+
|
|
657
|
+
@@unique([pv_agent_id, pv_version])
|
|
658
|
+
@@index([pv_agent_id, pv_created_at(sort: Desc)], name: "idx_prompt_versions_agent")
|
|
659
|
+
@@map("agent_prompt_versions")
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// ─────────────────────────────────────────────
|
|
663
|
+
// 11. CALLS
|
|
664
|
+
// ─────────────────────────────────────────────
|
|
665
|
+
|
|
666
|
+
model Call {
|
|
667
|
+
call_id String @id @default(uuid())
|
|
668
|
+
call_tenant_id String
|
|
669
|
+
call_clinic_id String
|
|
670
|
+
call_patient_id String?
|
|
671
|
+
call_agent_id String
|
|
672
|
+
call_campaign_id String?
|
|
673
|
+
call_conversation_id String?
|
|
674
|
+
call_direction CallDirection
|
|
675
|
+
call_caller_number String
|
|
676
|
+
call_callee_number String
|
|
677
|
+
call_duration_seconds Int @default(0)
|
|
678
|
+
call_start_time DateTime?
|
|
679
|
+
call_end_time DateTime?
|
|
680
|
+
call_termination_reason String?
|
|
681
|
+
call_cost Decimal?
|
|
682
|
+
call_language String?
|
|
683
|
+
call_elevenlabs_status String?
|
|
684
|
+
call_status CallStatus
|
|
685
|
+
call_sentiment Sentiment?
|
|
686
|
+
call_categories String[] @default([])
|
|
687
|
+
call_wa_notification_sent Boolean @default(false)
|
|
688
|
+
call_created_at DateTime @default(now())
|
|
689
|
+
call_updated_at DateTime @updatedAt
|
|
690
|
+
|
|
691
|
+
// Relations
|
|
692
|
+
tenant Tenant @relation(fields: [call_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
693
|
+
clinic Clinic @relation(fields: [call_clinic_id], references: [clinic_id])
|
|
694
|
+
patient Patient? @relation(fields: [call_patient_id], references: [patient_id])
|
|
695
|
+
agent Agent @relation(fields: [call_agent_id], references: [agent_id])
|
|
696
|
+
campaign OutboundCampaign? @relation(fields: [call_campaign_id], references: [campaign_id])
|
|
697
|
+
|
|
698
|
+
call_detail CallDetail?
|
|
699
|
+
billing_events BillingEvent[]
|
|
700
|
+
leads Lead[]
|
|
701
|
+
outbound_campaign_entries OutboundCampaignEntry[]
|
|
702
|
+
|
|
703
|
+
@@index([call_tenant_id, call_created_at(sort: Desc)], name: "idx_calls_tenant_date")
|
|
704
|
+
@@index([call_clinic_id, call_created_at(sort: Desc)], name: "idx_calls_clinic_date")
|
|
705
|
+
@@index([call_campaign_id, call_status], name: "idx_calls_campaign_status")
|
|
706
|
+
@@index([call_tenant_id, call_direction, call_created_at(sort: Desc)], name: "idx_calls_tenant_direction_date")
|
|
707
|
+
@@index([call_conversation_id], name: "idx_calls_conversation")
|
|
708
|
+
@@index([call_tenant_id, call_callee_number], name: "idx_calls_tenant_callee")
|
|
709
|
+
@@index([call_patient_id, call_created_at(sort: Desc)], name: "idx_calls_patient_date")
|
|
710
|
+
@@map("calls")
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// ─────────────────────────────────────────────
|
|
714
|
+
// 12. CALL DETAILS
|
|
715
|
+
// ─────────────────────────────────────────────
|
|
716
|
+
|
|
717
|
+
model CallDetail {
|
|
718
|
+
detail_id String @id @default(uuid())
|
|
719
|
+
detail_call_id String @unique
|
|
720
|
+
detail_transcript String @default("")
|
|
721
|
+
detail_llm_summary String?
|
|
722
|
+
detail_extracted_data Json?
|
|
723
|
+
detail_recording_url String?
|
|
724
|
+
detail_recording_key String?
|
|
725
|
+
detail_analysis Json?
|
|
726
|
+
detail_created_at DateTime @default(now())
|
|
727
|
+
detail_updated_at DateTime @updatedAt
|
|
728
|
+
|
|
729
|
+
// Relations
|
|
730
|
+
call Call @relation(fields: [detail_call_id], references: [call_id], onDelete: Cascade)
|
|
731
|
+
|
|
732
|
+
@@map("call_details")
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// ─────────────────────────────────────────────
|
|
736
|
+
// 13. LEADS
|
|
737
|
+
// ─────────────────────────────────────────────
|
|
738
|
+
|
|
739
|
+
model Lead {
|
|
740
|
+
lead_id String @id @default(uuid())
|
|
741
|
+
lead_tenant_id String
|
|
742
|
+
lead_clinic_id String
|
|
743
|
+
lead_patient_id String?
|
|
744
|
+
lead_call_id String?
|
|
745
|
+
lead_session_id String?
|
|
746
|
+
lead_chat_id String?
|
|
747
|
+
lead_name String?
|
|
748
|
+
lead_phone String
|
|
749
|
+
lead_service_of_interest String?
|
|
750
|
+
lead_status LeadStatus @default(new_lead)
|
|
751
|
+
lead_categories String[] @default([])
|
|
752
|
+
lead_summary String?
|
|
753
|
+
lead_created_at DateTime @default(now())
|
|
754
|
+
lead_updated_at DateTime @updatedAt
|
|
755
|
+
|
|
756
|
+
// Relations
|
|
757
|
+
tenant Tenant @relation(fields: [lead_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
758
|
+
clinic Clinic @relation(fields: [lead_clinic_id], references: [clinic_id])
|
|
759
|
+
patient Patient? @relation(fields: [lead_patient_id], references: [patient_id])
|
|
760
|
+
call Call? @relation(fields: [lead_call_id], references: [call_id])
|
|
761
|
+
session WhatsappSession? @relation(fields: [lead_session_id], references: [session_id])
|
|
762
|
+
chat WhatsappChat? @relation(fields: [lead_chat_id], references: [chat_id])
|
|
763
|
+
|
|
764
|
+
@@index([lead_tenant_id, lead_created_at(sort: Desc)], name: "idx_leads_tenant_date")
|
|
765
|
+
@@index([lead_tenant_id, lead_status], name: "idx_leads_tenant_status")
|
|
766
|
+
@@index([lead_call_id], name: "idx_leads_call")
|
|
767
|
+
@@index([lead_session_id], name: "idx_leads_session")
|
|
768
|
+
@@index([lead_patient_id], name: "idx_leads_patient")
|
|
769
|
+
@@map("leads")
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// ─────────────────────────────────────────────
|
|
773
|
+
// 14. OUTBOUND CAMPAIGNS
|
|
774
|
+
// ─────────────────────────────────────────────
|
|
775
|
+
|
|
776
|
+
model OutboundCampaign {
|
|
777
|
+
campaign_id String @id @default(uuid())
|
|
778
|
+
campaign_tenant_id String
|
|
779
|
+
campaign_clinic_id String
|
|
780
|
+
campaign_agent_id String
|
|
781
|
+
campaign_name String
|
|
782
|
+
campaign_description String @default("")
|
|
783
|
+
campaign_status OutboundCampaignStatus @default(draft)
|
|
784
|
+
campaign_agent_config Json @default("{}")
|
|
785
|
+
campaign_schedule Json
|
|
786
|
+
campaign_phone_id String?
|
|
787
|
+
campaign_stats Json @default("{}")
|
|
788
|
+
campaign_created_at DateTime @default(now())
|
|
789
|
+
campaign_updated_at DateTime @updatedAt
|
|
790
|
+
|
|
791
|
+
// Relations
|
|
792
|
+
tenant Tenant @relation(fields: [campaign_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
793
|
+
clinic Clinic @relation(fields: [campaign_clinic_id], references: [clinic_id])
|
|
794
|
+
agent Agent @relation(fields: [campaign_agent_id], references: [agent_id])
|
|
795
|
+
phone PhoneNumber? @relation(fields: [campaign_phone_id], references: [phone_id])
|
|
796
|
+
|
|
797
|
+
entries OutboundCampaignEntry[]
|
|
798
|
+
calls Call[]
|
|
799
|
+
|
|
800
|
+
@@index([campaign_tenant_id, campaign_status], name: "idx_campaigns_tenant_status")
|
|
801
|
+
@@index([campaign_clinic_id], name: "idx_campaigns_clinic")
|
|
802
|
+
@@map("outbound_campaigns")
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// ─────────────────────────────────────────────
|
|
806
|
+
// 15. OUTBOUND CAMPAIGN ENTRIES
|
|
807
|
+
// ─────────────────────────────────────────────
|
|
808
|
+
|
|
809
|
+
model OutboundCampaignEntry {
|
|
810
|
+
centry_id String @id @default(uuid())
|
|
811
|
+
centry_campaign_id String
|
|
812
|
+
centry_phone String
|
|
813
|
+
centry_contact_name String @default("")
|
|
814
|
+
centry_custom_data Json @default("{}")
|
|
815
|
+
centry_status CampaignEntryStatus @default(pending)
|
|
816
|
+
centry_attempts Int @default(0)
|
|
817
|
+
centry_max_attempts Int @default(3)
|
|
818
|
+
centry_last_attempt_at DateTime?
|
|
819
|
+
centry_conversation_id String?
|
|
820
|
+
centry_call_id String?
|
|
821
|
+
centry_call_duration_secs Int @default(0)
|
|
822
|
+
centry_extracted_data Json?
|
|
823
|
+
centry_summary String?
|
|
824
|
+
centry_called_at DateTime?
|
|
825
|
+
centry_completed_at DateTime?
|
|
826
|
+
centry_created_at DateTime @default(now())
|
|
827
|
+
centry_updated_at DateTime @updatedAt
|
|
828
|
+
|
|
829
|
+
// Relations
|
|
830
|
+
campaign OutboundCampaign @relation(fields: [centry_campaign_id], references: [campaign_id], onDelete: Cascade)
|
|
831
|
+
call Call? @relation(fields: [centry_call_id], references: [call_id])
|
|
832
|
+
|
|
833
|
+
@@index([centry_campaign_id, centry_status], name: "idx_centries_campaign_status")
|
|
834
|
+
@@index([centry_conversation_id], name: "idx_centries_conversation")
|
|
835
|
+
@@map("outbound_campaign_entries")
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// ─────────────────────────────────────────────
|
|
839
|
+
// 16. WHATSAPP CHATS
|
|
840
|
+
// ─────────────────────────────────────────────
|
|
841
|
+
|
|
842
|
+
model WhatsappChat {
|
|
843
|
+
chat_id String @id @default(uuid())
|
|
844
|
+
chat_tenant_id String
|
|
845
|
+
chat_clinic_id String
|
|
846
|
+
chat_patient_id String?
|
|
847
|
+
chat_channel ChatChannel @default(whatsapp)
|
|
848
|
+
chat_external_id String
|
|
849
|
+
chat_phone_id String?
|
|
850
|
+
chat_contact_name String @default("Bilinmiyor")
|
|
851
|
+
chat_contact_phone String @default("")
|
|
852
|
+
chat_is_closed Boolean @default(false)
|
|
853
|
+
chat_active_session_id String?
|
|
854
|
+
chat_last_message_at DateTime @default(now())
|
|
855
|
+
chat_last_message_preview String @default("")
|
|
856
|
+
chat_message_count Int @default(0)
|
|
857
|
+
chat_assigned_to_id String?
|
|
858
|
+
chat_assigned_by_id String?
|
|
859
|
+
chat_assigned_at DateTime?
|
|
860
|
+
chat_deleted_at DateTime?
|
|
861
|
+
chat_created_at DateTime @default(now())
|
|
862
|
+
chat_updated_at DateTime @updatedAt
|
|
863
|
+
|
|
864
|
+
// Relations
|
|
865
|
+
tenant Tenant @relation(fields: [chat_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
866
|
+
clinic Clinic @relation(fields: [chat_clinic_id], references: [clinic_id])
|
|
867
|
+
patient Patient? @relation(fields: [chat_patient_id], references: [patient_id])
|
|
868
|
+
phone PhoneNumber? @relation(fields: [chat_phone_id], references: [phone_id])
|
|
869
|
+
assigned_to User? @relation("ChatAssignedTo", fields: [chat_assigned_to_id], references: [user_id])
|
|
870
|
+
assigned_by User? @relation("ChatAssignedBy", fields: [chat_assigned_by_id], references: [user_id])
|
|
871
|
+
|
|
872
|
+
sessions WhatsappSession[]
|
|
873
|
+
messages WhatsappMessage[]
|
|
874
|
+
operator_requests OperatorRequest[]
|
|
875
|
+
appointments Appointment[]
|
|
876
|
+
leads Lead[]
|
|
877
|
+
|
|
878
|
+
@@unique([chat_tenant_id, chat_external_id])
|
|
879
|
+
@@index([chat_tenant_id, chat_clinic_id], name: "idx_chats_tenant_clinic")
|
|
880
|
+
@@index([chat_tenant_id, chat_last_message_at(sort: Desc)], name: "idx_chats_tenant_lastmsg")
|
|
881
|
+
@@index([chat_tenant_id, chat_contact_phone], name: "idx_chats_tenant_phone")
|
|
882
|
+
@@map("whatsapp_chats")
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// ─────────────────────────────────────────────
|
|
886
|
+
// 17. WHATSAPP SESSIONS
|
|
887
|
+
// ─────────────────────────────────────────────
|
|
888
|
+
|
|
889
|
+
model WhatsappSession {
|
|
890
|
+
session_id String @id @default(uuid())
|
|
891
|
+
session_chat_id String
|
|
892
|
+
session_tenant_id String
|
|
893
|
+
session_clinic_id String
|
|
894
|
+
session_status SessionStatus @default(waiting)
|
|
895
|
+
session_resolved_by SessionResolvedBy?
|
|
896
|
+
session_started_at DateTime @default(now())
|
|
897
|
+
session_resolved_at DateTime?
|
|
898
|
+
session_grace_deadline DateTime?
|
|
899
|
+
session_taken_over_by_id String?
|
|
900
|
+
session_taken_over_at DateTime?
|
|
901
|
+
session_el_conversation_id String?
|
|
902
|
+
session_el_prev_conversation_ids String[] @default([])
|
|
903
|
+
session_el_conversation_created DateTime?
|
|
904
|
+
session_el_last_interaction DateTime?
|
|
905
|
+
session_el_cost Decimal?
|
|
906
|
+
session_ref_code String?
|
|
907
|
+
session_awaiting_operator Boolean @default(false)
|
|
908
|
+
session_message_count Int @default(0)
|
|
909
|
+
session_llm_summary String?
|
|
910
|
+
session_sentiment Sentiment?
|
|
911
|
+
session_categories String[] @default([])
|
|
912
|
+
session_created_at DateTime @default(now())
|
|
913
|
+
session_updated_at DateTime @updatedAt
|
|
914
|
+
|
|
915
|
+
// Relations
|
|
916
|
+
tenant Tenant @relation(fields: [session_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
917
|
+
clinic Clinic @relation(fields: [session_clinic_id], references: [clinic_id])
|
|
918
|
+
chat WhatsappChat @relation(fields: [session_chat_id], references: [chat_id], onDelete: Cascade)
|
|
919
|
+
taken_over_by User? @relation("TakenOverBy", fields: [session_taken_over_by_id], references: [user_id])
|
|
920
|
+
|
|
921
|
+
messages WhatsappMessage[]
|
|
922
|
+
operator_requests OperatorRequest[]
|
|
923
|
+
appointments Appointment[]
|
|
924
|
+
leads Lead[]
|
|
925
|
+
|
|
926
|
+
@@index([session_chat_id, session_status], name: "idx_sessions_chat_status")
|
|
927
|
+
@@index([session_status, session_grace_deadline], name: "idx_sessions_status_grace")
|
|
928
|
+
@@index([session_tenant_id, session_status], name: "idx_sessions_tenant_status")
|
|
929
|
+
@@index([session_clinic_id, session_status], name: "idx_sessions_clinic_status")
|
|
930
|
+
@@index([session_status, session_updated_at], name: "idx_sessions_status_updated")
|
|
931
|
+
@@index([session_ref_code, session_tenant_id], name: "idx_sessions_ref_tenant")
|
|
932
|
+
@@map("whatsapp_sessions")
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// ─────────────────────────────────────────────
|
|
936
|
+
// 18. WHATSAPP MESSAGES
|
|
937
|
+
// ─────────────────────────────────────────────
|
|
938
|
+
|
|
939
|
+
model WhatsappMessage {
|
|
940
|
+
msg_id String @id @default(uuid())
|
|
941
|
+
msg_chat_id String
|
|
942
|
+
msg_session_id String?
|
|
943
|
+
msg_tenant_id String
|
|
944
|
+
msg_external_id String?
|
|
945
|
+
msg_sender MessageSender
|
|
946
|
+
msg_sender_name String @default("")
|
|
947
|
+
msg_sender_user_id String?
|
|
948
|
+
msg_text String
|
|
949
|
+
msg_media_type String?
|
|
950
|
+
msg_media_key String?
|
|
951
|
+
msg_media_url String?
|
|
952
|
+
msg_media_mime String?
|
|
953
|
+
msg_media_filename String?
|
|
954
|
+
msg_ad_context Json?
|
|
955
|
+
msg_metadata Json? // Structured data: location, contacts, reaction, button reply, etc.
|
|
956
|
+
msg_sent_via_bridge Boolean @default(false)
|
|
957
|
+
msg_quoted_text String?
|
|
958
|
+
msg_created_at DateTime @default(now())
|
|
959
|
+
|
|
960
|
+
// Relations
|
|
961
|
+
tenant Tenant @relation(fields: [msg_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
962
|
+
chat WhatsappChat @relation(fields: [msg_chat_id], references: [chat_id], onDelete: Cascade)
|
|
963
|
+
session WhatsappSession? @relation(fields: [msg_session_id], references: [session_id])
|
|
964
|
+
sender_user User? @relation(fields: [msg_sender_user_id], references: [user_id])
|
|
965
|
+
|
|
966
|
+
@@index([msg_chat_id, msg_created_at], name: "idx_msgs_chat_date")
|
|
967
|
+
@@index([msg_session_id, msg_created_at], name: "idx_msgs_session_date")
|
|
968
|
+
@@index([msg_tenant_id, msg_created_at(sort: Desc)], name: "idx_msgs_tenant_date")
|
|
969
|
+
@@map("whatsapp_messages")
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// ─────────────────────────────────────────────
|
|
973
|
+
// 20. OPERATOR REQUESTS
|
|
974
|
+
// ─────────────────────────────────────────────
|
|
975
|
+
|
|
976
|
+
model OperatorRequest {
|
|
977
|
+
opreq_id String @id @default(uuid())
|
|
978
|
+
opreq_tenant_id String
|
|
979
|
+
opreq_clinic_id String
|
|
980
|
+
opreq_session_id String
|
|
981
|
+
opreq_chat_id String
|
|
982
|
+
opreq_ref_code String
|
|
983
|
+
opreq_request_type String @default("general")
|
|
984
|
+
opreq_request_message String?
|
|
985
|
+
opreq_status OperatorRequestStatus @default(pending)
|
|
986
|
+
opreq_forwarded_media_types String[] @default([])
|
|
987
|
+
opreq_forwarded_count Int @default(0)
|
|
988
|
+
opreq_failed_count Int @default(0)
|
|
989
|
+
opreq_forwarded_at DateTime @default(now())
|
|
990
|
+
opreq_forwarded_to_phone String
|
|
991
|
+
opreq_operator_response String?
|
|
992
|
+
opreq_response_media_type String?
|
|
993
|
+
opreq_response_message_id String?
|
|
994
|
+
opreq_responded_at DateTime?
|
|
995
|
+
opreq_patient_message_ids String[] @default([])
|
|
996
|
+
opreq_expires_at DateTime
|
|
997
|
+
opreq_created_at DateTime @default(now())
|
|
998
|
+
opreq_updated_at DateTime @updatedAt
|
|
999
|
+
|
|
1000
|
+
// Relations
|
|
1001
|
+
tenant Tenant @relation(fields: [opreq_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1002
|
+
clinic Clinic @relation(fields: [opreq_clinic_id], references: [clinic_id])
|
|
1003
|
+
session WhatsappSession @relation(fields: [opreq_session_id], references: [session_id])
|
|
1004
|
+
chat WhatsappChat @relation(fields: [opreq_chat_id], references: [chat_id])
|
|
1005
|
+
|
|
1006
|
+
@@unique([opreq_tenant_id, opreq_ref_code])
|
|
1007
|
+
@@index([opreq_session_id, opreq_status], name: "idx_opreqs_session_status")
|
|
1008
|
+
@@index([opreq_status, opreq_expires_at], name: "idx_opreqs_status_expires")
|
|
1009
|
+
@@map("operator_requests")
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// ─────────────────────────────────────────────
|
|
1013
|
+
// 21. APPOINTMENTS
|
|
1014
|
+
// ─────────────────────────────────────────────
|
|
1015
|
+
|
|
1016
|
+
model Appointment {
|
|
1017
|
+
appt_id String @id @default(uuid())
|
|
1018
|
+
appt_tenant_id String
|
|
1019
|
+
appt_clinic_id String
|
|
1020
|
+
appt_patient_id String
|
|
1021
|
+
appt_doctor_id String?
|
|
1022
|
+
appt_treatment_id String?
|
|
1023
|
+
appt_treatment_plan_item_id String?
|
|
1024
|
+
appt_chat_id String?
|
|
1025
|
+
appt_session_id String?
|
|
1026
|
+
appt_google_event_id String?
|
|
1027
|
+
appt_patient_name String
|
|
1028
|
+
appt_patient_phone String
|
|
1029
|
+
appt_start_time DateTime
|
|
1030
|
+
appt_end_time DateTime
|
|
1031
|
+
appt_duration_minutes Int
|
|
1032
|
+
appt_type AppointmentType @default(appointment)
|
|
1033
|
+
appt_status AppointmentStatus @default(scheduled)
|
|
1034
|
+
appt_source AppointmentSource @default(dashboard)
|
|
1035
|
+
appt_notes String @default("")
|
|
1036
|
+
appt_conversation_id String?
|
|
1037
|
+
appt_reminder_sent_24h Boolean @default(false)
|
|
1038
|
+
appt_reminder_sent_2h Boolean @default(false)
|
|
1039
|
+
appt_cancelled_at DateTime?
|
|
1040
|
+
appt_completed_at DateTime?
|
|
1041
|
+
appt_created_at DateTime @default(now())
|
|
1042
|
+
appt_updated_at DateTime @updatedAt
|
|
1043
|
+
|
|
1044
|
+
// Relations
|
|
1045
|
+
tenant Tenant @relation(fields: [appt_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1046
|
+
clinic Clinic @relation(fields: [appt_clinic_id], references: [clinic_id])
|
|
1047
|
+
patient Patient @relation(fields: [appt_patient_id], references: [patient_id])
|
|
1048
|
+
doctor User? @relation("AppointmentDoctor", fields: [appt_doctor_id], references: [user_id])
|
|
1049
|
+
treatment Treatment? @relation(fields: [appt_treatment_id], references: [treatment_id])
|
|
1050
|
+
treatment_plan_item TreatmentPlanItem? @relation("AppointmentPlanItem", fields: [appt_treatment_plan_item_id], references: [tpitem_id])
|
|
1051
|
+
chat WhatsappChat? @relation(fields: [appt_chat_id], references: [chat_id])
|
|
1052
|
+
session WhatsappSession? @relation(fields: [appt_session_id], references: [session_id])
|
|
1053
|
+
|
|
1054
|
+
examination_record ExaminationRecord?
|
|
1055
|
+
treatment_plan_items_linked TreatmentPlanItem[] @relation("ItemAppointment")
|
|
1056
|
+
appointment_validation_entries AppointmentValidationEntry[]
|
|
1057
|
+
patient_documents PatientDocument[]
|
|
1058
|
+
|
|
1059
|
+
@@index([appt_tenant_id, appt_start_time], name: "idx_appts_tenant_start")
|
|
1060
|
+
@@index([appt_clinic_id, appt_start_time], name: "idx_appts_clinic_start")
|
|
1061
|
+
@@index([appt_patient_id, appt_start_time], name: "idx_appts_patient_start")
|
|
1062
|
+
@@index([appt_doctor_id, appt_start_time], name: "idx_appts_doctor_start")
|
|
1063
|
+
@@index([appt_tenant_id, appt_status], name: "idx_appts_tenant_status")
|
|
1064
|
+
@@index([appt_google_event_id], name: "idx_appts_google_event")
|
|
1065
|
+
@@map("appointments")
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// ─────────────────────────────────────────────
|
|
1069
|
+
// 22. APPOINTMENT VALIDATION BATCHES
|
|
1070
|
+
// ─────────────────────────────────────────────
|
|
1071
|
+
|
|
1072
|
+
model AppointmentValidationBatch {
|
|
1073
|
+
batch_id String @id @default(uuid())
|
|
1074
|
+
batch_tenant_id String
|
|
1075
|
+
batch_clinic_id String
|
|
1076
|
+
batch_created_by_id String
|
|
1077
|
+
batch_name String
|
|
1078
|
+
batch_status BatchStatus @default(draft)
|
|
1079
|
+
batch_el_batch_id String?
|
|
1080
|
+
batch_agent_id String?
|
|
1081
|
+
batch_phone_id String?
|
|
1082
|
+
batch_column_mapping Json
|
|
1083
|
+
batch_call_schedule Json
|
|
1084
|
+
batch_stats Json @default("{}")
|
|
1085
|
+
batch_created_at DateTime @default(now())
|
|
1086
|
+
batch_updated_at DateTime @updatedAt
|
|
1087
|
+
|
|
1088
|
+
// Relations
|
|
1089
|
+
tenant Tenant @relation(fields: [batch_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1090
|
+
clinic Clinic @relation(fields: [batch_clinic_id], references: [clinic_id])
|
|
1091
|
+
created_by User @relation("CreatedBy", fields: [batch_created_by_id], references: [user_id])
|
|
1092
|
+
agent Agent? @relation(fields: [batch_agent_id], references: [agent_id])
|
|
1093
|
+
phone PhoneNumber? @relation(fields: [batch_phone_id], references: [phone_id])
|
|
1094
|
+
|
|
1095
|
+
entries AppointmentValidationEntry[]
|
|
1096
|
+
|
|
1097
|
+
@@index([batch_tenant_id, batch_created_at(sort: Desc)], name: "idx_batches_tenant_date")
|
|
1098
|
+
@@index([batch_el_batch_id], name: "idx_batches_el")
|
|
1099
|
+
@@index([batch_clinic_id], name: "idx_batches_clinic")
|
|
1100
|
+
@@map("appointment_validation_batches")
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// ─────────────────────────────────────────────
|
|
1104
|
+
// 23. APPOINTMENT VALIDATION ENTRIES
|
|
1105
|
+
// ─────────────────────────────────────────────
|
|
1106
|
+
|
|
1107
|
+
model AppointmentValidationEntry {
|
|
1108
|
+
bentry_id String @id @default(uuid())
|
|
1109
|
+
bentry_batch_id String
|
|
1110
|
+
bentry_appointment_id String?
|
|
1111
|
+
bentry_row_index Int
|
|
1112
|
+
bentry_external_id String @default("")
|
|
1113
|
+
bentry_patient_name String
|
|
1114
|
+
bentry_patient_phone String
|
|
1115
|
+
bentry_appointment_date String
|
|
1116
|
+
bentry_appointment_time String
|
|
1117
|
+
bentry_doctor_name String @default("")
|
|
1118
|
+
bentry_department String @default("")
|
|
1119
|
+
bentry_notes String @default("")
|
|
1120
|
+
bentry_raw_data Json @default("{}")
|
|
1121
|
+
bentry_call_status EntryCallStatus @default(pending)
|
|
1122
|
+
bentry_attempts Int @default(0)
|
|
1123
|
+
bentry_conversation_id String?
|
|
1124
|
+
bentry_validation_result ValidationResult?
|
|
1125
|
+
bentry_reschedule_request String?
|
|
1126
|
+
bentry_patient_message String?
|
|
1127
|
+
bentry_call_duration_secs Int @default(0)
|
|
1128
|
+
bentry_called_at DateTime?
|
|
1129
|
+
bentry_result_at DateTime?
|
|
1130
|
+
bentry_created_at DateTime @default(now())
|
|
1131
|
+
bentry_updated_at DateTime @updatedAt
|
|
1132
|
+
|
|
1133
|
+
// Relations
|
|
1134
|
+
batch AppointmentValidationBatch @relation(fields: [bentry_batch_id], references: [batch_id], onDelete: Cascade)
|
|
1135
|
+
appointment Appointment? @relation(fields: [bentry_appointment_id], references: [appt_id])
|
|
1136
|
+
|
|
1137
|
+
@@index([bentry_batch_id, bentry_call_status], name: "idx_bentries_batch_status")
|
|
1138
|
+
@@index([bentry_conversation_id], name: "idx_bentries_conversation")
|
|
1139
|
+
@@map("appointment_validation_entries")
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// ─────────────────────────────────────────────
|
|
1143
|
+
// 24. BILLING EVENTS
|
|
1144
|
+
// ─────────────────────────────────────────────
|
|
1145
|
+
|
|
1146
|
+
model BillingEvent {
|
|
1147
|
+
billing_id String @id @default(uuid())
|
|
1148
|
+
billing_tenant_id String
|
|
1149
|
+
billing_clinic_id String?
|
|
1150
|
+
billing_type BillingEventType
|
|
1151
|
+
billing_amount Decimal
|
|
1152
|
+
billing_currency String @default("TRY")
|
|
1153
|
+
billing_call_id String?
|
|
1154
|
+
billing_description String @default("")
|
|
1155
|
+
billing_created_at DateTime @default(now())
|
|
1156
|
+
|
|
1157
|
+
// Relations
|
|
1158
|
+
tenant Tenant @relation(fields: [billing_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1159
|
+
clinic Clinic? @relation(fields: [billing_clinic_id], references: [clinic_id])
|
|
1160
|
+
call Call? @relation(fields: [billing_call_id], references: [call_id])
|
|
1161
|
+
|
|
1162
|
+
@@index([billing_tenant_id, billing_created_at(sort: Desc)], name: "idx_billing_tenant_date")
|
|
1163
|
+
@@map("billing_events")
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// ─────────────────────────────────────────────
|
|
1167
|
+
// 25. PAYMENTS
|
|
1168
|
+
// ─────────────────────────────────────────────
|
|
1169
|
+
|
|
1170
|
+
model Payment {
|
|
1171
|
+
payment_id String @id @default(uuid())
|
|
1172
|
+
payment_tenant_id String
|
|
1173
|
+
payment_type PaymentType @default(subscription)
|
|
1174
|
+
payment_plan_slug String
|
|
1175
|
+
payment_plan_name String
|
|
1176
|
+
payment_amount Decimal
|
|
1177
|
+
payment_extra_minutes Int @default(0)
|
|
1178
|
+
payment_period_start DateTime
|
|
1179
|
+
payment_period_end DateTime
|
|
1180
|
+
payment_method PaymentMethod @default(cash)
|
|
1181
|
+
payment_notes String @default("")
|
|
1182
|
+
payment_recorded_by_id String
|
|
1183
|
+
payment_created_at DateTime @default(now())
|
|
1184
|
+
payment_updated_at DateTime @updatedAt
|
|
1185
|
+
|
|
1186
|
+
// Relations
|
|
1187
|
+
tenant Tenant @relation(fields: [payment_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1188
|
+
recorded_by User @relation("RecordedBy", fields: [payment_recorded_by_id], references: [user_id])
|
|
1189
|
+
|
|
1190
|
+
billing_period_snapshots BillingPeriodSnapshot[]
|
|
1191
|
+
billing_alerts BillingAlert[]
|
|
1192
|
+
|
|
1193
|
+
@@index([payment_tenant_id], name: "idx_payments_tenant")
|
|
1194
|
+
@@index([payment_tenant_id, payment_period_end(sort: Desc)], name: "idx_payments_tenant_period")
|
|
1195
|
+
@@map("payments")
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// ─────────────────────────────────────────────
|
|
1199
|
+
// 26. BILLING PERIOD SNAPSHOTS
|
|
1200
|
+
// ─────────────────────────────────────────────
|
|
1201
|
+
|
|
1202
|
+
model BillingPeriodSnapshot {
|
|
1203
|
+
snapshot_id String @id @default(uuid())
|
|
1204
|
+
snapshot_tenant_id String
|
|
1205
|
+
snapshot_payment_id String
|
|
1206
|
+
snapshot_plan_id String?
|
|
1207
|
+
snapshot_period_start DateTime
|
|
1208
|
+
snapshot_period_end DateTime
|
|
1209
|
+
snapshot_total_calls Int @default(0)
|
|
1210
|
+
snapshot_inbound_calls Int @default(0)
|
|
1211
|
+
snapshot_inbound_minutes Decimal @default(0)
|
|
1212
|
+
snapshot_outbound_calls Int @default(0)
|
|
1213
|
+
snapshot_outbound_minutes Decimal @default(0)
|
|
1214
|
+
snapshot_total_charges Decimal @default(0)
|
|
1215
|
+
snapshot_wa_billable_chats Int @default(0)
|
|
1216
|
+
snapshot_wa_total_sessions Int @default(0)
|
|
1217
|
+
snapshot_wa_total_messages Int @default(0)
|
|
1218
|
+
snapshot_wa_ai_messages Int @default(0)
|
|
1219
|
+
snapshot_wa_el_cost Decimal @default(0)
|
|
1220
|
+
snapshot_wa_stt_count Int @default(0)
|
|
1221
|
+
snapshot_wa_stt_seconds Decimal @default(0)
|
|
1222
|
+
snapshot_created_at DateTime @default(now())
|
|
1223
|
+
|
|
1224
|
+
// Relations
|
|
1225
|
+
tenant Tenant @relation(fields: [snapshot_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1226
|
+
payment Payment @relation(fields: [snapshot_payment_id], references: [payment_id])
|
|
1227
|
+
plan Plan? @relation(fields: [snapshot_plan_id], references: [plan_id])
|
|
1228
|
+
|
|
1229
|
+
@@index([snapshot_tenant_id, snapshot_period_start(sort: Desc)], name: "idx_snapshots_tenant_period")
|
|
1230
|
+
@@map("billing_period_snapshots")
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// ─────────────────────────────────────────────
|
|
1234
|
+
// 27. BILLING ALERTS
|
|
1235
|
+
// ─────────────────────────────────────────────
|
|
1236
|
+
|
|
1237
|
+
model BillingAlert {
|
|
1238
|
+
alert_id String @id @default(uuid())
|
|
1239
|
+
alert_tenant_id String
|
|
1240
|
+
alert_type AlertType
|
|
1241
|
+
alert_service AlertService
|
|
1242
|
+
alert_payment_id String
|
|
1243
|
+
alert_created_at DateTime @default(now())
|
|
1244
|
+
|
|
1245
|
+
// Relations
|
|
1246
|
+
tenant Tenant @relation(fields: [alert_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1247
|
+
payment Payment @relation(fields: [alert_payment_id], references: [payment_id])
|
|
1248
|
+
|
|
1249
|
+
@@unique([alert_tenant_id, alert_type, alert_service, alert_payment_id])
|
|
1250
|
+
@@map("billing_alerts")
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// ─────────────────────────────────────────────
|
|
1254
|
+
// 28. STT USAGES
|
|
1255
|
+
// ─────────────────────────────────────────────
|
|
1256
|
+
|
|
1257
|
+
model SttUsage {
|
|
1258
|
+
stt_id String @id @default(uuid())
|
|
1259
|
+
stt_tenant_id String
|
|
1260
|
+
stt_clinic_id String?
|
|
1261
|
+
stt_chat_id String @default("")
|
|
1262
|
+
stt_message_id String @default("")
|
|
1263
|
+
stt_duration_seconds Decimal
|
|
1264
|
+
stt_character_count Int
|
|
1265
|
+
stt_language String @default("tr")
|
|
1266
|
+
stt_created_at DateTime @default(now())
|
|
1267
|
+
|
|
1268
|
+
// Relations
|
|
1269
|
+
tenant Tenant @relation(fields: [stt_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1270
|
+
clinic Clinic? @relation(fields: [stt_clinic_id], references: [clinic_id])
|
|
1271
|
+
|
|
1272
|
+
@@index([stt_tenant_id, stt_created_at(sort: Desc)], name: "idx_stt_tenant_date")
|
|
1273
|
+
@@map("stt_usages")
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// ─────────────────────────────────────────────
|
|
1277
|
+
// 29. LOGS (observability — no FKs)
|
|
1278
|
+
// ─────────────────────────────────────────────
|
|
1279
|
+
|
|
1280
|
+
model Log {
|
|
1281
|
+
log_id String @id @default(uuid())
|
|
1282
|
+
log_level String
|
|
1283
|
+
log_message String
|
|
1284
|
+
log_service String @default("api")
|
|
1285
|
+
log_meta Json @default("{}")
|
|
1286
|
+
log_request_id String?
|
|
1287
|
+
log_tenant_id String?
|
|
1288
|
+
log_clinic_id String?
|
|
1289
|
+
log_user_id String?
|
|
1290
|
+
log_timestamp DateTime @default(now())
|
|
1291
|
+
|
|
1292
|
+
@@index([log_level], name: "idx_logs_level")
|
|
1293
|
+
@@index([log_timestamp], name: "idx_logs_timestamp")
|
|
1294
|
+
@@index([log_level, log_timestamp(sort: Desc)], name: "idx_logs_level_timestamp")
|
|
1295
|
+
@@index([log_tenant_id, log_timestamp(sort: Desc)], name: "idx_logs_tenant_timestamp")
|
|
1296
|
+
@@index([log_request_id], name: "idx_logs_request")
|
|
1297
|
+
@@index([log_service, log_timestamp(sort: Desc)], name: "idx_logs_service_timestamp")
|
|
1298
|
+
@@map("logs")
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// ─────────────────────────────────────────────
|
|
1302
|
+
// 30. AUDIT LOGS (observability — no FKs)
|
|
1303
|
+
// ─────────────────────────────────────────────
|
|
1304
|
+
|
|
1305
|
+
model AuditLog {
|
|
1306
|
+
audit_id String @id @default(uuid())
|
|
1307
|
+
audit_tenant_id String?
|
|
1308
|
+
audit_clinic_id String?
|
|
1309
|
+
audit_user_id String?
|
|
1310
|
+
audit_user_email String?
|
|
1311
|
+
audit_user_role String?
|
|
1312
|
+
audit_action String
|
|
1313
|
+
audit_entity String
|
|
1314
|
+
audit_entity_id String
|
|
1315
|
+
audit_changes Json?
|
|
1316
|
+
audit_metadata Json?
|
|
1317
|
+
audit_created_at DateTime @default(now())
|
|
1318
|
+
|
|
1319
|
+
@@index([audit_tenant_id, audit_created_at(sort: Desc)], name: "idx_audit_tenant_date")
|
|
1320
|
+
@@index([audit_clinic_id, audit_created_at(sort: Desc)], name: "idx_audit_clinic_date")
|
|
1321
|
+
@@index([audit_entity, audit_entity_id], name: "idx_audit_entity")
|
|
1322
|
+
@@index([audit_user_id, audit_created_at(sort: Desc)], name: "idx_audit_user_date")
|
|
1323
|
+
@@index([audit_action, audit_created_at(sort: Desc)], name: "idx_audit_action_date")
|
|
1324
|
+
@@map("audit_logs")
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// ─────────────────────────────────────────────
|
|
1328
|
+
// 31. TOOL EXECUTION LOGS (observability — no FKs)
|
|
1329
|
+
// ─────────────────────────────────────────────
|
|
1330
|
+
|
|
1331
|
+
model ToolExecutionLog {
|
|
1332
|
+
toollog_id String @id @default(uuid())
|
|
1333
|
+
toollog_tenant_id String
|
|
1334
|
+
toollog_clinic_id String?
|
|
1335
|
+
toollog_tool_name String
|
|
1336
|
+
toollog_channel String
|
|
1337
|
+
toollog_patient_phone String @default("")
|
|
1338
|
+
toollog_conversation_id String?
|
|
1339
|
+
toollog_parameters Json @default("{}")
|
|
1340
|
+
toollog_result Json @default("{}")
|
|
1341
|
+
toollog_is_error Boolean @default(false)
|
|
1342
|
+
toollog_duration_ms Int @default(0)
|
|
1343
|
+
toollog_created_at DateTime @default(now())
|
|
1344
|
+
|
|
1345
|
+
@@index([toollog_tenant_id, toollog_created_at(sort: Desc)], name: "idx_toollog_tenant_date")
|
|
1346
|
+
@@index([toollog_tool_name, toollog_created_at(sort: Desc)], name: "idx_toollog_tool_date")
|
|
1347
|
+
@@index([toollog_conversation_id], name: "idx_toollog_conversation")
|
|
1348
|
+
@@map("tool_execution_logs")
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// ─────────────────────────────────────────────
|
|
1352
|
+
// 32. MIGRATIONS
|
|
1353
|
+
// ─────────────────────────────────────────────
|
|
1354
|
+
|
|
1355
|
+
model Migration {
|
|
1356
|
+
migration_id String @id @default(uuid())
|
|
1357
|
+
migration_name String @unique
|
|
1358
|
+
migration_ran_at DateTime
|
|
1359
|
+
migration_duration_ms Int
|
|
1360
|
+
migration_status MigrationStatus
|
|
1361
|
+
migration_error String?
|
|
1362
|
+
migration_created_at DateTime @default(now())
|
|
1363
|
+
migration_updated_at DateTime @updatedAt
|
|
1364
|
+
|
|
1365
|
+
@@map("migrations")
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
// ─────────────────────────────────────────────
|
|
1369
|
+
// 33. TRANSCRIPTIONS
|
|
1370
|
+
// ─────────────────────────────────────────────
|
|
1371
|
+
|
|
1372
|
+
model Transcription {
|
|
1373
|
+
tx_id String @id @default(uuid())
|
|
1374
|
+
tx_conversation_id String @unique
|
|
1375
|
+
tx_agent_id String
|
|
1376
|
+
tx_agent_name String?
|
|
1377
|
+
tx_user_id String?
|
|
1378
|
+
tx_event_type String @default("post_call_transcription")
|
|
1379
|
+
tx_event_timestamp Int?
|
|
1380
|
+
tx_status String @default("done")
|
|
1381
|
+
tx_transcript Json @default("[]")
|
|
1382
|
+
tx_metadata Json?
|
|
1383
|
+
tx_analysis Json?
|
|
1384
|
+
tx_processing_status TranscriptionProcessingStatus @default(pending)
|
|
1385
|
+
tx_processing_error String?
|
|
1386
|
+
tx_raw_payload Json?
|
|
1387
|
+
tx_created_at DateTime @default(now())
|
|
1388
|
+
tx_updated_at DateTime @updatedAt
|
|
1389
|
+
|
|
1390
|
+
// Relations
|
|
1391
|
+
summary Summary?
|
|
1392
|
+
|
|
1393
|
+
@@index([tx_agent_id], name: "idx_tx_agent")
|
|
1394
|
+
@@index([tx_user_id], name: "idx_tx_user")
|
|
1395
|
+
@@index([tx_processing_status], name: "idx_tx_processing")
|
|
1396
|
+
@@index([tx_created_at(sort: Desc)], name: "idx_tx_date")
|
|
1397
|
+
@@map("transcriptions")
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// ─────────────────────────────────────────────
|
|
1401
|
+
// 34. SUMMARIES
|
|
1402
|
+
// ─────────────────────────────────────────────
|
|
1403
|
+
|
|
1404
|
+
model Summary {
|
|
1405
|
+
summary_id String @id @default(uuid())
|
|
1406
|
+
summary_transcription_id String @unique
|
|
1407
|
+
summary_conversation_id String
|
|
1408
|
+
summary_text String
|
|
1409
|
+
summary_title String?
|
|
1410
|
+
summary_key_points String[] @default([])
|
|
1411
|
+
summary_detected_intent String?
|
|
1412
|
+
summary_sentiment Sentiment?
|
|
1413
|
+
summary_ai_provider String
|
|
1414
|
+
summary_ai_model String?
|
|
1415
|
+
summary_token_usage Json?
|
|
1416
|
+
summary_notification_status NotificationDeliveryStatus @default(pending)
|
|
1417
|
+
summary_notified_recipients Json @default("[]")
|
|
1418
|
+
summary_language String @default("tr")
|
|
1419
|
+
summary_created_at DateTime @default(now())
|
|
1420
|
+
summary_updated_at DateTime @updatedAt
|
|
1421
|
+
|
|
1422
|
+
// Relations
|
|
1423
|
+
transcription Transcription @relation(fields: [summary_transcription_id], references: [tx_id])
|
|
1424
|
+
|
|
1425
|
+
@@index([summary_conversation_id], name: "idx_summary_conversation")
|
|
1426
|
+
@@map("summaries")
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
// ─────────────────────────────────────────────
|
|
1430
|
+
// 36. PATIENTS
|
|
1431
|
+
// ─────────────────────────────────────────────
|
|
1432
|
+
|
|
1433
|
+
model Patient {
|
|
1434
|
+
patient_id String @id @default(uuid())
|
|
1435
|
+
patient_tenant_id String
|
|
1436
|
+
patient_clinic_id String?
|
|
1437
|
+
patient_phone String
|
|
1438
|
+
patient_email String?
|
|
1439
|
+
patient_first_name String @default("")
|
|
1440
|
+
patient_last_name String @default("")
|
|
1441
|
+
patient_display_name String @default("")
|
|
1442
|
+
patient_date_of_birth DateTime?
|
|
1443
|
+
patient_gender String?
|
|
1444
|
+
patient_id_number String?
|
|
1445
|
+
patient_blood_type String?
|
|
1446
|
+
patient_preferred_language String @default("tr")
|
|
1447
|
+
patient_source String?
|
|
1448
|
+
patient_source_detail String?
|
|
1449
|
+
patient_tags String[] @default([])
|
|
1450
|
+
patient_ai_summary String @default("")
|
|
1451
|
+
patient_is_active Boolean @default(true)
|
|
1452
|
+
patient_first_contact_at DateTime @default(now())
|
|
1453
|
+
patient_last_contact_at DateTime @default(now())
|
|
1454
|
+
patient_total_sessions Int @default(0)
|
|
1455
|
+
patient_total_appointments Int @default(0)
|
|
1456
|
+
patient_created_at DateTime @default(now())
|
|
1457
|
+
patient_updated_at DateTime @updatedAt
|
|
1458
|
+
|
|
1459
|
+
// Relations
|
|
1460
|
+
tenant Tenant @relation(fields: [patient_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1461
|
+
clinic Clinic? @relation(fields: [patient_clinic_id], references: [clinic_id])
|
|
1462
|
+
|
|
1463
|
+
medical_history PatientMedicalHistory?
|
|
1464
|
+
treatment_plans TreatmentPlan[]
|
|
1465
|
+
appointments Appointment[]
|
|
1466
|
+
photo_sets PatientPhotoSet[]
|
|
1467
|
+
documents PatientDocument[]
|
|
1468
|
+
notes PatientNote[]
|
|
1469
|
+
whatsapp_chats WhatsappChat[]
|
|
1470
|
+
leads Lead[]
|
|
1471
|
+
calls Call[]
|
|
1472
|
+
examination_records ExaminationRecord[]
|
|
1473
|
+
|
|
1474
|
+
@@unique([patient_tenant_id, patient_phone])
|
|
1475
|
+
@@index([patient_tenant_id, patient_last_contact_at(sort: Desc)], name: "idx_patients_tenant_lastcontact")
|
|
1476
|
+
@@index([patient_clinic_id], name: "idx_patients_clinic")
|
|
1477
|
+
@@index([patient_tenant_id, patient_last_name, patient_first_name], name: "idx_patients_tenant_name")
|
|
1478
|
+
@@map("patients")
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// ─────────────────────────────────────────────
|
|
1482
|
+
// 37. PATIENT MEDICAL HISTORIES
|
|
1483
|
+
// ─────────────────────────────────────────────
|
|
1484
|
+
|
|
1485
|
+
model PatientMedicalHistory {
|
|
1486
|
+
history_id String @id @default(uuid())
|
|
1487
|
+
history_patient_id String @unique
|
|
1488
|
+
history_allergies String @default("")
|
|
1489
|
+
history_chronic_conditions String @default("")
|
|
1490
|
+
history_current_medications String @default("")
|
|
1491
|
+
history_past_surgeries String @default("")
|
|
1492
|
+
history_pregnancy_status String?
|
|
1493
|
+
history_smoking Boolean?
|
|
1494
|
+
history_alcohol Boolean?
|
|
1495
|
+
history_notes String @default("")
|
|
1496
|
+
history_anamnesis_completed Boolean @default(false)
|
|
1497
|
+
history_anamnesis_date DateTime?
|
|
1498
|
+
history_created_at DateTime @default(now())
|
|
1499
|
+
history_updated_at DateTime @updatedAt
|
|
1500
|
+
|
|
1501
|
+
// Relations
|
|
1502
|
+
patient Patient @relation(fields: [history_patient_id], references: [patient_id], onDelete: Cascade)
|
|
1503
|
+
|
|
1504
|
+
@@map("patient_medical_histories")
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// ─────────────────────────────────────────────
|
|
1508
|
+
// 38. PATIENT DOCUMENTS
|
|
1509
|
+
// ─────────────────────────────────────────────
|
|
1510
|
+
|
|
1511
|
+
model PatientDocument {
|
|
1512
|
+
doc_id String @id @default(uuid())
|
|
1513
|
+
doc_patient_id String
|
|
1514
|
+
doc_tenant_id String
|
|
1515
|
+
doc_clinic_id String
|
|
1516
|
+
doc_appointment_id String?
|
|
1517
|
+
doc_type String @default("other")
|
|
1518
|
+
doc_name String
|
|
1519
|
+
doc_media_key String
|
|
1520
|
+
doc_content_type String
|
|
1521
|
+
doc_size_bytes Int @default(0)
|
|
1522
|
+
doc_uploaded_by String?
|
|
1523
|
+
doc_notes String @default("")
|
|
1524
|
+
doc_created_at DateTime @default(now())
|
|
1525
|
+
|
|
1526
|
+
// Relations
|
|
1527
|
+
patient Patient @relation(fields: [doc_patient_id], references: [patient_id], onDelete: Cascade)
|
|
1528
|
+
tenant Tenant @relation(fields: [doc_tenant_id], references: [tenant_id])
|
|
1529
|
+
clinic Clinic @relation(fields: [doc_clinic_id], references: [clinic_id])
|
|
1530
|
+
appointment Appointment? @relation(fields: [doc_appointment_id], references: [appt_id])
|
|
1531
|
+
uploaded_by_user User? @relation("DocUploader", fields: [doc_uploaded_by], references: [user_id])
|
|
1532
|
+
|
|
1533
|
+
@@index([doc_patient_id, doc_created_at(sort: Desc)], name: "idx_docs_patient_date")
|
|
1534
|
+
@@index([doc_tenant_id, doc_type], name: "idx_docs_tenant_type")
|
|
1535
|
+
@@map("patient_documents")
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
// ─────────────────────────────────────────────
|
|
1539
|
+
// 39. PATIENT NOTES
|
|
1540
|
+
// ─────────────────────────────────────────────
|
|
1541
|
+
|
|
1542
|
+
model PatientNote {
|
|
1543
|
+
note_id String @id @default(uuid())
|
|
1544
|
+
note_patient_id String
|
|
1545
|
+
note_tenant_id String
|
|
1546
|
+
note_clinic_id String
|
|
1547
|
+
note_author_id String
|
|
1548
|
+
note_text String
|
|
1549
|
+
note_is_pinned Boolean @default(false)
|
|
1550
|
+
note_created_at DateTime @default(now())
|
|
1551
|
+
note_updated_at DateTime @updatedAt
|
|
1552
|
+
|
|
1553
|
+
// Relations
|
|
1554
|
+
patient Patient @relation(fields: [note_patient_id], references: [patient_id], onDelete: Cascade)
|
|
1555
|
+
tenant Tenant @relation(fields: [note_tenant_id], references: [tenant_id])
|
|
1556
|
+
clinic Clinic @relation(fields: [note_clinic_id], references: [clinic_id])
|
|
1557
|
+
author User @relation("NoteAuthor", fields: [note_author_id], references: [user_id])
|
|
1558
|
+
|
|
1559
|
+
@@index([note_patient_id, note_created_at(sort: Desc)], name: "idx_notes_patient_date")
|
|
1560
|
+
@@map("patient_notes")
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// ─────────────────────────────────────────────
|
|
1564
|
+
// 40. TREATMENTS
|
|
1565
|
+
// ─────────────────────────────────────────────
|
|
1566
|
+
|
|
1567
|
+
model Treatment {
|
|
1568
|
+
treatment_id String @id @default(uuid())
|
|
1569
|
+
treatment_tenant_id String
|
|
1570
|
+
treatment_clinic_id String?
|
|
1571
|
+
treatment_name String
|
|
1572
|
+
treatment_category String @default("")
|
|
1573
|
+
treatment_description String @default("")
|
|
1574
|
+
treatment_duration_minutes Int @default(30)
|
|
1575
|
+
treatment_price Decimal?
|
|
1576
|
+
treatment_currency String @default("TRY")
|
|
1577
|
+
treatment_is_active Boolean @default(true)
|
|
1578
|
+
treatment_sort_order Int @default(0)
|
|
1579
|
+
treatment_recall_days Int?
|
|
1580
|
+
treatment_created_at DateTime @default(now())
|
|
1581
|
+
treatment_updated_at DateTime @updatedAt
|
|
1582
|
+
|
|
1583
|
+
// Relations
|
|
1584
|
+
tenant Tenant @relation(fields: [treatment_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1585
|
+
clinic Clinic? @relation(fields: [treatment_clinic_id], references: [clinic_id])
|
|
1586
|
+
|
|
1587
|
+
treatment_plan_items TreatmentPlanItem[]
|
|
1588
|
+
appointments Appointment[]
|
|
1589
|
+
|
|
1590
|
+
@@index([treatment_tenant_id, treatment_is_active], name: "idx_treatments_tenant_active")
|
|
1591
|
+
@@index([treatment_tenant_id, treatment_category], name: "idx_treatments_tenant_category")
|
|
1592
|
+
@@index([treatment_clinic_id], name: "idx_treatments_clinic")
|
|
1593
|
+
@@map("treatments")
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// ─────────────────────────────────────────────
|
|
1597
|
+
// 41. TREATMENT PLANS
|
|
1598
|
+
// ─────────────────────────────────────────────
|
|
1599
|
+
|
|
1600
|
+
model TreatmentPlan {
|
|
1601
|
+
tplan_id String @id @default(uuid())
|
|
1602
|
+
tplan_tenant_id String
|
|
1603
|
+
tplan_clinic_id String
|
|
1604
|
+
tplan_patient_id String
|
|
1605
|
+
tplan_doctor_id String?
|
|
1606
|
+
tplan_name String
|
|
1607
|
+
tplan_status TreatmentPlanStatus @default(active)
|
|
1608
|
+
tplan_notes String @default("")
|
|
1609
|
+
tplan_created_at DateTime @default(now())
|
|
1610
|
+
tplan_updated_at DateTime @updatedAt
|
|
1611
|
+
|
|
1612
|
+
// Relations
|
|
1613
|
+
tenant Tenant @relation(fields: [tplan_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1614
|
+
clinic Clinic @relation(fields: [tplan_clinic_id], references: [clinic_id])
|
|
1615
|
+
patient Patient @relation(fields: [tplan_patient_id], references: [patient_id])
|
|
1616
|
+
doctor User? @relation("PlanDoctor", fields: [tplan_doctor_id], references: [user_id])
|
|
1617
|
+
|
|
1618
|
+
items TreatmentPlanItem[]
|
|
1619
|
+
photo_sets PatientPhotoSet[]
|
|
1620
|
+
|
|
1621
|
+
@@index([tplan_patient_id, tplan_status], name: "idx_tplans_patient_status")
|
|
1622
|
+
@@index([tplan_tenant_id, tplan_status], name: "idx_tplans_tenant_status")
|
|
1623
|
+
@@index([tplan_doctor_id], name: "idx_tplans_doctor")
|
|
1624
|
+
@@index([tplan_clinic_id], name: "idx_tplans_clinic")
|
|
1625
|
+
@@map("treatment_plans")
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// ─────────────────────────────────────────────
|
|
1629
|
+
// 42. TREATMENT PLAN ITEMS
|
|
1630
|
+
// ─────────────────────────────────────────────
|
|
1631
|
+
|
|
1632
|
+
model TreatmentPlanItem {
|
|
1633
|
+
tpitem_id String @id @default(uuid())
|
|
1634
|
+
tpitem_plan_id String
|
|
1635
|
+
tpitem_treatment_id String?
|
|
1636
|
+
tpitem_appointment_id String?
|
|
1637
|
+
tpitem_name String
|
|
1638
|
+
tpitem_tooth_number String?
|
|
1639
|
+
tpitem_status TreatmentPlanItemStatus @default(planned)
|
|
1640
|
+
tpitem_notes String @default("")
|
|
1641
|
+
tpitem_sort_order Int @default(0)
|
|
1642
|
+
tpitem_completed_at DateTime?
|
|
1643
|
+
tpitem_created_at DateTime @default(now())
|
|
1644
|
+
tpitem_updated_at DateTime @updatedAt
|
|
1645
|
+
|
|
1646
|
+
// Relations
|
|
1647
|
+
plan TreatmentPlan @relation(fields: [tpitem_plan_id], references: [tplan_id], onDelete: Cascade)
|
|
1648
|
+
treatment Treatment? @relation(fields: [tpitem_treatment_id], references: [treatment_id])
|
|
1649
|
+
appointment Appointment? @relation("ItemAppointment", fields: [tpitem_appointment_id], references: [appt_id])
|
|
1650
|
+
appointments_for_item Appointment[] @relation("AppointmentPlanItem")
|
|
1651
|
+
|
|
1652
|
+
@@index([tpitem_plan_id, tpitem_sort_order], name: "idx_tpitems_plan_order")
|
|
1653
|
+
@@index([tpitem_appointment_id], name: "idx_tpitems_appointment")
|
|
1654
|
+
@@map("treatment_plan_items")
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
// ─────────────────────────────────────────────
|
|
1658
|
+
// 43. DOCTOR PROFILES
|
|
1659
|
+
// ─────────────────────────────────────────────
|
|
1660
|
+
|
|
1661
|
+
model DoctorProfile {
|
|
1662
|
+
dprofile_id String @id @default(uuid())
|
|
1663
|
+
dprofile_user_id String @unique
|
|
1664
|
+
dprofile_specialty String @default("")
|
|
1665
|
+
dprofile_title String @default("")
|
|
1666
|
+
dprofile_bio String @default("")
|
|
1667
|
+
dprofile_working_hours Json @default("[]")
|
|
1668
|
+
dprofile_appointment_duration Int @default(30)
|
|
1669
|
+
dprofile_color String @default("")
|
|
1670
|
+
dprofile_is_accepting Boolean @default(true)
|
|
1671
|
+
dprofile_blocked_dates Json @default("[]")
|
|
1672
|
+
dprofile_google_email String?
|
|
1673
|
+
dprofile_google_encrypted_token String?
|
|
1674
|
+
dprofile_google_calendar_id String?
|
|
1675
|
+
dprofile_google_calendar_name String?
|
|
1676
|
+
dprofile_google_connected_at DateTime?
|
|
1677
|
+
dprofile_created_at DateTime @default(now())
|
|
1678
|
+
dprofile_updated_at DateTime @updatedAt
|
|
1679
|
+
|
|
1680
|
+
// Relations
|
|
1681
|
+
user User @relation(fields: [dprofile_user_id], references: [user_id], onDelete: Cascade)
|
|
1682
|
+
|
|
1683
|
+
@@map("doctor_profiles")
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
// ─────────────────────────────────────────────
|
|
1687
|
+
// 44. PATIENT PHOTO SETS
|
|
1688
|
+
// ─────────────────────────────────────────────
|
|
1689
|
+
|
|
1690
|
+
model PatientPhotoSet {
|
|
1691
|
+
photoset_id String @id @default(uuid())
|
|
1692
|
+
photoset_patient_id String
|
|
1693
|
+
photoset_tenant_id String
|
|
1694
|
+
photoset_clinic_id String
|
|
1695
|
+
photoset_treatment_plan_id String?
|
|
1696
|
+
photoset_type String
|
|
1697
|
+
photoset_label String @default("")
|
|
1698
|
+
photoset_taken_at DateTime @default(now())
|
|
1699
|
+
photoset_taken_by String?
|
|
1700
|
+
photoset_notes String @default("")
|
|
1701
|
+
photoset_created_at DateTime @default(now())
|
|
1702
|
+
photoset_updated_at DateTime @updatedAt
|
|
1703
|
+
|
|
1704
|
+
// Relations
|
|
1705
|
+
patient Patient @relation(fields: [photoset_patient_id], references: [patient_id], onDelete: Cascade)
|
|
1706
|
+
tenant Tenant @relation(fields: [photoset_tenant_id], references: [tenant_id])
|
|
1707
|
+
clinic Clinic @relation(fields: [photoset_clinic_id], references: [clinic_id])
|
|
1708
|
+
treatment_plan TreatmentPlan? @relation(fields: [photoset_treatment_plan_id], references: [tplan_id])
|
|
1709
|
+
taken_by_user User? @relation("PhotoTaker", fields: [photoset_taken_by], references: [user_id])
|
|
1710
|
+
|
|
1711
|
+
photos PatientPhoto[]
|
|
1712
|
+
|
|
1713
|
+
@@index([photoset_patient_id, photoset_taken_at(sort: Desc)], name: "idx_photosets_patient_date")
|
|
1714
|
+
@@index([photoset_treatment_plan_id], name: "idx_photosets_plan")
|
|
1715
|
+
@@index([photoset_tenant_id, photoset_type], name: "idx_photosets_tenant_type")
|
|
1716
|
+
@@map("patient_photo_sets")
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
// ─────────────────────────────────────────────
|
|
1720
|
+
// 45. PATIENT PHOTOS
|
|
1721
|
+
// ─────────────────────────────────────────────
|
|
1722
|
+
|
|
1723
|
+
model PatientPhoto {
|
|
1724
|
+
photo_id String @id @default(uuid())
|
|
1725
|
+
photo_set_id String
|
|
1726
|
+
photo_angle String @default("")
|
|
1727
|
+
photo_media_key String
|
|
1728
|
+
photo_thumbnail_key String?
|
|
1729
|
+
photo_caption String @default("")
|
|
1730
|
+
photo_sort_order Int @default(0)
|
|
1731
|
+
photo_created_at DateTime @default(now())
|
|
1732
|
+
|
|
1733
|
+
// Relations
|
|
1734
|
+
photo_set PatientPhotoSet @relation(fields: [photo_set_id], references: [photoset_id], onDelete: Cascade)
|
|
1735
|
+
|
|
1736
|
+
@@index([photo_set_id, photo_sort_order], name: "idx_photos_set_order")
|
|
1737
|
+
@@map("patient_photos")
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
// ─────────────────────────────────────────────
|
|
1741
|
+
// 46. EXAMINATION RECORDS
|
|
1742
|
+
// ─────────────────────────────────────────────
|
|
1743
|
+
|
|
1744
|
+
model ExaminationRecord {
|
|
1745
|
+
exam_id String @id @default(uuid())
|
|
1746
|
+
exam_appointment_id String? @unique
|
|
1747
|
+
exam_patient_id String
|
|
1748
|
+
exam_doctor_id String
|
|
1749
|
+
exam_clinic_id String
|
|
1750
|
+
exam_tenant_id String
|
|
1751
|
+
exam_findings String @default("")
|
|
1752
|
+
exam_diagnosis String @default("")
|
|
1753
|
+
exam_procedure_notes String @default("")
|
|
1754
|
+
exam_prescription String @default("")
|
|
1755
|
+
exam_instructions String @default("")
|
|
1756
|
+
exam_created_at DateTime @default(now())
|
|
1757
|
+
exam_updated_at DateTime @updatedAt
|
|
1758
|
+
|
|
1759
|
+
// Relations
|
|
1760
|
+
appointment Appointment? @relation(fields: [exam_appointment_id], references: [appt_id], onDelete: Cascade)
|
|
1761
|
+
patient Patient @relation(fields: [exam_patient_id], references: [patient_id])
|
|
1762
|
+
doctor User @relation("ExamDoctor", fields: [exam_doctor_id], references: [user_id])
|
|
1763
|
+
clinic Clinic @relation(fields: [exam_clinic_id], references: [clinic_id])
|
|
1764
|
+
tenant Tenant @relation(fields: [exam_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1765
|
+
|
|
1766
|
+
@@index([exam_patient_id, exam_created_at(sort: Desc)], name: "idx_exam_patient_date")
|
|
1767
|
+
@@index([exam_doctor_id, exam_created_at(sort: Desc)], name: "idx_exam_doctor_date")
|
|
1768
|
+
@@map("examination_records")
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
// ─────────────────────────────────────────────
|
|
1772
|
+
// 47. AVAILABILITY BLOCKS (holidays, leaves, breaks)
|
|
1773
|
+
// ─────────────────────────────────────────────
|
|
1774
|
+
|
|
1775
|
+
model AvailabilityBlock {
|
|
1776
|
+
block_id String @id @default(uuid())
|
|
1777
|
+
block_tenant_id String
|
|
1778
|
+
block_clinic_id String
|
|
1779
|
+
block_doctor_id String? // null = clinic-wide, set = doctor-specific
|
|
1780
|
+
block_title String
|
|
1781
|
+
block_type AvailabilityBlockType @default(holiday)
|
|
1782
|
+
block_start_date DateTime @db.Date
|
|
1783
|
+
block_end_date DateTime @db.Date
|
|
1784
|
+
block_all_day Boolean @default(true)
|
|
1785
|
+
block_start_time String? // "14:00" when not all_day
|
|
1786
|
+
block_end_time String? // "16:00" when not all_day
|
|
1787
|
+
block_recurring Boolean @default(false)
|
|
1788
|
+
block_notes String @default("")
|
|
1789
|
+
block_created_by String?
|
|
1790
|
+
block_created_at DateTime @default(now())
|
|
1791
|
+
|
|
1792
|
+
// Relations
|
|
1793
|
+
tenant Tenant @relation(fields: [block_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
1794
|
+
clinic Clinic @relation(fields: [block_clinic_id], references: [clinic_id])
|
|
1795
|
+
doctor User? @relation("BlockDoctor", fields: [block_doctor_id], references: [user_id])
|
|
1796
|
+
created_by User? @relation("BlockCreatedBy", fields: [block_created_by], references: [user_id])
|
|
1797
|
+
|
|
1798
|
+
@@index([block_tenant_id, block_clinic_id, block_start_date], name: "idx_blocks_clinic_date")
|
|
1799
|
+
@@index([block_doctor_id, block_start_date], name: "idx_blocks_doctor_date")
|
|
1800
|
+
@@map("availability_blocks")
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
// ─────────────────────────────────────────────
|
|
1804
|
+
// ADMIN CHAT SESSIONS (AI Playground)
|
|
1805
|
+
// ─────────────────────────────────────────────
|
|
1806
|
+
|
|
1807
|
+
model AdminChatSession {
|
|
1808
|
+
acs_id String @id @default(uuid())
|
|
1809
|
+
acs_user_id String
|
|
1810
|
+
acs_title String @default("")
|
|
1811
|
+
acs_provider String @default("anthropic")
|
|
1812
|
+
acs_tenant_id String?
|
|
1813
|
+
acs_clinic_id String?
|
|
1814
|
+
acs_agent_id String?
|
|
1815
|
+
acs_system_prompt String @default("")
|
|
1816
|
+
acs_enable_tools Boolean @default(false)
|
|
1817
|
+
acs_channel String @default("whatsapp")
|
|
1818
|
+
acs_message_count Int @default(0)
|
|
1819
|
+
acs_last_message_at DateTime?
|
|
1820
|
+
acs_metadata Json @default("{}")
|
|
1821
|
+
acs_created_at DateTime @default(now())
|
|
1822
|
+
acs_updated_at DateTime @updatedAt
|
|
1823
|
+
|
|
1824
|
+
user User @relation(fields: [acs_user_id], references: [user_id], onDelete: Cascade)
|
|
1825
|
+
messages AdminChatMessage[]
|
|
1826
|
+
|
|
1827
|
+
@@index([acs_user_id, acs_updated_at(sort: Desc)], name: "idx_acs_user_updated")
|
|
1828
|
+
@@map("admin_chat_sessions")
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
model AdminChatMessage {
|
|
1832
|
+
acm_id String @id @default(uuid())
|
|
1833
|
+
acm_session_id String
|
|
1834
|
+
acm_role AcmRole
|
|
1835
|
+
acm_content String
|
|
1836
|
+
acm_metadata Json @default("{}")
|
|
1837
|
+
acm_created_at DateTime @default(now())
|
|
1838
|
+
|
|
1839
|
+
session AdminChatSession @relation(fields: [acm_session_id], references: [acs_id], onDelete: Cascade)
|
|
1840
|
+
|
|
1841
|
+
@@index([acm_session_id, acm_created_at], name: "idx_acm_session_date")
|
|
1842
|
+
@@map("admin_chat_messages")
|
|
1843
|
+
}
|