Skip to content

mohdasim/Zendesk-Agent-Performance-Audit-Custom-App

Repository files navigation

Agent Performance & Audit Trail Dashboard

A comprehensive Zendesk custom app that tracks agent actions — ticket reassignments, field changes, macro usage — and visualizes productivity patterns, response consistency, and compliance adherence over time.

Built with React 18, Zendesk Garden design system, Recharts visualizations, and IndexedDB for local caching with background sync.


Table of Contents


Features

  • 10 Key Metrics — Each with an info icon that explains the metric, its formula, and data source on click
  • 10 Interactive Charts — Bar, Line, Area, Pie, Radar, Funnel, and two Heatmap visualizations
  • IndexedDB Caching — API responses stored locally for instant loads; configurable TTL (15min to 24hrs)
  • Background Sync — Fresh data fetched in the background without freezing the UI
  • Last Updated Display — Shows relative time ("Updated 5 minutes ago") with manual refresh
  • PDF Export — Downloads the full dashboard with all charts as a multi-page PDF
  • CSV Export — Downloads all agent metrics as a spreadsheet-ready CSV file
  • Sortable Agent Table — Search, sort by any column, paginated, with color-coded SLA/CSAT badges
  • Audit Trail Timeline — Chronological event log with date grouping, type filtering, and lazy loading
  • Date Range & Agent Filters — Quick presets (7d/30d/90d/6mo/1yr) and custom date range with agent selector
  • Zendesk Garden UI — Fully themed with Zendesk's official design system components

Architecture Overview

graph TB
    subgraph Zendesk["Zendesk Platform"]
        ZAF["ZAF SDK<br/>(App Framework)"]
        API1["Audit Logs API"]
        API2["Ticket Audits API"]
        API3["Ticket Metrics API"]
        API4["Metric Events API"]
        API5["Satisfaction Ratings API"]
        API6["Users API"]
        API7["Groups API"]
        API8["Group Memberships API"]
    end

    subgraph App["Custom App (iframe)"]
        subgraph Services["Services Layer"]
            ZC["zafClient.js<br/>ZAF Client Singleton"]
            AP["api.js<br/>8 API Fetchers +<br/>Auto-Pagination"]
            CA["cache.js<br/>IndexedDB (idb)<br/>8 Object Stores"]
            DP["dataProcessor.js<br/>Pure Metric<br/>Computation"]
            EX["exportService.js<br/>PDF & CSV<br/>Generation"]
        end

        subgraph Hooks["React Hooks"]
            UAD["useAuditData<br/>Fetch + Cache +<br/>Background Sync"]
            UM["useMetrics<br/>Filter + Compute +<br/>Memoize"]
        end

        subgraph UI["UI Components"]
            DASH["Dashboard<br/>Main Layout"]
            MC["MetricCard ×10"]
            FIL["Filters"]
            SS["SyncStatus"]
            EC["ExportControls"]
            APT["AgentPerformanceTable"]
            AT["AuditTimeline"]
            subgraph Charts["10 Chart Components"]
                C1["ResponseTimeChart"]
                C2["TicketVolumeChart"]
                C3["CSATTrendChart"]
                C4["ActivityHeatmap"]
                C5["HourlyHeatmap"]
                C6["AgentComparisonRadar"]
                C7["ComplianceChart"]
                C8["ResolutionFunnel"]
                C9["WorkloadDistribution"]
                C10["ReassignmentChart"]
            end
        end
    end

    subgraph Browser["Browser Storage"]
        IDB["IndexedDB<br/>zendesk-audit-dashboard"]
    end

    ZAF --> ZC
    ZC --> AP
    AP --> API1 & API2 & API3 & API4 & API5 & API6 & API7 & API8
    AP --> CA
    CA --> IDB
    CA --> UAD
    UAD --> UM
    UM --> DASH
    DASH --> MC & FIL & SS & EC & APT & AT & Charts
    DP --> UM
    EX --> EC

    style Zendesk fill:#1f73b7,color:#fff
    style App fill:#f8f9f9,color:#2f3941
    style Browser fill:#e9ebed,color:#2f3941
    style Services fill:#edf8f4,color:#2f3941
    style Hooks fill:#fff6e5,color:#2f3941
    style UI fill:#fff0f1,color:#2f3941
    style Charts fill:#dceefb,color:#2f3941
Loading

Data Flow

