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
- Environment switching bug - Switching from dev to prod doesn't reload data
- Default environment - Should default to prod, not dev
- Call organization - Flat list doesn't scale; need hierarchical grouping
- 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
┌──────────┬────────────┬────────────┬─────────────────────────────┐
│ 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