# Agents (Manage)

**Nav:** Dashboard hub → **Agents** tab (`/manage/agents`, a `DashboardTabs`
main tab beside Insights / Sales / Pipeline / Calendar — it is a dashboard about
the team, so it lives with the other read-only overviews). The sidebar Dashboard
entry carries `/manage/agents` in its prefixes.

## What it does

The cross-channel productivity roll-up: one row per agent, counting the
conversations they conducted on each channel (**Zoom meetings, phone calls,
showroom F2F**) in a 7 / 30 / 90-day period, with combined talk time and a recency
badge. Three header cards carry the team-wide per-channel totals and link to each
channel's own dashboard. A **"Who worked when" heatmap** (agents × days, GitHub
style) sits above the table: one cell per day per agent, intensity = that day's
conversations (single-hue sequential ramp; zero = gray, weekends paler, today
outlined), with a Team pulse row on top and hover tooltips carrying the exact
per-channel breakdown. The day axis and each agent's positional `daily`
[zoom, calls, f2f] triples are bucketed in PHP on Asia/Kuala_Lumpur (MySQL
DATE() would bucket in the server zone), over a window of whole KL calendar
days so the cells always sum to the table's totals. The per-channel dashboards stay the place for depth
(scores, action items, trends); this page answers "who is doing how much, where."

## How it works

- `GET /manage/agents` → `Manage\Agents\AgentsController@index`, gated
  `permission:view-calls|view-zoom|view-f2f` (it reads the same data those
  dashboards show, rolled up). The sidebar entry carries the matching
  `permissionAny`.
- One grouped aggregate per channel (`count / sum(duration) / max(date)` keyed by
  `admin_id`): `ZoomMeeting` on `start_time` (duration is **minutes** — ×60),
  `CallRecording` on `called_at`, `F2fRecording` on `recorded_at` (both seconds).
  Zoom's `meetingsOnly` global scope applies, so webinars are excluded.
- Roster = **admins whose role carries the Sales Execution permission**
  (`User::permission(Permission::SALES_EXECUTION)`), **zeros included** — an agent
  with no conversations this period is a signal, not a row to hide (same rule as
  the module dashboards). Non-sales admins (ops, marketing) never appear.
- Each non-zero count links into the module's filtered list: zoom filters by
  `agent[]`, calls / f2f by `sales[]` (their QueryRequest keys).

## Related files

- `app/Http/Controllers/Manage/Agents/AgentsController.php`
- `resources/js/Pages/Manage/Agents/Index.vue`
- `resources/js/Components/DashboardTabs.vue` (the hub strip it mounts)
- Per-channel depth: `docs/modules_handbook/manage/call-history/`, `manage/zoom/`,
  `manage/f2f/` handbooks.
