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,519 @@
|
|
|
1
|
+
# Before/After Patient Photos
|
|
2
|
+
|
|
3
|
+
> Structured photo documentation linked to patients and treatment plans -- consultation photos, progress tracking, and before/after comparisons for aesthetic and dental clinics.
|
|
4
|
+
> Last updated: 2026-03-29
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Overview
|
|
9
|
+
|
|
10
|
+
Before/after photos are essential for aesthetic and dental clinics. This is **not** random media from WhatsApp chat -- it is structured photo documentation linked to patients and treatment plans.
|
|
11
|
+
|
|
12
|
+
### Use Cases
|
|
13
|
+
|
|
14
|
+
| Use Case | Description |
|
|
15
|
+
|----------|-------------|
|
|
16
|
+
| Before photos | Taken at consultation, before any treatment begins |
|
|
17
|
+
| Progress photos | Taken during treatment (e.g., between sessions) |
|
|
18
|
+
| After photos | Taken at treatment completion (1 week, 1 month, 3 months) |
|
|
19
|
+
| Comparison grids | Side-by-side before/after on patient detail page, matched by angle |
|
|
20
|
+
| Portfolio / case documentation | Future: marketing material with patient consent |
|
|
21
|
+
|
|
22
|
+
### How It Works
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
Patient visits clinic
|
|
26
|
+
|
|
|
27
|
+
v
|
|
28
|
+
Staff opens patient detail -> Photos tab -> "Add Photo Set"
|
|
29
|
+
|
|
|
30
|
+
v
|
|
31
|
+
Selects type (before / after_1week / progress / ...)
|
|
32
|
+
Optionally links to a treatment plan
|
|
33
|
+
|
|
|
34
|
+
v
|
|
35
|
+
Uploads multiple images (front, left, right, smile, ...)
|
|
36
|
+
|
|
|
37
|
+
v
|
|
38
|
+
Each image -> MinIO (original + thumbnail)
|
|
39
|
+
|
|
|
40
|
+
v
|
|
41
|
+
Later: staff adds after photos
|
|
42
|
+
|
|
|
43
|
+
v
|
|
44
|
+
Frontend displays comparison grid (before front vs. after front, etc.)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 2. Data Model
|
|
50
|
+
|
|
51
|
+
Two tables: `patient_photo_sets` (a group of related photos taken at a point in time) and `patient_photos` (individual images within a set).
|
|
52
|
+
|
|
53
|
+
### 2.1 patient_photo_sets
|
|
54
|
+
|
|
55
|
+
**Purpose:** A logical group of photos taken at a specific point in a patient's treatment timeline. For example, "Before - Front/Left/Right" or "1 Month After - Front/Smile".
|
|
56
|
+
|
|
57
|
+
```prisma
|
|
58
|
+
model PatientPhotoSet {
|
|
59
|
+
photoset_id String @id @default(uuid())
|
|
60
|
+
photoset_patient_id String
|
|
61
|
+
photoset_tenant_id String
|
|
62
|
+
photoset_clinic_id String?
|
|
63
|
+
photoset_treatment_plan_id String?
|
|
64
|
+
photoset_type String
|
|
65
|
+
photoset_label String @default("")
|
|
66
|
+
photoset_taken_at DateTime @default(now())
|
|
67
|
+
photoset_taken_by String?
|
|
68
|
+
photoset_notes String @default("")
|
|
69
|
+
photoset_created_at DateTime @default(now())
|
|
70
|
+
photoset_updated_at DateTime @updatedAt
|
|
71
|
+
|
|
72
|
+
patient Patient @relation(fields: [photoset_patient_id], references: [patient_id], onDelete: Cascade)
|
|
73
|
+
tenant Tenant @relation(fields: [photoset_tenant_id], references: [tenant_id], onDelete: Cascade)
|
|
74
|
+
clinic Clinic? @relation(fields: [photoset_clinic_id], references: [clinic_id], onDelete: SetNull)
|
|
75
|
+
treatmentPlan TreatmentPlan? @relation(fields: [photoset_treatment_plan_id], references: [plan_id], onDelete: SetNull)
|
|
76
|
+
takenBy User? @relation("PhotosTakenBy", fields: [photoset_taken_by], references: [user_id], onDelete: SetNull)
|
|
77
|
+
photos PatientPhoto[]
|
|
78
|
+
|
|
79
|
+
@@index([photoset_patient_id, photoset_taken_at(sort: Desc)])
|
|
80
|
+
@@index([photoset_treatment_plan_id])
|
|
81
|
+
@@index([photoset_tenant_id, photoset_type])
|
|
82
|
+
@@map("patient_photo_sets")
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Columns:**
|
|
87
|
+
|
|
88
|
+
| Column | Type | Required | Default | Description |
|
|
89
|
+
|--------|------|----------|---------|-------------|
|
|
90
|
+
| `photoset_id` | UUID | Yes | `uuid()` | Primary key |
|
|
91
|
+
| `photoset_patient_id` | UUID | Yes | -- | FK to `patients`. The patient these photos belong to |
|
|
92
|
+
| `photoset_tenant_id` | UUID | Yes | -- | FK to `tenants`. Tenant isolation |
|
|
93
|
+
| `photoset_clinic_id` | UUID | No | `null` | FK to `clinics`. Which clinic took the photos |
|
|
94
|
+
| `photoset_treatment_plan_id` | UUID | No | `null` | FK to `treatment_plans`. Optional link to treatment plan |
|
|
95
|
+
| `photoset_type` | String | Yes | -- | Photo set type: `before`, `after_1week`, `after_1month`, `after_3months`, `progress`, `other` |
|
|
96
|
+
| `photoset_label` | String | Yes | `""` | Free-form label for custom naming. E.g., "Pre-op", "6 ay sonrasi", "Kontrol 2" |
|
|
97
|
+
| `photoset_taken_at` | DateTime | Yes | `now()` | When the photos were physically taken (not when uploaded) |
|
|
98
|
+
| `photoset_taken_by` | UUID | No | `null` | FK to `users`. Staff member who took the photos |
|
|
99
|
+
| `photoset_notes` | String | Yes | `""` | Free-form notes about this photo set |
|
|
100
|
+
| `photoset_created_at` | DateTime | Yes | `now()` | Record creation timestamp |
|
|
101
|
+
| `photoset_updated_at` | DateTime | Yes | auto | Automatically updated on every write |
|
|
102
|
+
|
|
103
|
+
**Indexes:**
|
|
104
|
+
|
|
105
|
+
| Index | Columns | Purpose |
|
|
106
|
+
|-------|---------|---------|
|
|
107
|
+
| Primary | `photoset_id` | PK lookup |
|
|
108
|
+
| `idx_photosets_patient_date` | `(photoset_patient_id, photoset_taken_at DESC)` | Patient photo timeline, newest first |
|
|
109
|
+
| `idx_photosets_treatment` | `photoset_treatment_plan_id` | List all photo sets for a treatment plan |
|
|
110
|
+
| `idx_photosets_tenant_type` | `(photoset_tenant_id, photoset_type)` | Filter by type within a tenant |
|
|
111
|
+
|
|
112
|
+
**Relations:**
|
|
113
|
+
|
|
114
|
+
| Direction | Target | FK Column | Description |
|
|
115
|
+
|-----------|--------|-----------|-------------|
|
|
116
|
+
| belongs_to | patients | `photoset_patient_id` | Parent patient (cascade delete) |
|
|
117
|
+
| belongs_to | tenants | `photoset_tenant_id` | Tenant isolation (cascade delete) |
|
|
118
|
+
| belongs_to | clinics | `photoset_clinic_id` | Clinic that took the photos (nullable, set null on delete) |
|
|
119
|
+
| belongs_to | treatment_plans | `photoset_treatment_plan_id` | Linked treatment plan (nullable, set null on delete) |
|
|
120
|
+
| belongs_to | users (PhotosTakenBy) | `photoset_taken_by` | Staff who took photos (nullable, set null on delete) |
|
|
121
|
+
| has_many | patient_photos | -- | Individual photos in this set |
|
|
122
|
+
|
|
123
|
+
### 2.2 patient_photos
|
|
124
|
+
|
|
125
|
+
**Purpose:** An individual image within a photo set. Stores the MinIO key for the original file and its thumbnail, plus metadata like angle and sort order.
|
|
126
|
+
|
|
127
|
+
```prisma
|
|
128
|
+
model PatientPhoto {
|
|
129
|
+
photo_id String @id @default(uuid())
|
|
130
|
+
photo_set_id String
|
|
131
|
+
photo_angle String @default("")
|
|
132
|
+
photo_media_key String
|
|
133
|
+
photo_thumbnail_key String?
|
|
134
|
+
photo_caption String @default("")
|
|
135
|
+
photo_sort_order Int @default(0)
|
|
136
|
+
photo_created_at DateTime @default(now())
|
|
137
|
+
|
|
138
|
+
photoSet PatientPhotoSet @relation(fields: [photo_set_id], references: [photoset_id], onDelete: Cascade)
|
|
139
|
+
|
|
140
|
+
@@index([photo_set_id, photo_sort_order])
|
|
141
|
+
@@map("patient_photos")
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Columns:**
|
|
146
|
+
|
|
147
|
+
| Column | Type | Required | Default | Description |
|
|
148
|
+
|--------|------|----------|---------|-------------|
|
|
149
|
+
| `photo_id` | UUID | Yes | `uuid()` | Primary key |
|
|
150
|
+
| `photo_set_id` | UUID | Yes | -- | FK to `patient_photo_sets`. Parent set |
|
|
151
|
+
| `photo_angle` | String | Yes | `""` | Standardized angle: `front`, `left`, `right`, `top`, `bottom`, `smile`, `closeup`, `other` |
|
|
152
|
+
| `photo_media_key` | String | Yes | -- | MinIO object key for the original image |
|
|
153
|
+
| `photo_thumbnail_key` | String | No | `null` | MinIO object key for the thumbnail (generated on upload) |
|
|
154
|
+
| `photo_caption` | String | Yes | `""` | Optional caption for this specific photo |
|
|
155
|
+
| `photo_sort_order` | Int | Yes | `0` | Display order within the set |
|
|
156
|
+
| `photo_created_at` | DateTime | Yes | `now()` | Record creation timestamp |
|
|
157
|
+
|
|
158
|
+
**Indexes:**
|
|
159
|
+
|
|
160
|
+
| Index | Columns | Purpose |
|
|
161
|
+
|-------|---------|---------|
|
|
162
|
+
| Primary | `photo_id` | PK lookup |
|
|
163
|
+
| `idx_photos_set_order` | `(photo_set_id, photo_sort_order)` | Photos within a set, sorted for display |
|
|
164
|
+
|
|
165
|
+
**Relations:**
|
|
166
|
+
|
|
167
|
+
| Direction | Target | FK Column | Description |
|
|
168
|
+
|-----------|--------|-----------|-------------|
|
|
169
|
+
| belongs_to | patient_photo_sets | `photo_set_id` | Parent set (cascade delete -- deleting a set removes all photos) |
|
|
170
|
+
|
|
171
|
+
### 2.3 Design Decisions
|
|
172
|
+
|
|
173
|
+
- **Two tables (set + photos):** A photo set is a logical group taken at a point in time. Individual photos have their own metadata (angle, sort order, caption). This separation enables comparison grids: match "before front" with "after front" across sets.
|
|
174
|
+
- **`photoset_type` is a String, not a Prisma enum:** Clinics may need custom types beyond the standard set. A string avoids database migrations for new types. Validation happens at the application layer.
|
|
175
|
+
- **`photoset_taken_at` is separate from `created_at`:** Photos are often taken on a device and uploaded later. The taken date is the medically relevant timestamp, not the upload date.
|
|
176
|
+
- **`photoset_treatment_plan_id` is optional:** Photos can exist without a treatment plan. Consultation photos are often taken before a treatment plan exists.
|
|
177
|
+
- **`photo_angle` standardizes positioning:** The frontend can align "front" photos from a before set and an after set side by side. Without standardized angles, comparison views would require manual matching.
|
|
178
|
+
- **Cascade delete from set to photos:** A photo set and its photos are a unit. Deleting the set always deletes the photos. No orphaned photo records.
|
|
179
|
+
- **Cascade delete from patient to sets:** When a patient is deleted (KVKK), all their photo sets are automatically removed from the database. MinIO cleanup is a separate step.
|
|
180
|
+
- **`photo_thumbnail_key` is nullable:** The thumbnail is generated asynchronously on upload. If generation fails, the original image is still available.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 3. MinIO Storage
|
|
185
|
+
|
|
186
|
+
All patient photos are stored in MinIO. The database stores only the object key (a string). See [18-FILE-STORAGE.md](18-FILE-STORAGE.md) for MinIO infrastructure details.
|
|
187
|
+
|
|
188
|
+
### 3.1 Path Pattern
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
{tenantId}/patients/{patientId}/photos/{photosetId}/{photoId}.{ext}
|
|
192
|
+
{tenantId}/patients/{patientId}/photos/{photosetId}/{photoId}_thumb.{ext}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Example:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
abc-tenant-123/patients/patient-456/photos/set-789/photo-001.jpg
|
|
199
|
+
abc-tenant-123/patients/patient-456/photos/set-789/photo-001_thumb.jpg
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 3.2 Access Control
|
|
203
|
+
|
|
204
|
+
- All files served via pre-signed URLs with a 1-hour TTL. No public access.
|
|
205
|
+
- Tenant isolation enforced at the application layer: all keys start with `{tenantId}/`.
|
|
206
|
+
- Server-side encryption (SSE-S3) applied transparently by MinIO.
|
|
207
|
+
|
|
208
|
+
### 3.3 Thumbnail Generation
|
|
209
|
+
|
|
210
|
+
Thumbnails are generated server-side on upload using `sharp`:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import sharp from 'sharp';
|
|
214
|
+
|
|
215
|
+
const thumbnail = await sharp(originalBuffer)
|
|
216
|
+
.resize({ width: 400, withoutEnlargement: true })
|
|
217
|
+
.jpeg({ quality: 80 })
|
|
218
|
+
.toBuffer();
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
- Width: 400px (height auto-scaled to preserve aspect ratio)
|
|
222
|
+
- Format: JPEG at 80% quality regardless of original format
|
|
223
|
+
- `withoutEnlargement: true` prevents upscaling small images
|
|
224
|
+
- Thumbnails are used in list views and grid previews to avoid loading full-resolution images
|
|
225
|
+
|
|
226
|
+
### 3.4 KVKK Deletion
|
|
227
|
+
|
|
228
|
+
Patient photos are medical images (PHI). On KVKK data deletion or patient hard delete:
|
|
229
|
+
|
|
230
|
+
1. Cascade delete removes all `PatientPhoto` and `PatientPhotoSet` records from PostgreSQL
|
|
231
|
+
2. MinIO cleanup removes all objects under the patient photos prefix:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
await this.minioService.removeObjects(
|
|
235
|
+
`${tenantId}/patients/${patientId}/photos/`
|
|
236
|
+
);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
This is added to the existing KVKK deletion workflow alongside WhatsApp media and other patient data.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 4. Comparison View
|
|
244
|
+
|
|
245
|
+
The primary value of structured photo sets is the before/after comparison grid on the patient detail page.
|
|
246
|
+
|
|
247
|
+
### 4.1 Query Flow
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
Frontend: GET /patients/:id/photo-sets?treatmentPlanId=xxx
|
|
251
|
+
|
|
|
252
|
+
v
|
|
253
|
+
Backend returns sets sorted by taken_at, each containing photos sorted by sort_order
|
|
254
|
+
|
|
|
255
|
+
v
|
|
256
|
+
Frontend groups sets by type:
|
|
257
|
+
- before
|
|
258
|
+
- after_1week
|
|
259
|
+
- after_1month
|
|
260
|
+
- after_3months
|
|
261
|
+
- progress
|
|
262
|
+
|
|
|
263
|
+
v
|
|
264
|
+
Within each type pair (e.g., before + after_1month),
|
|
265
|
+
match photos by angle (front-to-front, left-to-left)
|
|
266
|
+
|
|
|
267
|
+
v
|
|
268
|
+
Display in comparison grid or slider
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 4.2 Angle Matching
|
|
272
|
+
|
|
273
|
+
The frontend matches photos across sets using the `photo_angle` field:
|
|
274
|
+
|
|
275
|
+
| Before Set | After Set | Result |
|
|
276
|
+
|-----------|-----------|--------|
|
|
277
|
+
| front | front | Side-by-side comparison |
|
|
278
|
+
| left | left | Side-by-side comparison |
|
|
279
|
+
| smile | smile | Side-by-side comparison |
|
|
280
|
+
| closeup | (no match) | Shown alone |
|
|
281
|
+
|
|
282
|
+
Photos without a matching angle in the other set are displayed separately. The comparison view does not require every angle to be present in both sets.
|
|
283
|
+
|
|
284
|
+
### 4.3 API Response Shape
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// GET /patients/:id/photo-sets?treatmentPlanId=xxx
|
|
288
|
+
{
|
|
289
|
+
data: [
|
|
290
|
+
{
|
|
291
|
+
photoset_id: "set-001",
|
|
292
|
+
photoset_type: "before",
|
|
293
|
+
photoset_label: "Ilk muayene",
|
|
294
|
+
photoset_taken_at: "2026-03-15T10:00:00Z",
|
|
295
|
+
photoset_notes: "",
|
|
296
|
+
photos: [
|
|
297
|
+
{
|
|
298
|
+
photo_id: "photo-001",
|
|
299
|
+
photo_angle: "front",
|
|
300
|
+
photo_url: "https://minio.../signed-url", // pre-signed GET URL
|
|
301
|
+
photo_thumbnail_url: "https://minio.../signed-url", // thumbnail signed URL
|
|
302
|
+
photo_caption: "",
|
|
303
|
+
photo_sort_order: 0
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
photo_id: "photo-002",
|
|
307
|
+
photo_angle: "left",
|
|
308
|
+
photo_url: "https://minio.../signed-url",
|
|
309
|
+
photo_thumbnail_url: "https://minio.../signed-url",
|
|
310
|
+
photo_caption: "",
|
|
311
|
+
photo_sort_order: 1
|
|
312
|
+
}
|
|
313
|
+
]
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
photoset_id: "set-002",
|
|
317
|
+
photoset_type: "after_1month",
|
|
318
|
+
photoset_label: "1 ay sonra",
|
|
319
|
+
photoset_taken_at: "2026-04-15T10:00:00Z",
|
|
320
|
+
photos: [ ... ]
|
|
321
|
+
}
|
|
322
|
+
],
|
|
323
|
+
total: 2
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
The backend resolves MinIO keys to signed URLs before returning the response. The frontend never sees raw MinIO keys.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## 5. Upload Flow
|
|
332
|
+
|
|
333
|
+
### 5.1 Step-by-Step
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
Staff opens patient detail -> Photos tab -> "Add Photo Set"
|
|
337
|
+
|
|
|
338
|
+
v
|
|
339
|
+
1. Staff selects type (before / after_1week / after_1month / after_3months / progress / other)
|
|
340
|
+
Optionally links a treatment plan
|
|
341
|
+
Sets taken_at date (defaults to now)
|
|
342
|
+
|
|
|
343
|
+
v
|
|
344
|
+
2. POST /patients/:id/photo-sets
|
|
345
|
+
Body: { type, label?, treatment_plan_id?, taken_at?, notes? }
|
|
346
|
+
Returns: { photoset_id, ... }
|
|
347
|
+
|
|
|
348
|
+
v
|
|
349
|
+
3. Staff uploads images (drag & drop or file picker, multiple at once)
|
|
350
|
+
For each image:
|
|
351
|
+
|
|
|
352
|
+
v
|
|
353
|
+
a. Frontend sends file to POST /patients/:id/photo-sets/:setId/photos (multipart/form-data)
|
|
354
|
+
|
|
|
355
|
+
v
|
|
356
|
+
b. Backend validates file (type: JPEG/PNG/WEBP, max size: 20MB)
|
|
357
|
+
|
|
|
358
|
+
v
|
|
359
|
+
c. Backend uploads original to MinIO:
|
|
360
|
+
Key: {tenantId}/patients/{patientId}/photos/{setId}/{photoId}.{ext}
|
|
361
|
+
|
|
|
362
|
+
v
|
|
363
|
+
d. Backend generates thumbnail (sharp, 400px width, JPEG 80%)
|
|
364
|
+
|
|
|
365
|
+
v
|
|
366
|
+
e. Backend uploads thumbnail to MinIO:
|
|
367
|
+
Key: {tenantId}/patients/{patientId}/photos/{setId}/{photoId}_thumb.{ext}
|
|
368
|
+
|
|
|
369
|
+
v
|
|
370
|
+
f. Backend creates PatientPhoto record with media_key and thumbnail_key
|
|
371
|
+
|
|
|
372
|
+
v
|
|
373
|
+
g. Returns photo record with signed URLs
|
|
374
|
+
|
|
|
375
|
+
v
|
|
376
|
+
4. Staff optionally sets angle and caption per photo via:
|
|
377
|
+
PUT /patients/:id/photo-sets/:setId/photos/:photoId
|
|
378
|
+
|
|
|
379
|
+
v
|
|
380
|
+
5. Done. Photos are immediately visible on the patient detail page.
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 5.2 File Validation
|
|
384
|
+
|
|
385
|
+
| Check | Rule | Error |
|
|
386
|
+
|-------|------|-------|
|
|
387
|
+
| MIME type | `image/jpeg`, `image/png`, `image/webp` only | 400: Unsupported file type |
|
|
388
|
+
| File size | Maximum 20 MB per image | 400: File too large |
|
|
389
|
+
| File count | Maximum 20 photos per set | 400: Too many photos in set |
|
|
390
|
+
|
|
391
|
+
HEIC files (common from iPhones) are converted to JPEG server-side using `sharp` before storage.
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## 6. Operator Workflow Integration
|
|
396
|
+
|
|
397
|
+
The existing operator workflow (see [05-OPERATOR-WORKFLOW.md](05-OPERATOR-WORKFLOW.md)) forwards patient photos from WhatsApp to a doctor via the `forward_to_operator` tool. These are unstructured media messages in a chat context.
|
|
398
|
+
|
|
399
|
+
The before/after photo system is separate and structured -- it is clinic-managed documentation, not chat media.
|
|
400
|
+
|
|
401
|
+
**Future enhancement:** When the operator workflow forwards patient photos to a doctor, those WhatsApp media images could optionally be saved as a patient photo set automatically. This would bridge the gap between chat-originated media and structured patient records. For now, the two systems are independent.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## 7. API Endpoints
|
|
406
|
+
|
|
407
|
+
All endpoints are nested under `/patients/:id` and require the patient to belong to the current user's tenant and accessible clinics.
|
|
408
|
+
|
|
409
|
+
| Method | Path | Permission | Description |
|
|
410
|
+
|--------|------|------------|-------------|
|
|
411
|
+
| GET | `/patients/:id/photo-sets` | `patients:read` | List photo sets for a patient. Filterable by `type` and `treatmentPlanId`. Returns sets with nested photos (signed URLs). Sorted by `taken_at` descending |
|
|
412
|
+
| POST | `/patients/:id/photo-sets` | `patients:update` | Create a new photo set (metadata only, no files). Body: `{ type, label?, treatment_plan_id?, taken_at?, taken_by?, notes? }` |
|
|
413
|
+
| GET | `/patients/:id/photo-sets/:setId` | `patients:read` | Single photo set with all photos (signed URLs) |
|
|
414
|
+
| PUT | `/patients/:id/photo-sets/:setId` | `patients:update` | Update set metadata: type, label, notes, taken_at, treatment_plan_id |
|
|
415
|
+
| DELETE | `/patients/:id/photo-sets/:setId` | `patients:update` | Delete set + all photos. Removes MinIO objects and database records |
|
|
416
|
+
| POST | `/patients/:id/photo-sets/:setId/photos` | `patients:update` | Upload a photo to a set. Multipart form data with single file. Returns photo record with signed URLs |
|
|
417
|
+
| PUT | `/patients/:id/photo-sets/:setId/photos/:photoId` | `patients:update` | Update photo metadata: angle, caption, sort_order |
|
|
418
|
+
| DELETE | `/patients/:id/photo-sets/:setId/photos/:photoId` | `patients:update` | Delete a single photo. Removes original + thumbnail from MinIO |
|
|
419
|
+
|
|
420
|
+
### Query Parameters for GET `/patients/:id/photo-sets`
|
|
421
|
+
|
|
422
|
+
| Parameter | Type | Description |
|
|
423
|
+
|-----------|------|-------------|
|
|
424
|
+
| `type` | String | Filter by set type: `before`, `after_1week`, `after_1month`, `after_3months`, `progress`, `other` |
|
|
425
|
+
| `treatmentPlanId` | UUID | Filter by linked treatment plan |
|
|
426
|
+
| `page` | Int | Page number (default 1) |
|
|
427
|
+
| `limit` | Int | Items per page (default 50) |
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## 8. Permissions
|
|
432
|
+
|
|
433
|
+
Photo management uses existing patient permissions. No separate photo permission is needed.
|
|
434
|
+
|
|
435
|
+
| Permission | Photo Operations |
|
|
436
|
+
|------------|-----------------|
|
|
437
|
+
| `patients:read` | View photo sets, view individual photos (signed URLs) |
|
|
438
|
+
| `patients:update` | Create/update/delete photo sets, upload/update/delete photos |
|
|
439
|
+
|
|
440
|
+
**Rationale:** Photos are patient data. If you can view a patient, you can view their photos. If you can update a patient, you can manage their photos. Adding a separate `photos:*` permission would complicate the permission model without meaningful access control benefit -- anyone working with a patient's clinical data needs to see their photos.
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## 9. NestJS Module Structure
|
|
445
|
+
|
|
446
|
+
Photo management is part of the `PatientsModule`, not a separate module. Photos are tightly coupled to patients.
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
src/patients/
|
|
450
|
+
patients.module.ts # Imports MinioModule, registers photo service
|
|
451
|
+
patients.controller.ts # Patient CRUD endpoints
|
|
452
|
+
photo-sets.controller.ts # Photo set + photo endpoints (nested under /patients/:id)
|
|
453
|
+
photo-sets.service.ts # Photo set CRUD, photo upload, thumbnail generation, MinIO operations
|
|
454
|
+
dto/
|
|
455
|
+
create-photo-set.dto.ts # { type, label?, treatment_plan_id?, taken_at?, taken_by?, notes? }
|
|
456
|
+
update-photo-set.dto.ts # Partial of create
|
|
457
|
+
update-photo.dto.ts # { angle?, caption?, sort_order? }
|
|
458
|
+
photo-set-query.dto.ts # { type?, treatmentPlanId?, page?, limit? }
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Service Responsibilities
|
|
462
|
+
|
|
463
|
+
`PhotoSetsService` handles:
|
|
464
|
+
|
|
465
|
+
1. **Photo set CRUD** -- create, read, update, delete sets with tenant scoping
|
|
466
|
+
2. **Photo upload** -- accept multipart file, validate, upload to MinIO, generate thumbnail, create record
|
|
467
|
+
3. **Signed URL resolution** -- convert MinIO keys to pre-signed URLs when returning photo data
|
|
468
|
+
4. **Photo metadata updates** -- angle, caption, sort order
|
|
469
|
+
5. **MinIO cleanup** -- delete objects when photos or sets are removed
|
|
470
|
+
6. **KVKK support** -- bulk delete all photos for a patient (called by KVKK deletion workflow)
|
|
471
|
+
|
|
472
|
+
### Dependencies
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
@Module({
|
|
476
|
+
imports: [MinioModule], // For file storage
|
|
477
|
+
controllers: [PatientsController, PhotoSetsController],
|
|
478
|
+
providers: [PatientsService, PhotoSetsService],
|
|
479
|
+
exports: [PatientsService, PhotoSetsService],
|
|
480
|
+
})
|
|
481
|
+
export class PatientsModule {}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## 10. KVKK Considerations
|
|
487
|
+
|
|
488
|
+
Patient photos are medical images and classified as Personal Health Information (PHI) under KVKK (Turkish data protection law).
|
|
489
|
+
|
|
490
|
+
### What Must Be Deleted
|
|
491
|
+
|
|
492
|
+
When a KVKK data deletion request is executed for a patient:
|
|
493
|
+
|
|
494
|
+
| Data | Location | Deletion Method |
|
|
495
|
+
|------|----------|-----------------|
|
|
496
|
+
| `PatientPhotoSet` records | PostgreSQL | Cascade delete from patient |
|
|
497
|
+
| `PatientPhoto` records | PostgreSQL | Cascade delete from photo set |
|
|
498
|
+
| Original images | MinIO | `removeObjects({tenantId}/patients/{patientId}/photos/)` |
|
|
499
|
+
| Thumbnails | MinIO | Same prefix removal (thumbnails are in the same directory) |
|
|
500
|
+
|
|
501
|
+
### Integration with KVKK Workflow
|
|
502
|
+
|
|
503
|
+
The existing KVKK deletion workflow runs these steps. Patient photos are added as an additional cleanup step:
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
// In KVKK deletion handler:
|
|
507
|
+
async deletePatientData(tenantId: string, patientId: string) {
|
|
508
|
+
// ... existing deletion steps ...
|
|
509
|
+
|
|
510
|
+
// Delete patient photos from MinIO
|
|
511
|
+
await this.minioService.removeObjects(
|
|
512
|
+
`${tenantId}/patients/${patientId}/photos/`
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
// PostgreSQL records deleted via cascade when patient record is removed
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
No separate audit trail is needed for photo deletion -- the KVKK deletion audit log covers the entire patient data removal.
|