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,542 @@
|
|
|
1
|
+
# Outbound Campaigns
|
|
2
|
+
|
|
3
|
+
> Customizable outbound call system for any use case: patient follow-ups, satisfaction surveys, marketing, feedback collection.
|
|
4
|
+
> Last updated: 2026-04-02
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Design Philosophy
|
|
9
|
+
|
|
10
|
+
The outbound campaign system is intentionally decoupled from any specific use case. Earlier iterations tied campaigns to a Survey model with fixed questions. That dependency has been removed.
|
|
11
|
+
|
|
12
|
+
**Core principle:** Each campaign defines its own prompt, first message, extraction schema, and schedule. The system does not know or care whether the campaign is a patient satisfaction survey, a follow-up call, or a marketing outreach. The extraction schema replaces fixed survey questions with flexible structured data extraction.
|
|
13
|
+
|
|
14
|
+
**Comparison with Appointment Validation:**
|
|
15
|
+
|
|
16
|
+
| Aspect | Appointment Validation | Outbound Campaigns |
|
|
17
|
+
|--------|----------------------|-------------------|
|
|
18
|
+
| Purpose | Confirm existing appointments | Any use case |
|
|
19
|
+
| Outcomes | Fixed: confirmed, cancelled, reschedule, unresolved | Flexible: defined by extraction schema |
|
|
20
|
+
| Data model | Batch + entries | Campaign + entries |
|
|
21
|
+
| Agent config | Uses tenant's configured validation agent | Per-campaign custom prompt and voice |
|
|
22
|
+
| Phone list source | CSV with appointment data columns | CSV/JSON with optional custom data per entry |
|
|
23
|
+
| AI behavior | Single tool (`confirm_appointment_validation`) | Post-call extraction from transcript |
|
|
24
|
+
| Feature flag | `appointment_validation` | `outbound_campaigns` |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Campaign Lifecycle
|
|
29
|
+
|
|
30
|
+
### 2.1 State Machine
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
+-------+
|
|
34
|
+
| draft |
|
|
35
|
+
+---+---+
|
|
36
|
+
|
|
|
37
|
+
| start
|
|
38
|
+
v
|
|
39
|
+
+-----------+
|
|
40
|
+
| scheduled |
|
|
41
|
+
+-----+-----+
|
|
42
|
+
|
|
|
43
|
+
| first call dispatched
|
|
44
|
+
v
|
|
45
|
+
+---------+
|
|
46
|
+
+--->| running |<---+
|
|
47
|
+
| +----+----+ |
|
|
48
|
+
| | |
|
|
49
|
+
| resume | pause | resume
|
|
50
|
+
| v |
|
|
51
|
+
| +--------+ |
|
|
52
|
+
+----| paused |-----+
|
|
53
|
+
+--------+
|
|
54
|
+
|
|
|
55
|
+
| stop (or all entries done)
|
|
56
|
+
v
|
|
57
|
+
+-----------+
|
|
58
|
+
| completed |
|
|
59
|
+
+-----------+
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2.2 State Transitions
|
|
63
|
+
|
|
64
|
+
| From | To | Trigger | Validation |
|
|
65
|
+
|------|----|---------|-----------|
|
|
66
|
+
| `draft` | `scheduled` | `POST /:id/start` | Must have entries, agent config, and schedule |
|
|
67
|
+
| `draft` | (deleted) | `DELETE /:id` | Only draft campaigns can be deleted |
|
|
68
|
+
| `scheduled` | `running` | First call dispatched by BullMQ | Automatic |
|
|
69
|
+
| `running` | `paused` | `POST /:id/pause` | Stops dispatching new calls; in-progress calls continue |
|
|
70
|
+
| `paused` | `running` | `POST /:id/resume` | Resumes dispatching |
|
|
71
|
+
| `running` | `completed` | `POST /:id/stop` or all entries processed | Manual stop or automatic on completion |
|
|
72
|
+
| `paused` | `completed` | `POST /:id/stop` | Manual stop while paused |
|
|
73
|
+
|
|
74
|
+
**Constraints:**
|
|
75
|
+
- Only `draft` campaigns can be edited (`PUT /:id`) or deleted.
|
|
76
|
+
- Entries can only be uploaded (`POST /:id/entries`) or cleared (`DELETE /:id/entries`) while in `draft`.
|
|
77
|
+
- Failed/no_answer entries can be retried in `running` or `paused` state.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 3. Creating a Campaign
|
|
82
|
+
|
|
83
|
+
### 3.1 Agent Configuration
|
|
84
|
+
|
|
85
|
+
Each campaign carries its own agent configuration in the `campaign_agent_config` JSONB column:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
{
|
|
89
|
+
prompt: string; // System prompt for the AI agent
|
|
90
|
+
first_message: string; // What the AI says when the patient answers
|
|
91
|
+
language: string; // e.g., "tr"
|
|
92
|
+
voice_id: string; // ElevenLabs voice ID
|
|
93
|
+
extraction_schema: Array<{ // What data to extract (Section 4)
|
|
94
|
+
field: string;
|
|
95
|
+
type: 'text' | 'number' | 'boolean' | 'enum';
|
|
96
|
+
description: string;
|
|
97
|
+
options?: string[]; // Required for enum type
|
|
98
|
+
required: boolean;
|
|
99
|
+
}>;
|
|
100
|
+
post_call_prompt: string; // Prompt for post-call data extraction
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The `campaign_agent_id` references the base Agent record (for ElevenLabs agent ID and tenant resolution), but the prompt and voice can be overridden per-campaign via `agent_config`.
|
|
105
|
+
|
|
106
|
+
### 3.2 Phone List Upload
|
|
107
|
+
|
|
108
|
+
Entries are uploaded as CSV or JSON. Each entry can carry optional custom data that is passed to the AI agent as dynamic variables during the call.
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
POST /outbound-campaigns/:id/entries
|
|
112
|
+
Content-Type: application/json
|
|
113
|
+
|
|
114
|
+
{
|
|
115
|
+
"entries": [
|
|
116
|
+
{
|
|
117
|
+
"phone": "+905551234567",
|
|
118
|
+
"contact_name": "Ayse Yilmaz",
|
|
119
|
+
"custom_data": {
|
|
120
|
+
"product": "Implant",
|
|
121
|
+
"last_visit": "2026-01-15",
|
|
122
|
+
"doctor": "Dr. Mehmet"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
...
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The `custom_data` is stored in `centry_custom_data` (JSONB) and made available to the AI agent as dynamic variables during the call. This enables personalized conversations without changing the campaign prompt.
|
|
131
|
+
|
|
132
|
+
### 3.3 Schedule Configuration
|
|
133
|
+
|
|
134
|
+
Stored in `campaign_schedule` JSONB:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
{
|
|
138
|
+
start_date: string; // "2026-04-01"
|
|
139
|
+
end_date: string; // "2026-04-15"
|
|
140
|
+
daily_start_time: string; // "09:00"
|
|
141
|
+
daily_end_time: string; // "18:00"
|
|
142
|
+
days_of_week: number[]; // [1,2,3,4,5] (Mon-Fri)
|
|
143
|
+
max_concurrent: number; // Max simultaneous calls (e.g., 5)
|
|
144
|
+
max_retries: number; // Max retry attempts per entry (e.g., 3)
|
|
145
|
+
retry_delay_minutes: number; // Delay between retries (e.g., 60)
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 4. Extraction Schema
|
|
152
|
+
|
|
153
|
+
The extraction schema defines what structured data the AI should pull from each call. It replaces fixed survey questions with a flexible, per-campaign definition.
|
|
154
|
+
|
|
155
|
+
### 4.1 Schema Definition
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
extraction_schema: [
|
|
159
|
+
{
|
|
160
|
+
field: "satisfaction_score",
|
|
161
|
+
type: "number",
|
|
162
|
+
description: "Patient's satisfaction on a scale of 1-10",
|
|
163
|
+
required: true
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
field: "wants_callback",
|
|
167
|
+
type: "boolean",
|
|
168
|
+
description: "Whether the patient wants to be called back",
|
|
169
|
+
required: true
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
field: "preferred_time",
|
|
173
|
+
type: "enum",
|
|
174
|
+
description: "When the patient prefers to be contacted",
|
|
175
|
+
options: ["morning", "afternoon", "evening", "no_preference"],
|
|
176
|
+
required: false
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
field: "feedback",
|
|
180
|
+
type: "text",
|
|
181
|
+
description: "Free-form patient feedback about their experience",
|
|
182
|
+
required: false
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 4.2 Supported Types
|
|
188
|
+
|
|
189
|
+
| Type | Description | Example Value |
|
|
190
|
+
|------|-------------|---------------|
|
|
191
|
+
| `text` | Free-form string | `"The service was excellent but parking was difficult"` |
|
|
192
|
+
| `number` | Numeric value | `8` |
|
|
193
|
+
| `boolean` | True or false | `true` |
|
|
194
|
+
| `enum` | One of predefined options | `"morning"` |
|
|
195
|
+
|
|
196
|
+
### 4.3 Extraction Process
|
|
197
|
+
|
|
198
|
+
Data extraction happens during post-call processing (Section 6), not during the call itself. The AI processes the transcript with a dedicated extraction prompt (`agent_config.post_call_prompt`) that references the schema:
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
Given this phone call transcript, extract the following data points:
|
|
202
|
+
- satisfaction_score (number, 1-10): Patient's satisfaction rating
|
|
203
|
+
- wants_callback (boolean): Whether patient wants callback
|
|
204
|
+
- preferred_time (enum: morning/afternoon/evening/no_preference): Contact preference
|
|
205
|
+
- feedback (text): Free-form patient feedback
|
|
206
|
+
|
|
207
|
+
Transcript:
|
|
208
|
+
{transcript}
|
|
209
|
+
|
|
210
|
+
Return valid JSON matching the schema.
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The extracted data is stored as JSONB in `centry_extracted_data`:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"satisfaction_score": 8,
|
|
218
|
+
"wants_callback": true,
|
|
219
|
+
"preferred_time": "morning",
|
|
220
|
+
"feedback": "The treatment was great but I had to wait 30 minutes"
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 5. Call Dispatch (BullMQ)
|
|
227
|
+
|
|
228
|
+
### 5.1 Dispatch Processor
|
|
229
|
+
|
|
230
|
+
**Queue:** `outbound-campaigns:dispatch`
|
|
231
|
+
**Concurrency:** Configured per-campaign via `campaign_schedule.max_concurrent`.
|
|
232
|
+
|
|
233
|
+
### 5.2 Dispatch Flow
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
Campaign started (status = scheduled/running)
|
|
237
|
+
|
|
|
238
|
+
v
|
|
239
|
+
Dispatch processor picks up campaign
|
|
240
|
+
|
|
|
241
|
+
v
|
|
242
|
+
For each entry where centry_status = 'pending'
|
|
243
|
+
AND centry_attempts < centry_max_attempts:
|
|
244
|
+
|
|
|
245
|
+
+-- Check time window
|
|
246
|
+
| |
|
|
247
|
+
| +-- Current time within daily_start_time..daily_end_time?
|
|
248
|
+
| +-- Current day in days_of_week?
|
|
249
|
+
| +-- Current date within start_date..end_date?
|
|
250
|
+
| |
|
|
251
|
+
| +-- NO: delay job until next valid window
|
|
252
|
+
| +-- YES: continue
|
|
253
|
+
|
|
|
254
|
+
+-- Check concurrency
|
|
255
|
+
| |
|
|
256
|
+
| +-- Count entries where centry_status = 'calling'
|
|
257
|
+
| +-- If count >= max_concurrent: wait
|
|
258
|
+
|
|
|
259
|
+
+-- Dispatch call
|
|
260
|
+
|
|
|
261
|
+
1. Set centry_status = 'calling'
|
|
262
|
+
2. Set centry_attempts += 1
|
|
263
|
+
3. Set centry_last_attempt_at = now()
|
|
264
|
+
4. Call elevenlabsService.sipTrunkOutboundCall({
|
|
265
|
+
agentId: campaign.agent.agent_elevenlabs_id,
|
|
266
|
+
fromPhoneNumber: campaign.phone.phone_number,
|
|
267
|
+
toPhoneNumber: centry_phone,
|
|
268
|
+
dynamicVariables: {
|
|
269
|
+
contact_name: centry_contact_name,
|
|
270
|
+
...centry_custom_data
|
|
271
|
+
},
|
|
272
|
+
agentOverrides: {
|
|
273
|
+
prompt: campaign_agent_config.prompt,
|
|
274
|
+
first_message: campaign_agent_config.first_message,
|
|
275
|
+
language: campaign_agent_config.language,
|
|
276
|
+
voice_id: campaign_agent_config.voice_id,
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
5. On success: store conversation_id in centry_conversation_id
|
|
280
|
+
6. On failure: set centry_status = 'failed'
|
|
281
|
+
If attempts < max_retries: requeue with retry_delay_minutes
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### 5.3 Time Window Enforcement
|
|
285
|
+
|
|
286
|
+
Calls are only placed during the configured schedule window. If the dispatch processor runs outside the window, it calculates the delay to the next valid window and schedules the job accordingly:
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
next_window = find next valid {day_of_week + daily_start_time} from now
|
|
290
|
+
delay = next_window - Date.now()
|
|
291
|
+
queue.add('dispatch', { campaignId, entryId }, { delay })
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### 5.4 Retry Logic
|
|
295
|
+
|
|
296
|
+
| Scenario | Action |
|
|
297
|
+
|----------|--------|
|
|
298
|
+
| Call placed, no answer | Set status `no_answer`. If attempts < max_retries, requeue with delay. |
|
|
299
|
+
| Call placed, voicemail | Set status `voicemail`. If attempts < max_retries, requeue with delay. |
|
|
300
|
+
| Call failed (SIP error) | Set status `failed`. If attempts < max_retries, requeue with delay. |
|
|
301
|
+
| Call completed | Proceed to post-call processing. |
|
|
302
|
+
| Max attempts exhausted | Set final status. No more retries. |
|
|
303
|
+
|
|
304
|
+
Manual retry is also available via:
|
|
305
|
+
- `POST /:id/retry` -- retry all failed/no_answer entries in the campaign.
|
|
306
|
+
- `POST /:id/entries/:entryId/retry` -- retry a single entry.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## 6. Post-Call Processing
|
|
311
|
+
|
|
312
|
+
### 6.1 Sequence Diagram
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
ElevenLabs Webhook Handler Webhook Processor AIModule Database
|
|
316
|
+
| | | | |
|
|
317
|
+
| Post-call webhook | | | |
|
|
318
|
+
| {conversation_id, | | | |
|
|
319
|
+
| transcript, ...} | | | |
|
|
320
|
+
|---------------------->| | | |
|
|
321
|
+
| | | | |
|
|
322
|
+
| | Enqueue to | | |
|
|
323
|
+
| | elevenlabs:webhook | | |
|
|
324
|
+
| 200 OK | queue | | |
|
|
325
|
+
|<----------------------| | | |
|
|
326
|
+
| | | | |
|
|
327
|
+
| | | Process job | |
|
|
328
|
+
| | | | |
|
|
329
|
+
| | | 1. Find campaign | |
|
|
330
|
+
| | | entry by | |
|
|
331
|
+
| | | conversation_id | |
|
|
332
|
+
| | | | |
|
|
333
|
+
| | | 2. Extract data per | |
|
|
334
|
+
| | | extraction_schema | |
|
|
335
|
+
| | |---------------------->| |
|
|
336
|
+
| | | extracted_data JSON | |
|
|
337
|
+
| | |<----------------------| |
|
|
338
|
+
| | | | |
|
|
339
|
+
| | | 3. Generate summary | |
|
|
340
|
+
| | |---------------------->| |
|
|
341
|
+
| | | summary text | |
|
|
342
|
+
| | |<----------------------| |
|
|
343
|
+
| | | | |
|
|
344
|
+
| | | 4. Update entry | |
|
|
345
|
+
| | | status, data, | |
|
|
346
|
+
| | | summary | |
|
|
347
|
+
| | |--------------------------------------------->|
|
|
348
|
+
| | | | |
|
|
349
|
+
| | | 5. Create Call | |
|
|
350
|
+
| | | record, link to | |
|
|
351
|
+
| | | entry | |
|
|
352
|
+
| | |--------------------------------------------->|
|
|
353
|
+
| | | | |
|
|
354
|
+
| | | 6. Recalculate | |
|
|
355
|
+
| | | campaign_stats | |
|
|
356
|
+
| | |--------------------------------------------->|
|
|
357
|
+
| | | | |
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 6.2 Processing Steps
|
|
361
|
+
|
|
362
|
+
1. **Match entry by `conversation_id`:** The ElevenLabs webhook contains a `conversation_id`. Look up the `OutboundCampaignEntry` where `centry_conversation_id` matches.
|
|
363
|
+
|
|
364
|
+
2. **Extract structured data:** Use AIModule with the campaign's `post_call_prompt` and `extraction_schema` to pull structured data from the transcript. Store the result as JSONB in `centry_extracted_data`.
|
|
365
|
+
|
|
366
|
+
3. **Generate summary:** Use AIModule to produce a concise text summary of the call. Store in `centry_summary`.
|
|
367
|
+
|
|
368
|
+
4. **Update entry:** Set `centry_status = 'completed'`, `centry_call_duration_secs`, `centry_completed_at = now()`.
|
|
369
|
+
|
|
370
|
+
5. **Create Call record:** Insert a row in the `calls` table with `call_campaign_id` linking back to the campaign. Insert `call_details` with transcript and summary. Link the call to the entry via `centry_call_id`.
|
|
371
|
+
|
|
372
|
+
6. **Recalculate campaign stats:** Update the denormalized `campaign_stats` JSON by counting entries per status:
|
|
373
|
+
```json
|
|
374
|
+
{
|
|
375
|
+
"total": 150,
|
|
376
|
+
"pending": 42,
|
|
377
|
+
"calling": 3,
|
|
378
|
+
"completed": 89,
|
|
379
|
+
"failed": 8,
|
|
380
|
+
"no_answer": 6,
|
|
381
|
+
"voicemail": 2
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
This avoids expensive aggregation queries on every dashboard load.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## 7. Data Model
|
|
389
|
+
|
|
390
|
+
### outbound_campaigns
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
outbound_campaigns
|
|
394
|
+
campaign_id UUID PK
|
|
395
|
+
campaign_tenant_id UUID FK -> tenants
|
|
396
|
+
campaign_clinic_id UUID FK -> clinics -- Required. Every campaign belongs to a clinic.
|
|
397
|
+
campaign_agent_id UUID FK -> agents
|
|
398
|
+
campaign_name String
|
|
399
|
+
campaign_description String
|
|
400
|
+
campaign_status enum: draft | scheduled | running | paused | completed
|
|
401
|
+
campaign_agent_config JSONB -- {prompt, first_message, language, voice_id,
|
|
402
|
+
-- extraction_schema, post_call_prompt}
|
|
403
|
+
campaign_schedule JSONB -- {start_date, end_date, daily_start_time,
|
|
404
|
+
-- daily_end_time, days_of_week, max_concurrent,
|
|
405
|
+
-- max_retries, retry_delay_minutes}
|
|
406
|
+
campaign_phone_id UUID? FK -> phone_numbers (outbound phone)
|
|
407
|
+
campaign_stats JSONB -- {total, pending, calling, completed, failed, ...}
|
|
408
|
+
campaign_created_at DateTime
|
|
409
|
+
campaign_updated_at DateTime
|
|
410
|
+
|
|
411
|
+
Indexes:
|
|
412
|
+
(campaign_tenant_id, campaign_status)
|
|
413
|
+
(campaign_clinic_id)
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### outbound_campaign_entries
|
|
417
|
+
|
|
418
|
+
```
|
|
419
|
+
outbound_campaign_entries
|
|
420
|
+
centry_id UUID PK
|
|
421
|
+
centry_campaign_id UUID FK -> outbound_campaigns (CASCADE)
|
|
422
|
+
centry_phone String
|
|
423
|
+
centry_contact_name String
|
|
424
|
+
centry_custom_data JSONB default {} -- Per-entry dynamic variables
|
|
425
|
+
centry_status enum: pending | calling | completed | failed | no_answer | voicemail
|
|
426
|
+
centry_attempts Int default 0
|
|
427
|
+
centry_max_attempts Int default 3
|
|
428
|
+
centry_last_attempt_at DateTime?
|
|
429
|
+
centry_conversation_id String? -- ElevenLabs conversation ID
|
|
430
|
+
centry_call_id UUID? FK -> calls -- Linked after call completes
|
|
431
|
+
centry_call_duration_secs Int default 0
|
|
432
|
+
centry_extracted_data JSONB? -- AI-extracted per extraction_schema
|
|
433
|
+
centry_summary String?
|
|
434
|
+
centry_called_at DateTime?
|
|
435
|
+
centry_completed_at DateTime?
|
|
436
|
+
centry_created_at DateTime
|
|
437
|
+
centry_updated_at DateTime
|
|
438
|
+
|
|
439
|
+
Indexes:
|
|
440
|
+
(centry_campaign_id, centry_status)
|
|
441
|
+
(centry_conversation_id)
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### campaign_stats (Denormalized)
|
|
445
|
+
|
|
446
|
+
The `campaign_stats` JSONB on `outbound_campaigns` is a cache. It is recomputed whenever an entry status changes (in the post-call processor and dispatch processor). This avoids `COUNT(*)` queries with GROUP BY on every dashboard page load.
|
|
447
|
+
|
|
448
|
+
Recomputation logic:
|
|
449
|
+
|
|
450
|
+
```sql
|
|
451
|
+
SELECT centry_status, COUNT(*) as count
|
|
452
|
+
FROM outbound_campaign_entries
|
|
453
|
+
WHERE centry_campaign_id = :campaignId
|
|
454
|
+
GROUP BY centry_status
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
The result is written to `campaign_stats` as a single JSON object.
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## 8. API Endpoints
|
|
462
|
+
|
|
463
|
+
| Method | Path | Permission | Description |
|
|
464
|
+
|--------|------|-----------|-------------|
|
|
465
|
+
| GET | `/outbound-campaigns` | `campaigns:read` | List campaigns (paginated) |
|
|
466
|
+
| POST | `/outbound-campaigns` | `campaigns:manage` | Create campaign with agent config + extraction schema |
|
|
467
|
+
| GET | `/outbound-campaigns/:id` | `campaigns:read` | Campaign detail with stats |
|
|
468
|
+
| PUT | `/outbound-campaigns/:id` | `campaigns:manage` | Update (only in draft) |
|
|
469
|
+
| DELETE | `/outbound-campaigns/:id` | `campaigns:manage` | Delete (only in draft) |
|
|
470
|
+
| POST | `/outbound-campaigns/:id/entries` | `campaigns:manage` | Upload phone list |
|
|
471
|
+
| DELETE | `/outbound-campaigns/:id/entries` | `campaigns:manage` | Clear phone list (only in draft) |
|
|
472
|
+
| POST | `/outbound-campaigns/:id/start` | `campaigns:manage` | Start calling |
|
|
473
|
+
| POST | `/outbound-campaigns/:id/pause` | `campaigns:manage` | Pause calling |
|
|
474
|
+
| POST | `/outbound-campaigns/:id/resume` | `campaigns:manage` | Resume calling |
|
|
475
|
+
| POST | `/outbound-campaigns/:id/stop` | `campaigns:manage` | Stop and complete |
|
|
476
|
+
| POST | `/outbound-campaigns/:id/retry` | `campaigns:manage` | Retry all failed/no_answer |
|
|
477
|
+
| POST | `/outbound-campaigns/:id/entries/:entryId/retry` | `campaigns:manage` | Retry single entry |
|
|
478
|
+
| GET | `/outbound-campaigns/:id/results` | `campaigns:read` | Results with extracted data |
|
|
479
|
+
| GET | `/outbound-campaigns/:id/results/export` | `campaigns:export` | CSV export with extracted data |
|
|
480
|
+
| GET | `/outbound-campaigns/:id/logs` | `campaigns:read` | Campaign-scoped application logs |
|
|
481
|
+
| POST | `/outbound-campaigns/:id/sync` | `campaigns:manage` | Manual sync statuses from ElevenLabs |
|
|
482
|
+
|
|
483
|
+
### CSV Export Format
|
|
484
|
+
|
|
485
|
+
The export includes all static entry fields plus dynamically generated columns from the extraction schema:
|
|
486
|
+
|
|
487
|
+
```
|
|
488
|
+
Phone, Contact Name, Status, Attempts, Call Duration, Called At, Completed At,
|
|
489
|
+
Summary, [extraction_field_1], [extraction_field_2], ...
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
For example, with the satisfaction survey schema from Section 4.1:
|
|
493
|
+
|
|
494
|
+
```
|
|
495
|
+
Phone, Contact Name, Status, ..., satisfaction_score, wants_callback, preferred_time, feedback
|
|
496
|
+
+905551234567, Ayse Yilmaz, completed, ..., 8, true, morning, "Great service but parking..."
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## 9. BullMQ Queues
|
|
502
|
+
|
|
503
|
+
| Queue | Purpose | Concurrency | Schedule |
|
|
504
|
+
|-------|---------|-------------|----------|
|
|
505
|
+
| `outbound-campaigns:dispatch` | Call dispatch with time window enforcement | Per-campaign `max_concurrent` | On campaign start, continuous |
|
|
506
|
+
| `outbound-campaigns:sync` | Sync entry statuses from ElevenLabs | 1 | Repeatable every 60 seconds |
|
|
507
|
+
|
|
508
|
+
The dispatch processor runs as a continuous loop while a campaign is in `running` status. It picks the next `pending` entry, checks time window constraints, and dispatches the call. When paused, the processor stops picking new entries but does not interrupt in-progress calls.
|
|
509
|
+
|
|
510
|
+
The sync processor polls ElevenLabs for conversation statuses, similar to appointment validation sync. It handles edge cases where the post-call webhook was missed or delayed.
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## 10. Feature Flag
|
|
515
|
+
|
|
516
|
+
| Flag | Gates |
|
|
517
|
+
|------|-------|
|
|
518
|
+
| `outbound_campaigns` | All `/outbound-campaigns/*` endpoints |
|
|
519
|
+
|
|
520
|
+
The feature flag is checked by the `FeaturesGuard` on every request to the outbound campaigns controller. If the tenant does not have `outbound_campaigns` in `tenant_enabled_features`, all endpoints return 403.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## 11. NestJS Module Structure
|
|
525
|
+
|
|
526
|
+
```
|
|
527
|
+
src/outbound-campaigns/
|
|
528
|
+
outbound-campaigns.module.ts -- Module definition, imports BullMQ queues
|
|
529
|
+
outbound-campaigns.controller.ts -- All REST endpoints
|
|
530
|
+
outbound-campaigns.service.ts -- Business logic: create, start, pause, stop, retry, sync
|
|
531
|
+
processors/
|
|
532
|
+
dispatch.processor.ts -- BullMQ: call dispatch with concurrency + time windows
|
|
533
|
+
sync.processor.ts -- BullMQ: status sync from ElevenLabs
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
The module imports:
|
|
537
|
+
- `IntegrationsModule` (for `ElevenLabsService` -- SIP trunk outbound calls)
|
|
538
|
+
- `AIModule` (for post-call extraction and summary)
|
|
539
|
+
- `BullModule.registerQueue('outbound-campaigns:dispatch', 'outbound-campaigns:sync')`
|
|
540
|
+
- `PrismaModule` (for database access)
|
|
541
|
+
|
|
542
|
+
The post-call processing for campaign entries is handled within the `elevenlabs:webhook` processor (shared with all call types), which detects campaign calls by checking if a `conversation_id` matches any `centry_conversation_id`.
|