Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changeset/2370-dashboards-and-formats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"hotcrm": minor
---

**Dashboards say what they count, and amounts, quantities and dates read one way (#2370).**

- The two SLA tiles on Customer Service state their base. **Open Cases Past SLA** counts open cases only, so a case closed late leaves the count when it closes. **SLA Met (Closed Cases)** is the rate over closed cases. The SLA report is now **SLA on Closed Cases**.
- **Revenue Trend** appears once, on Executive Overview. CRM Overview and Sales Performance no longer repeat it.
- The CRM Overview tile that summed catalog list prices is now **List Price by Category**, with a description saying it is not sales.
- **Opportunity Funnel by Owner** is split by owner: one row per rep, one column per stage, a Total per rep, and a bar chart of amount by rep.
- **Quota Attainment by Rep** says when it fills: after the nightly forecast snapshot opens the quarter and a manager sets each quota.
- Each report's sidebar entry carries the report's own title, in every language the app ships.
- Sales Home's amount KPIs read in whole units, like the dashboards. Line item quantities are whole numbers, and a fractional quantity is refused. Quote dates and price book validity show the year and are never relative. A quote line's related list shows the discount instead of a second subtotal.

The currency symbol on every amount comes from **Setup → Settings → Localization → Default currency**. See `docs/developers/number-formats.md`.
22 changes: 10 additions & 12 deletions content/docs/analytics/dashboards.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ All five respect [sharing rules](/docs/administration/sharing-and-security) —

**A hidden dashboard is not a locked one.** Executive Overview is also left out of the sidebar for anyone holding the `sales_rep`, `service_agent` or `service_manager` position, so their app opens on a page built for their day — **Sales Home** for a rep — instead of the company-level view. That is a shorter menu for focus, not an access restriction: a rep who opens the dashboard's link still sees it. What any dashboard shows is decided by record visibility, which [sharing rules](/docs/administration/sharing-and-security#how-the-layers-combine) set: every number adds up only the records the viewer may read, so a rep sees the executive layout over their own share of the data, never a deal they could not open themselves.

### No tile shows a trend arrow
### A trend arrow is a real comparison

None of the KPI tiles displays a "vs last period" delta, on any dashboard. A period-over-period comparison is a measurement: it has to come from a real comparison query, and until the renderer can run one for dataset-bound metrics, a percentage on the tile would be a number typed by hand that no data can change — it would read the same on a full database and an empty one. So the tiles show the figure that was actually queried, and nothing else.
A KPI tile shows a "vs previous period" or "vs previous year" delta only when it declares a comparison, and the console then runs a second query over the earlier window. On CRM Overview that is Total Revenue, Deals Won and Avg Deal Size; on Sales Performance, Open Pipeline, Closed Won and Avg Deal Size; on Customer Service, Open Cases, Avg Resolution Time and Open Cases Past SLA; on Executive Overview, Total Revenue (YTD). A *(Selected Period)* tile compares with the window of the same length just before the picker's, so with the picker at All time there is no earlier window and the tile shows its bare number. No percentage is typed by hand: every one changes with the data.

## 🏠 CRM Overview

Expand All @@ -37,10 +37,9 @@ The cross-functional home dashboard — revenue, pipeline and deal mix on one pa
- **Open Deals (Selected Period)** — open opportunities whose close date falls in the selected period.
- **Deals Won (Selected Period)** — closed-won deals in the selected period.
- **Avg Deal Size (Selected Period)** — average value of the deals closed won in the selected period.
- **Revenue Trends** — closed-won revenue over the last 12 months (area chart).
- **Lead Source** — pipeline value by acquisition channel (donut).
- **Pipeline by Stage** — open opportunity value at each sales stage (horizontal bar chart).
- **Top Products** — total list-price revenue by product category (bar).
- **Lead Source** — pipeline value by acquisition channel (donut).
- **List Price by Category** — catalog list prices summed per product category. It reads the price book, not sales: no tile on this page sums sold line items (bar).
- **Pipeline by Owner** — open pipeline value, deal count and average deal size per rep (table).

**Controls**: a date-range picker over the opportunity close date (defaults to this quarter) and an Owner filter.
Expand All @@ -61,11 +60,10 @@ The sales team's daily operational dashboard.
- **Deals Won (12M)** — the numerator behind that percentage.
- **Deals Lost (12M)** — the other half of its denominator, so both numbers are always on screen next to the rate.
- **Pipeline by Stage** — open opportunity value at each sales stage (horizontal bar chart).
- **Monthly Revenue Trend** — closed-won revenue, last 12 months.
- **Pipeline by Forecast Category** — open pipeline grouped by forecast category.
- **Lead Source** — where the pipeline is coming from (donut).
- **Open Pipeline by Owner** — in-flight value, deal count and average win probability per rep (table).
- **Quota Attainment by Rep** — current-quarter quota, closed revenue and attainment per rep, read from the forecast snapshots.
- **Quota Attainment by Rep** — current-quarter quota, closed revenue and attainment per rep, read from the forecast snapshots. It stays empty until the nightly forecast snapshot has opened the current quarter and a manager has set each rep's quota; the demo data does not open one for you.
- **Win / Loss by Rep** — won, lost, settled, win rate and won revenue per rep (table).
- **Win / Loss by Lead Source** — the same breakdown by acquisition channel: which sources produce deals that actually close.
- **Why We Lose** — lost deals by loss reason. Every closed-lost deal carries a reason (it is [required at close](/docs/sales/opportunities)), so this chart has no "unattributed" slice — an empty chart means no losses in the window, not an unfilled field.
Expand Down Expand Up @@ -106,12 +104,12 @@ The service team's daily ops view.
- **Open Cases** — cases that are not yet closed.
- **Critical Cases** — open cases at critical priority.
- **Avg Resolution Time** — mean time to close, in hours.
- **SLA Violations** — cases that breached their SLA.
- **Open Cases Past SLA** — open cases whose SLA deadline has passed. Its base is open cases only: a case closed late leaves this count when it closes.
- **Cases by Status** — workload distribution across the pipeline (donut).
- **Cases by Priority** — open case mix by urgency (pie).
- **Cases by Origin** — Email / Phone / Web / Chat / Portal (bar).
- **Daily Case Volume** — new cases created over the last 30 days.
- **SLA Compliance** — share of cases resolved within SLA, against a 95% target line (gauge).
- **SLA Met (Closed Cases)** — share of closed cases that met their SLA, against a 95% target line (gauge). Its base is closed cases only: an open case is in neither the numerator nor the denominator.
- **My Open Cases by Priority** — the signed-in user's own open cases and their SLA-violation rate per priority (table). It ignores the Agent filter: it always shows your own cases.

**Controls**: a date-range picker over the date a case was created (defaults to the last 90 days), Agent and Priority filters, and a one-minute refresh — service desks need fresh numbers. It is the only picker that windows a case date rather than the opportunity close date, and the only one that does not default to this quarter, so every number on this page is bounded by the last 90 days until you widen it. Daily Case Volume opts out of the picker and keeps its own 30-day window, so the chart under that title always covers the 30 days it names.
Expand All @@ -126,7 +124,7 @@ The exec / finance view of the business.
- **Active Accounts** — customers with at least one active relationship.
- **Total Contacts** — people in the address book.
- **Open Leads** — unconverted leads in the funnel.
- **Revenue Trend** — closed-won revenue over the last 12 months.
- **Revenue Trend** — closed-won revenue over the last 12 months. This is the only dashboard that carries the trend, so it has one home.
- **Revenue by Industry** — YTD closed-won revenue split by customer industry (donut).
- **Pipeline by Stage** — open opportunity value at each sales stage (horizontal bar chart).
- **New Accounts** — account creation cadence over the last 6 months.
Expand All @@ -144,7 +142,7 @@ This dashboard is the basis for the weekly leadership review.

A dashboard filter is matched against the **object** behind each widget's dataset, not against that dataset's declared dimensions, and it is ANDed into the query of every widget bound to it. That is why Customer Service can offer an Agent filter even though `case_metrics` declares no owner dimension: `owner_id` is a field on the case, and the filter needs nothing more than that. Filtering is all it buys — a widget still cannot **group by** a field the dataset does not declare, which is how [SLA & Escalation](/docs/service/sla-and-escalation) can say, correctly, that no report and no dashboard widget breaks cases down by agent, on the same app whose service desk filters by one. It cuts the other way too: a filter naming a field a widget's own object lacks would ask that widget's query for a column that does not exist, so a widget that cannot answer a filter opts out of it by name (`filterBindings`) instead of quietly ignoring it.

Some tiles opt out of the dashboard's own filters on purpose. The 12-month revenue trends, Top Products and Quota Attainment by Rep keep the window they are labelled with, so a narrower date picker cannot silently redefine the number under its own title.
Some tiles opt out of the dashboard's own filters on purpose. Revenue Trend, List Price by Category and Quota Attainment by Rep keep the window they are labelled with, so a narrower date picker cannot silently redefine the number under its own title.

## Where the numbers come from

Expand All @@ -158,5 +156,5 @@ The window is not shared, and each KPI title says which one it reads. *(Selected

- ✅ Before a pipeline review, read **Win / Loss by Rep** next to **Why We Lose** — the first says who is converting, the second says what is beating you.
- ✅ Work the **Quiet 90+ Days** tile weekly. An account with no logged interaction in a quarter is either dormant or already gone, and the tile is only as good as the interactions your team logs.
- ✅ On the service desk, watch **SLA Violations** (the count of breaches) alongside the **SLA Compliance** tile (the rate against target) — a small count on a small volume is not the same as a healthy rate.
- ✅ On the service desk, read the two SLA tiles as two different populations: **Open Cases Past SLA** counts open cases that are already late (work to do now), while **SLA Met (Closed Cases)** is the rate over cases already closed (how the desk did). A late case moves from the first to the second when it closes.
- ✅ Read **Interactions on Deals** against **Open Deals**: the ratio, not either number alone, is the coverage question.
Loading
Loading