sequenceDiagram
    participant User
    participant Dashboard
    participant useAuditData
    participant IndexedDB
    participant API as Zendesk APIs (×8)
    participant useMetrics
    participant Charts

    User->>Dashboard: Opens nav_bar app
    Dashboard->>useAuditData: Mount hook

    Note over useAuditData,IndexedDB: Phase 1: Instant Load from Cache
    useAuditData->>IndexedDB: getCachedData() for all 8 stores
    IndexedDB-->>useAuditData: Cached data (or empty)
    useAuditData-->>Dashboard: { data, isLoading: false }
    Dashboard->>useMetrics: Pass raw data + filters
    useMetrics->>useMetrics: computeAgentMetrics()<br/>computeSummaryMetrics()<br/>computeChartData()
    useMetrics-->>Dashboard: { agentMetrics, summaryMetrics, chartData }
    Dashboard->>Charts: Render all visualizations

    Note over useAuditData,API: Phase 2: Background Sync (non-blocking)
    useAuditData->>useAuditData: Check isCacheStale() (TTL)
    alt Cache is stale
        useAuditData->>useAuditData: setTimeout → isSyncing = true
        useAuditData->>API: fetchAll() in parallel (8 requests)
        API-->>useAuditData: Fresh data
        useAuditData->>IndexedDB: setCachedData() + setLastSyncTime()
        useAuditData-->>Dashboard: Updated data + isSyncing: false
        Dashboard->>useMetrics: Recompute metrics
        Dashboard->>Charts: Re-render with fresh data
    end

    Note over User,Dashboard: User Actions
    User->>Dashboard: Change date range / agent filter
    Dashboard->>useMetrics: New filters
    useMetrics-->>Dashboard: Filtered metrics
    Dashboard->>Charts: Update visualizations

    User->>Dashboard: Click "Refresh"
    Dashboard->>useAuditData: refresh()
    useAuditData->>API: Force re-fetch all
    API-->>useAuditData: Fresh data
    useAuditData->>IndexedDB: Update cache
    useAuditData-->>Dashboard: Updated data

    User->>Dashboard: Click "Export PDF"
    Dashboard->>Dashboard: html2canvas → jsPDF → download

    User->>Dashboard: Click "Export CSV"
    Dashboard->>Dashboard: papaparse → Blob → download
Loading

Caching Strategy

flowchart TD
    START([App Opens]) --> LOAD_CACHE[Load from IndexedDB<br/>All 8 stores in parallel]
    LOAD_CACHE --> HAS_DATA{Has cached data?}

    HAS_DATA -->|Yes| SHOW_CACHED[Render UI with cached data<br/>isLoading = false]
    HAS_DATA -->|No| SHOW_EMPTY[Render empty state<br/>isLoading = false]

    SHOW_CACHED --> CHECK_TTL{Cache stale?<br/>age > TTL}
    SHOW_EMPTY --> FORCE_SYNC[Start sync immediately]

    CHECK_TTL -->|Fresh| DONE([Wait for next check])
    CHECK_TTL -->|Stale| BG_SYNC[Start background sync<br/>isSyncing = true]

    BG_SYNC --> FETCH_API[Fetch all 8 APIs<br/>in parallel via<br/>Promise.allSettled]
    FORCE_SYNC --> FETCH_API

    FETCH_API --> STORE_CACHE[Store results in IndexedDB<br/>Clear old data + bulk put]
    STORE_CACHE --> UPDATE_SYNC[Update syncMeta<br/>lastSync timestamp]
    UPDATE_SYNC --> UPDATE_UI[Update React state<br/>isSyncing = false]
    UPDATE_UI --> DONE

    subgraph TTL["Configurable TTL"]
        direction LR
        T1["15 min"]
        T2["30 min"]
        T3["1 hour ★ default"]
        T4["2 hours"]
        T5["6 hours"]
        T6["24 hours"]
    end

    subgraph IDB["IndexedDB Stores"]
        direction LR
        S1["auditLogs"]
        S2["ticketAudits"]
        S3["ticketMetrics"]
        S4["metricEvents"]
        S5["satisfactionRatings"]
        S6["agents"]
        S7["groups"]
        S8["syncMeta"]
    end

    style START fill:#1f73b7,color:#fff
    style DONE fill:#038153,color:#fff
    style BG_SYNC fill:#ffb648,color:#2f3941
    style FORCE_SYNC fill:#cc3340,color:#fff
Loading

Component Hierarchy

