Dashboard
The dashboard module provides a consolidated view of organization activity. It displays KPIs and charts across calls, SMS, email, text agents, plans, AI usage, and contact engagement — all filtered by a shared time range.
Data Model
Section titled “Data Model”DashboardStats (Calls)
Section titled “DashboardStats (Calls)”pub struct DashboardStats { pub total_calls: i64, pub total_duration_secs: i64, pub avg_duration_secs: f64, pub total_todos: i64, pub call_activity: Vec<CallActivityDay>, pub call_heatmap: Vec<HeatmapCell>, pub call_heatmap_max: i64, pub recent_calls: Vec<Call>, pub todo_status_counts: Vec<TodoStatusCount>,}MessagingStats
Section titled “MessagingStats”pub struct MessagingStats { pub total_messages: u32, pub delivery_rate: f64, // 0.0–100.0 pub inbound_count: u32, pub outbound_count: u32, pub message_activity: Vec<MessageActivityBucket>, pub message_heatmap: Vec<HeatmapCell>, pub message_heatmap_max: u32, pub response_insights: ResponseInsights,}MessageActivityBucket breaks down each time bucket by channel:
pub struct MessageActivityBucket { pub date: String, // Bucket timestamp pub label: String, // Display label pub sms_count: u32, pub email_count: u32,}ResponseInsights
Section titled “ResponseInsights”Detailed response-time analytics computed from inbound→outbound message pairs:
pub struct ResponseInsights { pub avg_response_time_secs: Option<f64>, pub unanswered_count: u32, pub response_rate: f64, // 0.0–100.0 pub unresponded_by_hour: Vec<UnrespondedHourBucket>, pub by_phone: Vec<PhoneResponseBreakdown>,}
pub struct PhoneResponseBreakdown { pub phone_label: String, // Friendly name or E.164 number pub responded_count: u32, pub unanswered_count: u32, pub response_rate: f64, pub avg_response_time_secs: Option<f64>,}Response times use a single-pass algorithm: messages sorted by (contact_id, created_at), pairing each outbound with the preceding inbound for the same contact. Unpaired inbound messages count as unanswered.
TextAgentStats
Section titled “TextAgentStats”pub struct TextAgentStats { pub total_suggestions: u32, pub auto_reply_count: u32, pub auto_reply_rate: f64, // Percentage auto-sent pub avg_confidence: f64, // 0.0–1.0 pub escalation_count: u32, pub escalation_rate: f64,}PlanStats
Section titled “PlanStats”pub struct PlanStats { pub active_plans: u32, pub contacts_in_active_plans: u32, pub completion_rate: f64, // (completed / terminal) × 100 pub total_plans: u32,}Plan stats have no time-range filter — they reflect current state.
AiUsageStats
Section titled “AiUsageStats”pub struct AiUsageStats { pub total_tokens: u64, pub total_cost: f64, pub cost_by_feature: Vec<FeatureCost>, // Sorted by cost desc}
pub struct FeatureCost { pub feature: String, // Prettified feature name pub cost: f64,}EngagementStats
Section titled “EngagementStats”pub struct EngagementStats { pub active_contacts: u32, // Contacts with calls or messages pub total_contacts: u32, pub channel_distribution: ChannelDistribution, pub recent_activities: Vec<RecentActivity>, // Max 10}
pub struct ChannelDistribution { pub calls: u32, pub sms: u32, pub email: u32, pub other: u32,}
pub struct RecentActivity { pub id: Uuid, pub activity_type: ActivityType, // Call | Message pub contact_id: Option<Uuid>, pub contact_name: Option<String>, pub description: String, pub channel: String, pub created_at: String,}API Endpoints
Section titled “API Endpoints”| Method | Path | Description |
|---|---|---|
GET | /api/dashboard/stats?time_range | Call KPIs, activity chart, heatmap, recent calls, to-do counts |
GET | /api/dashboard/messaging-stats?time_range | Messaging KPIs, activity, heatmap, response insights |
GET | /api/dashboard/text-agent-stats?time_range | Text agent suggestions, auto-reply rate, confidence |
GET | /api/dashboard/plan-stats | Active plans and completion rate (no time filter) |
GET | /api/dashboard/ai-usage-stats?time_range | Token totals, cost breakdown by feature |
GET | /api/dashboard/ai-message-origin-stats?time_range | AI-composed message counts by feature — see AI Origin Tracking |
GET | /api/dashboard/engagement-stats?time_range | Active contacts, channel distribution, recent activity feed |
All endpoints require an authenticated session. Every handler calls resolve_dashboard_scope() to determine data visibility.
DashboardScope
Section titled “DashboardScope”pub enum DashboardScope { Org, Scoped { phone_ids: Vec<Uuid>, member_id: Uuid },}resolve_dashboard_scope() checks the session’s permissions in order:
- Super-admin / org owner →
DashboardScope::Org(bypass) Dashboard:Instance:ViewOrg→DashboardScope::Org(org-wide metrics, no phone filter)Dashboard:Instance:ViewOwn→DashboardScope::Scoped(filtered to the member’s assigned phones)- Neither →
403 Forbidden
Helper methods on DashboardScope:
| Method | Returns |
|---|---|
phone_ids_slice() | Option<&[Uuid]> — None for org-wide, Some for scoped |
scoped_member_id() | Option<Uuid> — the member ID for scoped users |
Client-Side Permission Check
Section titled “Client-Side Permission Check”The dashboard view uses can_view_dashboard() to gate rendering before any data loads:
pub fn can_view_dashboard(session: &ClientSession) -> bool { session.has_permission(&Permission::Dashboard( DashboardPermission::Instance(DashboardInstancePermission::ViewOrg), )) || session.has_permission(&Permission::Dashboard( DashboardPermission::Instance(DashboardInstancePermission::ViewOwn), ))}If false, the view renders an AccessDenied card instead of the dashboard content
Time Range Filtering
Section titled “Time Range Filtering”The TimeRangeSelector popover provides preset options (Today, Yesterday, Last 7 Days, Last 30 Days, Last 90 Days, All Time) and custom date range inputs. Changing the range triggers a refetch of all time-scoped endpoints. Plan stats are unaffected.
Data Loading
Section titled “Data Loading”The dashboard fires seven independent API calls in parallel when it mounts:
get_dashboard_stats_api(time_range) → DashboardStatsget_messaging_stats_api(time_range) → MessagingStatsget_text_agent_stats_api(time_range) → TextAgentStatsget_plan_stats_api() → PlanStatsget_ai_usage_stats_api(time_range) → AiUsageStatsget_ai_message_origin_stats_api(time_range) → AiMessageOriginStatsget_engagement_stats_api(time_range) → EngagementStatsEach section loads independently with skeleton states. Sections render as data arrives — no waterfall.
UI Components
Section titled “UI Components”Call Section
Section titled “Call Section”| Component | Description |
|---|---|
KpiCards | Total calls, total duration, avg duration, total to-dos |
CallActivityChart | Bar chart of daily call counts |
Heatmap (red) | 7×24 grid of calls by day/hour |
RecentCalls | Table with status, duration, recording playback |
TodoStatus | To-do breakdown by status |
Messaging Section
Section titled “Messaging Section”| Component | Description |
|---|---|
MessagingKpiCards | Total messages, delivery rate, inbound/outbound split |
MessageActivityChart | Stacked bar chart — SMS (blue) + Email (emerald) per bucket |
Heatmap (blue) | 7×24 grid of messages by day/hour |
MessagingResponseInsights | Avg response time, unanswered count, per-phone breakdown table |
The response insights card color-codes rates: green (good), amber (warning), destructive (poor). The unanswered count links to the messaging view filtered for unanswered conversations.
Analytics Section
Section titled “Analytics Section”| Component | Description |
|---|---|
TextAgentPerformance | Suggestions count, auto-reply rate, avg confidence, escalation rate |
PlanMetrics | Active plans, contacts in progress, completion rate |
AiUsageOverview | Total tokens + cost, horizontal bar breakdown by feature |
AiMessageOrigin | AI-composed message count, AI share %, bar chart by feature (details) |
Engagement Section
Section titled “Engagement Section”| Component | Description |
|---|---|
ChannelDistributionChart | CSS donut chart using conic-gradient — calls (amber), SMS (blue), email (emerald), other (orange) |
RecentActivityFeed | Unified feed of calls + messages (max 10), clickable rows linking to detail views |
QuickActions | Shortcuts: add phone number, create agent, upload document |
Layout
Section titled “Layout”The dashboard view arranges sections top to bottom:
- Time range selector (header actions slot)
- Call KPI cards + Messaging KPI cards
- Response Insights (full-width)
- Call Activity Chart + Message Activity Chart (side-by-side)
- Call Heatmap (red) + Message Heatmap (blue)
- Text Agent + Plan Metrics + AI Usage (3-column grid)
- Recent Activity Feed + Task Status (2-column grid)
- Channel Distribution Chart
The layout stacks on narrow screens.
Heatmap Component
Section titled “Heatmap Component”The Heatmap component is generic and reusable. It accepts:
#[component]fn Heatmap( cells: Vec<HeatmapCell>, max_count: u32, title: String, item_label: String, // "calls" or "messages" color: String, // RGB like "239, 68, 68" (red) or "59, 130, 246" (blue)) -> ElementColor intensity is normalized against max_count. The component renders a 7-row × 24-column grid with day-of-week labels and hour labels.
Service Layer
Section titled “Service Layer”The messaging stats service (get_messaging_stats_service.rs) handles the heaviest computation:
- SQL aggregation for counts, delivery rates, and direction splits
- Timezone-aware bucketing via
date_truncwith the org’s timezone - Heatmap generation using
EXTRACT(ISODOW)andEXTRACT(HOUR) - Gap filling to ensure continuous time series (zero-fill missing buckets)
- Response time pairing via single-pass contact-grouped iteration
Query helpers in services/query_helpers.rs provide reusable functions for heatmap building, bucket interval selection, and timezone-safe SQL expressions.
Module Structure
Section titled “Module Structure”src/mods/dashboard/├── api/ # Stats endpoints: calls, messaging, text-agent, plan, ai-usage, engagement├── components/ # KPI cards, charts, heatmaps, response insights, activity feed├── services/ # get_messaging_stats service + query helpers├── types/ # All stats types: messaging, text-agent, plan, ai-usage, engagement└── views/ # DashboardViewRelated Modules
Section titled “Related Modules”- Call — call data and status
- Messaging — message records for stats computation
- Text Agents — suggestion and auto-reply data
- Todo — to-do status counts
- Shared —
TimeRangetype andTimeRangeSelectorcomponent