Commit Graph

10 Commits

Author SHA1 Message Date
60d2329dd8 fix(call-attribution): resolve Ozonetel chain AgentNames to agent.id
Inbound transferred calls arrive with AgentName like 'RamaiahAdmin -> GlobalHealthX'. The webhook was persisting the raw chain string and leaving agentId null; the CDR enrichment cron then silently skipped 100% of rows because the bulk CDR keys on caller-leg UCID while the webhook stores monitorUCID — the join never matched.

- missed-call-webhook: split chain on ' -> ', take final handler,
  resolve via AgentLookupService (ozonetelAgentId + display name)
- cdr-enrichment: index CDR rows by both UCID and monitorUCID so
  the cron actually patches historical rows
- enrichment also parses chain in CDR AgentName as a second fallback
- spec: add CallerResolutionService + AgentLookupService mocks
2026-04-15 18:55:00 +05:30
846c5f4c9b feat(calls): consolidate agent identity via Ozonetel CDR
Ozonetel's webhook AgentName is a transfer-chain display string — same
display can collide (two agents both named "GlobalHealthX" with distinct
agent IDs), and chained like "RamaiahAdmin -> Ganesh Bandi -> GlobalHealthX".
Team Performance was bucketing every unique raw string as a separate
"agent", producing 7 rows for 3 real agents.

Fix — authoritative agent link via CDR AgentID (unique):

- New AgentLookupService (platform module): case-insensitive
  ozonetelAgentId → Agent UUID cache, shared across webhook / dispose /
  enrichment / backfill paths
- Webhook + outbound-dispose now persist UCID on Call so CDR can join
- Outbound dispose resolves agent relation at create time and overwrites
  from CDR AgentID post-hoc (catches dial transfers)
- New CdrEnrichmentService: every 30 min fetches today + yesterday CDR,
  patches Calls missing agentId / transferredTo / transferType by UCID
  join. Well under Ozonetel's 2 req/min cap.
- Historical backfill maint endpoint: /api/maint/enrich-call-agents
  with configurable day window (default 2, max 15). Rate-limited at 35s
  between dates.

Call schema additions (synced on Global + Ramaiah): agent relation,
ucid, transferredTo, transferType. agentName remains for legacy/display.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 07:43:28 +05:30
fbe782b5ac fix+feat: morning QA fixes, worklist pagination, misc sidecar improvements
- caller-resolution: drop cache, use indexed phone filter (lead.contactPhone.primaryPhoneNumber.like)
- worklist: externalize page size (WORKLIST_PAGE_SIZE × WORKLIST_MAX_PAGES), paginate getMissedCalls/getAssignedLeads/getPendingFollowUps
- maint: unlock-agent, force-ready, backfill-caller-resolution, clear-analysis-cache, fix-timestamps
- ozonetel agent.service: force logout+re-login on "already logged in"
- ai chat: context expansion
- livekit-agent: updates
- widget: session handling
- masterdata: clinic list cache

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 06:49:02 +05:30
96d0c32000 fix: skip outbound calls in webhook + filter abandon polls by campaign
Webhook controller now skips outbound calls (type=Manual/OutBound).
An unanswered outbound dial is NOT a missed inbound call — it was
being incorrectly created as MISSED with PENDING_CALLBACK status.

MissedQueueService now filters the Ozonetel abandonCalls API response
by campaign name (read from TelephonyConfigService). Prevents
cross-tenant ingestion when multiple sidecars share the same
Ozonetel account.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:09:17 +05:30
898ff65951 fix: camelCase field names + dial uses per-agent config
Defect 5: Worklist, missed-call-webhook, missed-queue, ai-chat, and
rules-engine all used legacy lowercase field names (callbackstatus,
callsourcenumber, missedcallcount, callbackattemptedat) from the old
VPS schema. Fixed to camelCase (callbackStatus, callSourceNumber,
missedCallCount, callbackAttemptedAt) matching the current SDK sync.

Defect 6: Dial endpoint used global defaults (OZONETEL_AGENT_ID env
var) instead of the logged-in agent's config. Now accepts agentId
and campaignName from the frontend request body. Falls back to
telephony config → DID-derived campaign name → explicit error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:29:19 +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
4b5edc4e55 fix: appointmentStatus→status, missed call visibility, webhook callbackstatus, KB logging
- Renamed appointmentStatus to status in search + call-assist queries
- Missed calls worklist: removed agentName filter (shared FIFO queue)
- Webhook sets callbackstatus: PENDING_CALLBACK on missed calls
- AI chat: added KB content logging for debugging

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 14:42:38 +05:30
58225b7943 feat: webhook field fixes, Force Ready endpoint, improved error logging
- Fix Call record field names (recording, callerNumber, durationSec)
- Add POST /api/ozonetel/agent-ready using logout+login for Force Ready
- Add callerNumber to kookoo callback
- Better error logging with response body

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:22:47 +05:30
8c0853dd19 feat: Ozonetel webhook handler — create call records from call events
- Parse Ozonetel POST payload (CallerID, Status, Duration, Recording URL)
- Create Call record in platform via API key auth
- Match caller to Lead by phone number
- Create LeadActivity timeline entry
- Update lead contactAttempts and lastContacted
- Map Ozonetel dispositions to platform enum values

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:09:54 +05:30
6f7d408724 feat: add worklist engine with prioritized missed calls, follow-ups, and leads 2026-03-18 11:26:04 +05:30