graph TD
    INDEX["index.js<br/>ZAF Init + React Render"] --> APP["App.jsx<br/>ThemeProvider"]
    APP --> DASH["Dashboard.jsx<br/>Main Layout + State"]

    DASH --> TOP["Top Bar"]
    DASH --> METRICS["Metrics Section"]
    DASH --> PERF["Performance Section"]
    DASH --> ACTIVITY["Activity Section"]
    DASH --> COMPARE["Comparison Section"]
    DASH --> WORKLOAD["Workload Section"]
    DASH --> TABLE["Agent Details Section"]
    DASH --> TIMELINE["Audit Trail Section"]

    TOP --> SS["SyncStatus<br/>Last updated + Refresh"]
    TOP --> FIL["Filters<br/>Date Range + Agent"]
    TOP --> EC["ExportControls<br/>PDF + CSV"]

    METRICS --> MC1["MetricCard<br/>Avg Response Time"]
    METRICS --> MC2["MetricCard<br/>Avg Resolution Time"]
    METRICS --> MC3["MetricCard<br/>Tickets Resolved"]
    METRICS --> MC4["MetricCard<br/>Reassignments"]
    METRICS --> MC5["MetricCard<br/>Field Changes"]
    METRICS --> MC6["MetricCard<br/>Macro Usage"]
    METRICS --> MC7["MetricCard<br/>SLA Compliance"]
    METRICS --> MC8["MetricCard<br/>CSAT Score"]
    METRICS --> MC9["MetricCard<br/>Work Time"]
    METRICS --> MC10["MetricCard<br/>Wait Time"]

    MC1 & MC2 & MC3 & MC4 & MC5 & MC6 & MC7 & MC8 & MC9 & MC10 --> IM["InfoModal<br/>Metric Explanation"]

    PERF --> RTC["ResponseTimeChart<br/>📊 Bar Chart"]
    PERF --> TVC["TicketVolumeChart<br/>📈 Area Chart"]
    PERF --> CSAT["CSATTrendChart<br/>📉 Line Chart"]

    ACTIVITY --> AH["ActivityHeatmap<br/>🟩 Calendar Heatmap"]
    ACTIVITY --> HH["HourlyActivityHeatmap<br/>🟦 Hour×Day Grid"]

    COMPARE --> ACR["AgentComparisonRadar<br/>🕸️ Radar Chart"]
    COMPARE --> CC["ComplianceChart<br/>🍩 Donut Chart"]
    COMPARE --> RF["ResolutionFunnel<br/>📐 Funnel Chart"]

    WORKLOAD --> WD["WorkloadDistribution<br/>📊 Stacked Area"]
    WORKLOAD --> RC["ReassignmentChart<br/>📊 Horizontal Bar"]

    TABLE --> APT["AgentPerformanceTable<br/>Sortable + Searchable"]
    TIMELINE --> AT["AuditTimeline<br/>Date Groups + Scroll"]

    style DASH fill:#1f73b7,color:#fff
    style METRICS fill:#edf8f4,color:#2f3941
    style PERF fill:#dceefb,color:#2f3941
    style ACTIVITY fill:#fff6e5,color:#2f3941
    style COMPARE fill:#fff0f1,color:#2f3941
Loading

API Integration

flowchart LR
    subgraph Client["ZAF Client"]
        REQ["client.request()"]
    end

    subgraph Pagination["Auto-Pagination"]
        CP["Cursor-Based<br/>paginateRequest()"]
        IP["Incremental<br/>incrementalFetch()"]
    end

    subgraph APIs["8 Zendesk APIs"]
        A1["GET /api/v2/audit_logs.json<br/>Admin audit trail, macro usage"]
        A2["GET /api/v2/ticket_audits.json<br/>Field changes, reassignments"]
        A3["GET /api/v2/ticket_metrics.json<br/>Response & resolution times"]
        A4["GET /api/v2/incremental/<br/>ticket_metric_events.json<br/>SLA breaches, work time"]
        A5["GET /api/v2/satisfaction_ratings.json<br/>CSAT scores per agent"]
        A6["GET /api/v2/users.json?role=agent<br/>Agent list & profiles"]
        A7["GET /api/v2/groups.json<br/>Team/group structure"]
        A8["GET /api/v2/group_memberships.json<br/>Agent-to-group mapping"]
    end

    REQ --> CP & IP
    CP --> A1 & A2 & A3 & A5 & A6 & A7 & A8
    IP --> A4

    style Client fill:#1f73b7,color:#fff
    style Pagination fill:#ffb648,color:#2f3941
