Skip to content

Call Debugger Dashboard Improvements

Linear Ticket: ARE-1557 Date: 2026-02-04 Status: Design Complete

Overview

Redesign the call debugger dashboard to organize calls by org/location hierarchy (prod) or agent (dev), with improved navigation and search.

Problems Addressed

  1. Environment switching bug - Switching from dev to prod doesn't reload data
  2. Default environment - Should default to prod, not dev
  3. Call organization - Flat list doesn't scale; need hierarchical grouping
  4. Navigation - Need easier day-to-day navigation and search

Architecture

Two Parallel Data Paths

┌─────────────────────────────────────────────────────────────────┐
│                         Frontend                                 │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │  CallsLandingPage (Multi-sidebar layout)                  │   │
│  │  ├─ DayNavigator (← Feb 4, 2026 →)                       │   │
│  │  ├─ OrgSidebar (fuzzy search + list)      [prod]         │   │
│  │  ├─ LocationSidebar (fuzzy search + list) [prod]         │   │
│  │  ├─ AgentSidebar (fuzzy search + list)    [dev]          │   │
│  │  ├─ CallsSidebar (search + paginated list)               │   │
│  │  └─ Debugger (full-width when call selected)             │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
           ┌──────────────────┴──────────────────┐
           ▼                                      ▼
