Commit Graph

20 Commits

Author SHA1 Message Date
34e053204f feat(leads): sidecar polling service for auto-assigning unassigned leads
Replaces the untrusted platform function path (SDK's lead-auto-assign
was written but never deployed to either workspace — all leads created
after seeding are orphan).

Polls every 60s:
  1. Fetch up to 100 unassigned leads (assignedAgent empty or null)
  2. Fetch platform Agents whose live SupervisorService state is
     ready/calling/in-call/acw (skip offline/break/training/unknown)
  3. Build open-lead count per agent (single paginated query)
  4. Assign each unassigned lead to the least-loaded active agent —
     writes agent.name into lead.assignedAgent to match the worklist
     filter (assignedAgent: { eq: agentName })

Catches every lead-creation path: CSV import, enquiry form,
missed-call webhook, widget, livekit. No platform changes needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:23:53 +05:30
dbefa9675a feat: master data endpoint — cached departments, doctors, clinics
Redis-cached (5min TTL) lookups via /api/masterdata/departments,
/api/masterdata/doctors, /api/masterdata/clinics. Warms cache on
startup. Frontend dropdowns use these instead of hardcoded lists.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:31:01 +05:30
9f5935e417 feat: telephony dispatcher registration — sidecar self-registers on boot
Adds TelephonyRegistrationService that:
1. On startup: queries platform for agent list, registers with the
   telephony dispatcher at TELEPHONY_DISPATCHER_URL
2. Every 30s: sends heartbeat to keep registration alive (90s TTL)
3. On shutdown: deregisters (best-effort, TTL cleans up anyway)
4. On heartbeat failure: auto re-registers

Env vars:
  TELEPHONY_DISPATCHER_URL — where to register (outbound to dispatcher)
  TELEPHONY_CALLBACK_URL — where events come back (inbound to sidecar)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:08:30 +05:30
695f119c2b feat: team module, multi-stage Dockerfile, doctor utils, AI config overhaul
- Team module: POST /api/team/members (in-place employee creation with
  temp password + Redis cache), PUT /api/team/members/:id, GET temp
  password endpoint. Uses signUpInWorkspace — no email invites.
- Dockerfile: rewritten as multi-stage build (builder + runtime) so
  native modules compile for target arch. Fixes darwin→linux crash.
- .dockerignore: exclude dist, node_modules, .env, .git, data/
- package-lock.json: regenerated against public npmjs.org (was
  pointing at localhost:4873 Verdaccio — broke docker builds)
- Doctor utils: shared DOCTOR_VISIT_SLOTS_FRAGMENT + normalizeDoctors
  helper for visit-slot-aware queries across 6 consumers
- AI config: full admin CRUD (GET/PUT/POST reset), workspace-scoped
  setup-state with workspace ID isolation, AI prompt defaults overhaul
- Agent config: camelCase field fix for SDK-synced workspaces
- Session service: workspace-scoped Redis key prefixing for setup state
- Recordings/supervisor/widget services: updated to use doctor-utils
  shared fragments instead of inline visitingHours queries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 08:37:58 +05:30
76fa6f51de feat: website widget + omnichannel lead webhooks
Widget (embeddable):
- Preact + Vite library mode → 35KB IIFE bundle served from sidecar
- Shadow DOM for CSS isolation, themed from sidecar theme API
- AI chatbot (streaming), appointment booking (4-step wizard), lead capture form
- FontAwesome Pro duotone SVGs bundled as inline strings
- HMAC-signed site keys (Redis storage, origin validation)
- Captcha guard (Cloudflare Turnstile ready)

Sidecar endpoints:
- GET/PUT/DELETE /api/widget/keys/* — site key management
- GET /api/widget/init — theme + config (key-gated)
- GET /api/widget/doctors, /slots — doctor list + availability
- POST /api/widget/book — appointment booking (captcha-gated)
- POST /api/widget/lead — lead capture (captcha-gated)

Omnichannel webhooks:
- POST /api/webhook/facebook — Meta Lead Ads (verification + lead ingestion)
- POST /api/webhook/google — Google Ads lead form extension
- POST /api/webhook/whatsapp — Ozonetel WhatsApp callback (receiver ready)
- POST /api/webhook/sms — Ozonetel SMS callback (receiver ready)

Infrastructure:
- SessionService.setCachePersistent() for non-expiring Redis keys
- Static file serving from /public (widget.js)
- WidgetModule registered in AppModule

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 06:49:02 +05:30
8cc1bdc812 feat: theme config service — REST API with versioning + backup
- ThemeService: read/write/validate theme.json, auto-backup on save
- ThemeController: GET/PUT/POST /api/config/theme (public GET, versioned PUT)
- ThemeConfig type with version + updatedAt fields
- Default theme: Global Hospital blue scale
- ConfigThemeModule registered in AppModule

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:50:51 +05:30
b8556cf440 feat: rules engine — json-rules-engine integration with worklist scoring
- Self-contained NestJS module: types, storage (Redis+JSON), fact providers, action handlers
- PriorityConfig CRUD (slider values for task weights, campaign weights, source weights)
- Score action handler with SLA multiplier + campaign multiplier formula
- Worklist consumer: scores and ranks items before returning
- Hospital starter template (7 rules)
- REST API: /api/rules/* (CRUD, priority-config, evaluate, templates)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 16:59:10 +05:30
3e2e7372cc feat: event bus with Redpanda + AI insight consumer
- EventBusService: Kafka/Redpanda pub/sub with kafkajs, graceful fallback when broker unavailable
- Topics: call.completed, call.missed, agent.state
- AiInsightConsumer: on call.completed, fetches lead activity → OpenAI generates summary + suggested action → updates Lead entity on platform
- Disposition endpoint emits call.completed event after Ozonetel dispose
- EventsModule registered as @Global for cross-module injection
- Redpanda container added to VPS docker-compose
- Docker image rebuilt for linux/amd64 with kafkajs dependency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 09:38:02 +05:30
fcc7c90e84 feat: recording analysis module with Deepgram + AI insights + Redis cache
- RecordingsModule: POST /api/recordings/analyze
- Deepgram pre-recorded API: diarize, summarize, topics, sentiment, utterances
- AI insights via OpenAI generateObject: call outcome, coaching, compliance, satisfaction
- Redis cache: 7-day TTL per callId, check before hitting Deepgram/OpenAI
- Generic getCache/setCache added to SessionService for cross-module use

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 09:20:15 +05:30
eb4000961f feat: SSE agent state, maint module, timestamp fix, missed call lead lookup
- SSE agent state stream: supervisor maintains state map from Ozonetel webhooks, streams via /api/supervisor/agent-state/stream
- Force-logout via SSE: distinct force-logout event type avoids conflict with normal login cycle
- Maint module (/api/maint): OTP-guarded endpoints for force-ready, unlock-agent, backfill-missed-calls, fix-timestamps
- Fix Ozonetel IST→UTC timestamp conversion: istToUtc() in webhook controller and missed-queue service
- Missed call lead lookup: ingestion queries leads by phone, stores leadId + leadName on Call entity
- Timestamp backfill endpoint: throttled at 700ms/mutation, idempotent (skips already-fixed records)
- Structured logging: full JSON payloads for agent/call webhooks, [DISPOSE] trace with agentId
- Fix dead code: agent-state endpoint auto-assign was after return statement
- Export SupervisorService for cross-module injection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:04:31 +05:30
2e4f97ff1a feat: supervisor module — team performance + active calls endpoints
- SupervisorService: aggregates Ozonetel agent summary across all agents,
  tracks active calls from real-time events
- GET /api/supervisor/team-performance — per-agent time breakdown + thresholds
- GET /api/supervisor/active-calls — current active call map
- POST /api/supervisor/call-event — Ozonetel event webhook
- POST /api/supervisor/agent-event — Ozonetel agent event webhook

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 13:53:49 +05:30
4963a698d9 feat: agent state endpoint + search module
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:21:40 +05:30
bbf77ed0e9 feat: call control, recording, CDR, missed calls, live call assist
- Call Control API (CONFERENCE/HOLD/MUTE/KICK_CALL)
- Recording pause/unpause
- Fetch CDR Detailed (call history with recordings)
- Abandon Calls (missed calls from Ozonetel)
- Call Assist WebSocket gateway (Deepgram STT + OpenAI suggestions)
- Call Assist service (lead context loading)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 10:36:35 +05:30
6f7d408724 feat: add worklist engine with prioritized missed calls, follow-ups, and leads 2026-03-18 11:26:04 +05:30
a42d479f06 feat: wire sidecar to platform — auth proxy with workspace subdomain, GraphQL proxy, health check 2026-03-18 07:15:47 +05:30
3e0d9a4351 feat: add auth proxy controller for login and token exchange
Adds POST /auth/login and POST /auth/tokens endpoints that proxy
GraphQL mutations to the fortytwo-eap-core platform, letting the
frontend use only the sidecar URL for authentication.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 09:08:07 +05:30
702afabfa7 feat: add AI enrichment service with Claude Haiku and rule-based fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 09:04:45 +05:30
30df1d0158 feat: add Exotel webhook controller and service for call event parsing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 09:04:15 +05:30
5b35c65e6e feat: add Platform GraphQL client service for lead lookup and CRUD
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 09:04:00 +05:30
a3172140b0 chore: scaffold NestJS sidecar with config, CORS, and dependency setup 2026-03-17 09:02:15 +05:30