Loading
API Endpoint Pagination Key Data
Audit Logs /api/v2/audit_logs.json Cursor actor_name, action, change_description, source_type
Ticket Audits /api/v2/ticket_audits.json Cursor author_id, events[] (field changes, status transitions)
Ticket Metrics /api/v2/ticket_metrics.json Cursor reply_time_in_minutes, full_resolution_time_in_minutes
Metric Events /api/v2/incremental/ticket_metric_events.json Time-based metric, status (breached/fulfilled), sla_policy
Satisfaction Ratings /api/v2/satisfaction_ratings.json Cursor assignee_id, score (good/bad)
Users /api/v2/users.json?role=agent Cursor name, email, photo
Groups /api/v2/groups.json Cursor id, name
Group Memberships /api/v2/group_memberships.json Cursor user_id, group_id

Metrics Reference

# Metric Unit Formula Source
1 Avg First Response Time hours Sum of first response times / Total tickets Ticket Metrics
2 Avg Resolution Time hours Sum of resolution times / Total resolved tickets Ticket Metrics
3 Tickets Resolved count Count of status changed to solved/closed Ticket Audits
4 Reassignment Count count Count of assignee_id field change events Ticket Audits
5 Field Change Frequency count Count of all field change events Ticket Audits
6 Macro Usage count Count of macro-related audit events Audit Logs
7 SLA Compliance Rate % (Non-breached / Total SLA events) × 100 Metric Events
8 CSAT Score % (Good ratings / Total ratings) × 100 Satisfaction Ratings
9 Agent Work Time hours Sum of agent_work_time metric events Metric Events
10 Requester Wait Time hours Sum of requester_wait_time / Total tickets Metric Events

Click the icon next to any metric in the dashboard to see its full description, formula, and data source.


Visualizations

Charts

# Chart Type Library Description
1 Response Time Bar Recharts Avg first response & resolution time per agent
2 Ticket Volume Area Recharts Daily ticket resolution trend over time
3 CSAT Trend Line Recharts Monthly CSAT score with 80% target reference line
4 Activity Heatmap Calendar react-calendar-heatmap GitHub-style 365-day activity intensity
5 Hourly Heatmap Grid Custom CSS Grid 7×24 matrix (Day of Week × Hour) activity pattern
6 Agent Comparison Radar Recharts Multi-agent comparison across 5 dimensions
7 SLA Compliance Donut Recharts Met vs Breached with center percentage
8 Resolution Funnel Funnel Recharts New → Open → Pending → Solved → Closed pipeline
9 Workload Distribution Stacked Area Recharts Agent workload share over time
10 Reassignments Horizontal Bar Recharts Reassignment count per agent

Heatmap Color Scales

Activity Heatmap (green scale):

□ No activity  ■ Low  ■ Medium  ■ High  ■ Very High

Hourly Heatmap (blue scale):

□ No activity  ■ Minimal  ■ Light  ■ Moderate  ■ Active  ■ Peak

Tech Stack

Category Technology Purpose
Framework React 18 UI rendering
Bundler Webpack 5 Module bundling
Transpiler Babel 7 JSX + modern JS
UI Library Zendesk Garden Design system components
Styling styled-components 5 CSS-in-JS (required by Garden)
Charts Recharts 2 Bar, Line, Area, Pie, Radar, Funnel
Heatmap react-calendar-heatmap GitHub-style calendar
Caching idb 8 IndexedDB Promise wrapper
PDF html2canvas + jsPDF Dashboard screenshot → PDF
CSV PapaParse JSON → CSV conversion
Dates date-fns 3 Date formatting & math
Platform ZAF SDK 2.0 Zendesk App Framework

Project Structure