┌───────────────────────┐            ┌───────────────────────┐
│  /api/debug/db/*      │            │  /api/debug/s3/*      │
│  (Hyperdrive + MySQL) │            │  (S3 ListObjects)     │
│  60s query cache      │            │                       │
└───────────────────────┘            └───────────────────────┘

API Endpoints

Prod (database):

Endpoint Purpose
GET /api/debug/db/index?date= Get org→location hierarchy with call counts
GET /api/debug/db/locations/:olid/calls?date=&offset=&limit= Get paginated calls for a location

Dev (S3):

Endpoint Purpose
GET /api/debug/s3/index?date= Get flat list of calls (grouped by agent_id client-side)

UI Design

Multi-Sidebar Layout (Browse Mode)

┌──────────┬────────────┬────────────┬─────────────────────────────┐
│  Orgs    │  Locations │  Calls     │  (empty or preview)         │
│ [search] │  [search]  │  [search]  │                             │
├──────────┼────────────┼────────────┤                             │
│ ● Acme   │  Chicago   │  call_123  │                             │
│   Better │  NYC ●     │  call_456  │                             │
│   Down.. │  LA        │  call_789● │                             │
│          │  Miami     │  ...       │                             │
│          │            │  [more]    │                             │
└──────────┴────────────┴────────────┴─────────────────────────────┘
  • Each sidebar has fuse.js fuzzy search
  • Clicking an org loads its locations
  • Clicking a location loads its calls (paginated)
  • Sorted by call count descending (busiest first)

Debugger Mode (Call Selected)

┌─────────────────────────────────────────────────────────────────┐
│ ← Acme Dental > NYC HQ > call_789abc      [Feb 4, 2026] [≡]    │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [Turns] [Logs] [Waterfall] [Data]                             │
│                                                                 │
│  (full-width debugger content)                                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
  • All sidebars collapse automatically
  • Breadcrumb shows path: Org > Location > Call
  • Click or breadcrumb to return to browse mode
  • [≡] hamburger can also toggle sidebars

Day Navigation

┌─────────────────────────────────────────┐
│   [←]    Tuesday, February 4, 2026   [→] │
└─────────────────────────────────────────┘
  • Left/right arrows navigate ±1 day
  • Today is the default date

Dev Environment View

┌──────────┬────────────┬─────────────────────────────────────────┐
│  Agents  │  Calls     │  (debugger or empty)                    │
│ [search] │  [search]  │                                         │
├──────────┼────────────┤                                         │
│ ● Main   │  call_123  │                                         │
│   Test   │  call_456  │                                         │
│   Ovflw  │  call_789● │                                         │
└──────────┴────────────┴─────────────────────────────────────────┘
  • Two sidebars instead of three (no org/location hierarchy)
  • Agents displayed as "Agent Name (agent_id)"
  • Agent metadata mapping to be provided later; stub with agent_id for now

Database Queries

Query 1: Day Index (Prod)

SELECT
  o.uid AS org_id,
  o.name AS org_name,
  ol.uid AS location_id,
  ol.name AS location_name,
  COUNT(rc.retell_call_id) AS call_count
FROM retell_calls rc
JOIN calls c ON rc.arini_call_id = c.uid
JOIN org_locations ol ON c.to_id = ol.uid
JOIN orgs o ON ol.org_id = o.uid
WHERE DATE(rc.created_at) = ?
GROUP BY o.uid, o.name, ol.uid, ol.name
ORDER BY call_count DESC

Query 2: Location Calls (Prod, Paginated)

SELECT
  rc.retell_call_id AS call_id,
  rc.arini_call_id,
  rc.created_at,
  JSON_UNQUOTE(JSON_EXTRACT(rc.retell_call_details, '$.call_type')) AS direction
FROM retell_calls rc
JOIN calls c ON rc.arini_call_id = c.uid
WHERE c.to_id = ?
  AND DATE(rc.created_at) = ?
ORDER BY rc.created_at DESC
LIMIT ? OFFSET ?

Response Types

type DayIndexResponse = {
  orgs: {
    org_id: string
    org_name: string
    call_count: number
    locations: {
      location_id: string
      location_name: string
      call_count: number
    }[]
  }[]
}

type LocationCallsResponse = {
  calls: {
    call_id: string
    arini_call_id: string
    created_at: string
    direction: 'inbound' | 'outbound' | null
  }[]
  hasMore: boolean
  total: number
}

type DevDayIndexResponse = {
  agents: {
    agent_id: string
    agent_name: string | null  // from hardcoded mapping
    calls: {
      call_id: string
      created_at: string
    }[]
  }[]
}

State Management

URL State

/debug                           → Landing, today's date, prod env
/debug?date=2026-02-04&env=dev   → Landing, specific date, dev env
/debug/call/:callId              → Debugger view (auto-resolves date/env)

React State

type DashboardState = {
  // URL-synced
  date: string              // YYYY-MM-DD
  env: 'prod' | 'dev'

  // Selection state
  selectedOrgId: string | null
  selectedLocationId: string | null  // prod only
  selectedAgentId: string | null     // dev only
  selectedCallId: string | null

  // View state
  sidebarView: 'browse' | 'debugger'

  // Search (local, not URL)
  orgSearch: string
  locationSearch: string
  callSearch: string
}

Data Fetching Hooks

// Prod
useDayIndex(date: string)  { orgs, isLoading, error }
useLocationCalls(locationId: string, date: string, page: number)  { calls, hasMore, isLoading, error }

// Dev
useDevDayIndex(date: string)  { agents, isLoading, error }

// Shared (existing)
useCallDebugger(callId: string)  unchanged

Environment Switch Behavior

  • Debounce 500ms before clearing cached data
  • Reset selection state (org/location/agent)
  • Keep current date
  • Refetch day index for new environment

Error Handling

Empty States

Scenario UI
No calls for selected day "No calls on Feb 4, 2026" with navigation arrows
No calls for location "No calls for NYC HQ on this day"
Search returns no results "No results for 'xyz'" with clear button
API error Toast notification + retry button

Loading States

Component Loading UI
Day index Skeleton cards in org sidebar
Location calls Skeleton rows in calls sidebar
Debugger Existing loading spinner

Edge Cases

Case Handling
Deep link to /debug/call/:callId Resolve date/env via lookup API, load sidebars with context
Location with 500+ calls Paginate at 50/page with "Load more"
Rapid date navigation Abort in-flight requests, debounce 200ms
User navigates away mid-load Abort controller cleanup

File Changes

New Files

File Purpose
src/worker/modules/debug/queries/dayIndex.ts Day index query (prod)
src/worker/modules/debug/queries/locationCalls.ts Location calls query (prod)
src/ui/modules/debug/components/DayNavigator.tsx Date navigation component
src/ui/modules/debug/components/OrgSidebar.tsx Org list with search
src/ui/modules/debug/components/LocationSidebar.tsx Location list with search
src/ui/modules/debug/components/CallsSidebar.tsx Calls list with search
src/ui/modules/debug/components/AgentSidebar.tsx Agent list for dev env
src/ui/modules/debug/hooks/useDayIndex.ts Fetch prod day index
src/ui/modules/debug/hooks/useLocationCalls.ts Fetch location calls
src/ui/modules/debug/hooks/useDevDayIndex.ts Fetch dev day index

Modified Files

File Changes
src/worker/modules/debug/router.ts Add new routes
src/ui/modules/debug/pages/CallsLandingPage.tsx Replace with multi-sidebar layout
src/ui/modules/debug/types/debugger.ts Add new response types

Dependencies

  • fuse.js - Fuzzy search (add if not present)

Out of Scope

  • Dev agent metadata mapping (stub with agent_id for now)
  • S3 layout optimization for better agent-based queries
  • Pre-computed materialized views for day summaries

Scale Considerations

Metric Current Near-term
Calls/day 3-5k 10-15k
Locations ~200 500-600
Calls/location 1-10 (most), 100+ (some) Same distribution
  • Hyperdrive query caching (60s TTL) handles repeated requests
  • Pagination at location and calls level for large datasets
  • Busiest locations sorted first for quick access