zendesk-agent-performance-audit-custom-app/
├── manifest.json                          # Zendesk app manifest (v2.0)
├── package.json                           # Dependencies & scripts
├── webpack.config.js                      # Webpack 5 config
├── .babelrc                               # Babel presets
├── .gitignore
├── LICENSE
│
├── assets/
│   ├── iframe.html                        # App entry point (loads ZAF SDK)
│   ├── logo.svg                           # App logo (128×128)
│   └── icon_nav_bar.svg                   # Navigation bar icon
│
├── translations/
│   └── en.json                            # English strings
│
└── src/
    ├── index.js                           # ZAF init → React render
    ├── App.jsx                            # ThemeProvider wrapper
    │
    ├── constants/
    │   ├── config.js                      # TTL, colors, DB config, presets
    │   └── metricDefinitions.js           # 10 metric descriptions & formulas
    │
    ├── services/
    │   ├── zafClient.js                   # ZAF client singleton
    │   ├── api.js                         # 8 API fetchers + auto-pagination
    │   ├── cache.js                       # IndexedDB CRUD (8 stores)
    │   ├── dataProcessor.js               # Pure metric computation functions
    │   └── exportService.js               # PDF & CSV generation
    │
    ├── hooks/
    │   ├── useAuditData.js                # Cache-first + background sync
    │   └── useMetrics.js                  # Filter + compute + memoize
    │
    └── components/
        ├── Dashboard.jsx                  # Main layout & state management
        ├── MetricCard.jsx                 # Metric value + info icon
        ├── InfoModal.jsx                  # Metric explanation modal
        ├── Filters.jsx                    # Date range + agent selector
        ├── SyncStatus.jsx                 # Last updated + refresh + TTL
        ├── ExportControls.jsx             # PDF/CSV export buttons
        ├── AgentPerformanceTable.jsx      # Sortable agent stats table
        ├── AuditTimeline.jsx              # Scrollable audit event log
        │
        └── charts/
            ├── ChartWrapper.jsx           # Shared chart card with info icon
            ├── ResponseTimeChart.jsx      # 📊 Bar: response time per agent
            ├── TicketVolumeChart.jsx       # 📈 Area: tickets over time
            ├── CSATTrendChart.jsx          # 📉 Line: CSAT trend
            ├── ActivityHeatmap.jsx         # 🟩 Calendar: yearly activity
            ├── HourlyActivityHeatmap.jsx   # 🟦 Grid: hour × day matrix
            ├── AgentComparisonRadar.jsx    # 🕸️ Radar: multi-metric compare
            ├── ComplianceChart.jsx         # 🍩 Donut: SLA met vs breached
            ├── ResolutionFunnel.jsx        # 📐 Funnel: ticket pipeline
            ├── WorkloadDistribution.jsx    # 📊 Stacked area: workload
            └── ReassignmentChart.jsx       # 📊 Horizontal bar: reassigns

Getting Started

Prerequisites

  • Node.js 18+ and npm 9+
  • Zendesk account (Enterprise plan for Audit Logs API; other APIs work on all plans)
  • Zendesk CLI (@zendesk/zcli) for local development and deployment

Installation

# Clone the repository
git clone https://github.com/mohdasim/Zendesk-Agent-Performance-Audit-Custom-App.git
cd Zendesk-Agent-Performance-Audit-Custom-App

# Install dependencies
npm install

Local Development

# Start webpack dev server
npm start
# App available at http://localhost:4567

# Or use Zendesk CLI for in-Zendesk testing
npm run build
npm run server
# Then append ?zcli_apps=true to your Zendesk URL

Validate

npm run validate

Build & Deploy

# Production build
npm run build

# Output in dist/
#   dist/manifest.json
#   dist/assets/iframe.html
#   dist/assets/bundle.[hash].js
#   dist/translations/en.json

Deploy to Zendesk

# Package for upload
cd dist && zip -r ../app.zip . && cd ..

# Upload via Zendesk Admin → Apps → Upload private app
# Or use zcli:
npx @zendesk/zcli apps:create dist

The app will appear as an icon in the left navigation bar of Zendesk Support.


Configuration

Cache TTL

The auto-refresh interval is configurable from the dashboard via the dropdown next to the refresh button:

Setting Value
15 minutes 900000 ms
30 minutes 1800000 ms
1 hour (default) 3600000 ms
2 hours 7200000 ms
6 hours 21600000 ms
24 hours 86400000 ms

The selected TTL is persisted in IndexedDB and survives page reloads.

Date Range Presets

Quick filter presets available in the toolbar:

  • Last 7 days
  • Last 30 days (default)
  • Last 90 days
  • Last 6 months
  • Last year

Custom start/end dates can also be set manually.


Export

PDF Export

Captures the full dashboard (all charts, metrics, tables) as a landscape PDF:

  • Uses html2canvas to screenshot the DOM at 2× resolution
  • Generates multi-page PDF via jsPDF if content exceeds one page
  • Includes header with report title and generation timestamp

CSV Export

Downloads agent performance metrics as a CSV file with columns:

  • Agent Name, Email, Group(s)
  • Tickets Resolved, Avg First Response Time, Avg Resolution Time
  • Reassignment Count, Field Changes, Macro Usage
  • SLA Compliance %, CSAT Score %, CSAT Rating Count
  • Agent Work Time, Requester Wait Time

License

MIT

About

Track agent actions — ticket reassignments, field changes, macro usage — and visualizes productivity patterns, response consistency, and compliance adherence over time.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors