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
49 changes: 49 additions & 0 deletions .changeset/analytics-typography-stops-promising-phantom-reports.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
'hotcrm': patch
---

Re-weight every phantom name on the **Cubes** and **Reports** analytics pages, all
three locales of each. The prose on both pages was already honest — its headings say
outright that the reports are published nowhere — but the typography contradicted it,
and a reader who skims bold runs reads the typography.

### What was wrong

The repo reserves **bold** for names the app really has and *italics* for a name a
reader arrives with that the product does not carry; a phantom must still be named —
say where the thing really lives, never delete it silently. Measured against the
declared labels under `src/` (every `label:` / `title:` string literal, 2936 of them),
`analytics/reports` carried **20** bolded names per locale that resolve to nothing,
and `analytics/cubes` **9** — 87 bold runs across the six pages.

They were not a long tail of near-misses. They were whole sections of report names:
*Forecast vs Actual*, *Win/Loss Analysis*, *Big Deals Won*, *Sales Cycle Length*,
*Discount Approval Activity*, *Lead Conversion Funnel*, *Aged Leads*,
*Lead Source ROI*, *Case Volume by Origin*, *Case Resolution Time*,
*Top Accounts by Case Volume*, *Reopened Cases*, *CSAT by Agent*,
*Contracts Expiring*, *Active Contracts by Product*, *Renewal Pipeline*,
*Campaign ROI*, *Campaign Engagement* — plus *Top Performing Reps*, which the page
itself introduces as a name whose real one is different, and the retired
*Customer Satisfaction* rating, bolded on both pages inside the sentence that says it
was retired. On `cubes` the *Name by name* list under the marketing section bolded
eight metric names that are questions a reader arrives with, one of them beside a real
formula field on the same line.

### What changed

Every one of those 87 runs is now italic, at the same site in English, Simplified and
Traditional Chinese — nothing was deleted, and every phantom still names where the
real thing lives. Three sites needed judgement rather than a sweep:

- *Campaign spend*, *cost per lead* and *cost per opportunity* now sit in italics
beside **ROI %** in bold, on the same line: the ROI percentage is a real formula
field on `crm_campaign`, the three spend figures are carried by no field at all.
- *Persona (job role)* is italic; the **Title** field it points at stays bold.
- The bullet that called **period** a real field on `crm_campaign` was corrected
rather than re-marked. The campaign carries **Start Date** and **End Date** and no
Period field, so italicising the word alone would have left a sentence that reads
"real fields on `crm_campaign`" over a name that is not one.

Nothing under `src/` changed, no count on any page moved, and the bold runs that name
something real — 72 on `reports`, 36 on `cubes` — were re-read against source and left
alone.
12 changes: 6 additions & 6 deletions content/docs/analytics/cubes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ One dataset stands behind every case-related dashboard tile and all three case r
- **Agent, and team** — the dataset declares **no owner dimension**, so nothing in analytics can group, rank or filter cases by agent. `owner_id` is a field on the case; no dimension exposes it. This is why the service pages carry no agent leaderboard, and why *"reopened cases by agent"* is doubly impossible — nothing records a reopen either.
- **Account, and account tier** — it reads `crm_case` alone and never crosses to `crm_account`.
- **Product** — cases carry no product link that analytics can read, so *"cases by category by product"* has no path. The nearest real cut to a category is the case **Type** (*Question / Problem / Feature Request / Bug*).
- **CSAT score** — there is no satisfaction data to aggregate. The case object used to declare a **Customer Satisfaction** rating, but nothing in the product ever collected it — no screen offered it and no automation wrote it — so it was retired rather than left standing as a column a report could point at.
- **CSAT score** — there is no satisfaction data to aggregate. The case object used to declare a *Customer Satisfaction* rating, but nothing in the product ever collected it — no screen offered it and no automation wrote it — so it was retired rather than left standing as a column a report could point at.
- **Open / new / resolved counts as numbers of their own** — the pre-filtered counts this dataset declares are on the closed side only. Status is a dimension, so a count *split by* status gives the same breakdown.
- **Period at any grain but day** — the created-date dimension buckets by day.

Expand All @@ -73,12 +73,12 @@ The records do carry the numbers. `crm_campaign` has the **Number Sent / Number

Name by name:

- **Members enrolled / responded**, **conversion count** — per-campaign counters on the record; no measure, so no total and no ranking across campaigns.
- **Sourced and influenced revenue** — unreachable from the deal side too: `crm_opportunity.crm_campaign` is a real lookup, but `opportunity_metrics` declares no campaign dimension, so revenue cannot be attributed to a campaign anywhere in analytics.
- **Campaign spend**, **cost per lead**, **cost per opportunity**, **ROI %** — the ROI percentage exists on each record as a formula; nothing sums the spend or compares campaigns.
- **Campaign (and type)**, **channel**, **period** — real fields on `crm_campaign`, and dimensions nowhere.
- *Members enrolled / responded*, *conversion count* — per-campaign counters on the record; no measure, so no total and no ranking across campaigns.
- *Sourced and influenced revenue* — unreachable from the deal side too: `crm_opportunity.crm_campaign` is a real lookup, but `opportunity_metrics` declares no campaign dimension, so revenue cannot be attributed to a campaign anywhere in analytics.
- *Campaign spend*, *cost per lead*, *cost per opportunity*, **ROI %** — the ROI percentage exists on each record as a formula; nothing sums the spend or compares campaigns.
- **Campaign (and type)**, **channel** — real fields on `crm_campaign`, and dimensions nowhere. A *period* is not one of them: the campaign carries **Start Date** and **End Date**, and no dataset reads either.
- **Lead source** — a dimension on both the lead and the deal side, so *"which sources produce deals"* is answerable; the *campaign* behind the source is not.
- **Persona (job role)** — no path at all: **Title** is free text on the contact and the lead, and the contact dataset declares no dimensions.
- *Persona (job role)* — no path at all: **Title** is free text on the contact and the lead, and the contact dataset declares no dimensions.

So the three questions this section offered — *"ROI by campaign type"*, *"cost per opportunity by channel"*, *"conversion rate by persona"* — cannot be answered here today. Closing the gap means adding `src/datasets/campaign.dataset.ts`: a source change and a redeploy, not a setting. See [Campaigns](/docs/marketing/campaigns) for what the campaign record shows today.

Expand Down
12 changes: 6 additions & 6 deletions content/docs/analytics/cubes.zh-Hans.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ description: HotCRM 分析底下的语义层——它是什么、回答哪些业
- **客服(及团队)** —— 这个 dataset **没有负责人维度**,所以分析侧无法按客服分组、排名或筛选。`owner_id` 是工单上的字段,没有任何维度把它暴露出来。这也是服务侧各页都没有客服排行榜的原因,而「按客服看重开工单」更是两头都不成立 —— 也没有任何东西在记录「重开」。
- **客户(及层级)** —— 它只读 `crm_case`,从不跨到 `crm_account`。
- **产品** —— 工单上没有分析侧读得到的产品关联,所以「按类别按产品看工单」没有路径。最接近「类别」的真实切法是工单的 **Type**(*Question / Problem / Feature Request / Bug*)。
- **CSAT 评分** —— 没有满意度数据可聚合。工单对象上曾经声明过一个**客户满意度**评分,但产品里从来没有任何环节采集它 —— 没有界面可填,也没有自动化会写 —— 因此它被退役,而不是留着当一个报表可以指过来的空列。
- **CSAT 评分** —— 没有满意度数据可聚合。工单对象上曾经声明过一个*客户满意度*评分,但产品里从来没有任何环节采集它 —— 没有界面可填,也没有自动化会写 —— 因此它被退役,而不是留着当一个报表可以指过来的空列。
- **把未结 / 新建 / 已解决当作各自独立的数字** —— 这个 dataset 声明的预筛计数都在已关闭那一侧。状态是维度,所以按状态*拆开*的计数能给出同样的分解。
- **除天以外的任何周期粒度** —— 创建日期维度只按天分桶。

Expand All @@ -73,12 +73,12 @@ description: HotCRM 分析底下的语义层——它是什么、回答哪些业

逐条来看:

- **入组成员数 / 响应成员数**、**转化数量** —— 都是记录上的单活动计数器;没有度量,也就没有跨活动的合计与排名。
- **来源收入与影响收入** —— 从交易这一侧同样够不着:`crm_opportunity.crm_campaign` 是真实的 lookup,但 `opportunity_metrics` 没有声明营销活动维度,所以分析侧任何地方都无法把收入归因到某个营销活动。
- **营销活动支出**、**每线索成本**、**每商机成本**、**ROI %** —— ROI 百分比作为公式在每条记录上是有的;但没有任何东西在汇总支出、也没有任何东西在比较活动之间的高低。
- **营销活动(及类型)**、**渠道**、**周期** —— 都是 `crm_campaign` 上真实的字段,而在任何地方都不是维度。
- *入组成员数 / 响应成员数*、*转化数量* —— 都是记录上的单活动计数器;没有度量,也就没有跨活动的合计与排名。
- *来源收入与影响收入* —— 从交易这一侧同样够不着:`crm_opportunity.crm_campaign` 是真实的 lookup,但 `opportunity_metrics` 没有声明营销活动维度,所以分析侧任何地方都无法把收入归因到某个营销活动。
- *营销活动支出*、*每线索成本*、*每商机成本*、**ROI %** —— ROI 百分比作为公式在每条记录上是有的;但没有任何东西在汇总支出、也没有任何东西在比较活动之间的高低。
- **营销活动(及类型)**、**渠道** —— 都是 `crm_campaign` 上真实的字段,而在任何地方都不是维度。*周期* 则不在其列:营销活动记录上带的是 **Start Date** 与 **End Date**,而没有任何数据集读它们。
- **线索来源** —— 它在线索侧和交易侧都是维度,所以「哪些来源带来了交易」答得出来;来源背后的那个*营销活动*则答不出来。
- **人物画像(职位角色)** —— 完全没有路径:**Title** 在联系人和线索上都是自由文本,而联系人那个 dataset 一个维度都没有声明。
- *人物画像(职位角色)* —— 完全没有路径:**Title** 在联系人和线索上都是自由文本,而联系人那个 dataset 一个维度都没有声明。

所以本节给出的那三个问题 —— 「按营销活动类型的 ROI」「按渠道的每商机成本」「按人物画像的转化率」 —— 今天在这里一个都答不出来。要补上这个缺口,得新增 `src/datasets/campaign.dataset.ts`:那是改源码加重新部署,不是一个设置项。营销活动记录今天能看到什么,见 [营销活动](/zh-Hans/docs/marketing/campaigns)。

Expand Down
12 changes: 6 additions & 6 deletions content/docs/analytics/cubes.zh-Hant.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ description: HotCRM 分析底下的語義層——它是什麼、回答哪些業
- **客服(及團隊)** —— 這個 dataset **沒有負責人維度**,所以分析側無法按客服分組、排名或篩選。`owner_id` 是工單上的欄位,沒有任何維度把它暴露出來。這也是服務側各頁都沒有客服排行榜的原因,而「按客服看重開工單」更是兩頭都不成立 —— 也沒有任何東西在記錄「重開」。
- **客戶(及層級)** —— 它只讀 `crm_case`,從不跨到 `crm_account`。
- **產品** —— 工單上沒有分析側讀得到的產品關聯,所以「按類別按產品看工單」沒有路徑。最接近「類別」的真實切法是工單的 **Type**(*Question / Problem / Feature Request / Bug*)。
- **CSAT 評分** —— 沒有滿意度資料可彙總。工單物件上曾經宣告過一個**客戶滿意度**評分,但產品裡從來沒有任何環節採集它 —— 沒有介面可填,也沒有自動化會寫 —— 因此它被退役,而不是留著當一個報表可以指過來的空欄。
- **CSAT 評分** —— 沒有滿意度資料可彙總。工單物件上曾經宣告過一個*客戶滿意度*評分,但產品裡從來沒有任何環節採集它 —— 沒有介面可填,也沒有自動化會寫 —— 因此它被退役,而不是留著當一個報表可以指過來的空欄。
- **把未結 / 新建 / 已解決當作各自獨立的數字** —— 這個 dataset 宣告的預篩計數都在已關閉那一側。狀態是維度,所以按狀態*拆開*的計數能給出同樣的分解。
- **除天以外的任何週期粒度** —— 建立日期維度只按天分桶。

Expand All @@ -73,12 +73,12 @@ description: HotCRM 分析底下的語義層——它是什麼、回答哪些業

逐條來看:

- **加入的成員數 / 已回應的成員數**、**轉化數量** —— 都是記錄上的單活動計數器;沒有度量,也就沒有跨活動的合計與排名。
- **來源收入與影響收入** —— 從交易這一側同樣夠不著:`crm_opportunity.crm_campaign` 是真實的 lookup,但 `opportunity_metrics` 沒有宣告行銷活動維度,所以分析側任何地方都無法把收入歸因到某個行銷活動。
- **行銷活動支出**、**每潛在客戶成本**、**每商機成本**、**ROI %** —— ROI 百分比作為公式在每筆記錄上是有的;但沒有任何東西在彙總支出、也沒有任何東西在比較活動之間的高低。
- **行銷活動(及類型)**、**通路**、**週期** —— 都是 `crm_campaign` 上真實的欄位,而在任何地方都不是維度。
- *加入的成員數 / 已回應的成員數*、*轉化數量* —— 都是記錄上的單活動計數器;沒有度量,也就沒有跨活動的合計與排名。
- *來源收入與影響收入* —— 從交易這一側同樣夠不著:`crm_opportunity.crm_campaign` 是真實的 lookup,但 `opportunity_metrics` 沒有宣告行銷活動維度,所以分析側任何地方都無法把收入歸因到某個行銷活動。
- *行銷活動支出*、*每潛在客戶成本*、*每商機成本*、**ROI %** —— ROI 百分比作為公式在每筆記錄上是有的;但沒有任何東西在彙總支出、也沒有任何東西在比較活動之間的高低。
- **行銷活動(及類型)**、**通路** —— 都是 `crm_campaign` 上真實的欄位,而在任何地方都不是維度。*週期* 則不在其列:行銷活動記錄上帶的是 **Start Date** 與 **End Date**,而沒有任何資料集讀它們。
- **潛在客戶來源** —— 它在潛在客戶側和交易側都是維度,所以「哪些來源帶來了交易」答得出來;來源背後的那個*行銷活動*則答不出來。
- **人物誌(職位角色)** —— 完全沒有路徑:**Title** 在聯絡人和潛在客戶上都是自由文字,而聯絡人那個 dataset 一個維度都沒有宣告。
- *人物誌(職位角色)* —— 完全沒有路徑:**Title** 在聯絡人和潛在客戶上都是自由文字,而聯絡人那個 dataset 一個維度都沒有宣告。

所以本節給出的那三個問題 —— 「按行銷活動類型的 ROI」「按通路的每商機成本」「按人物誌的轉化率」 —— 今天在這裡一個都答不出來。要補上這個缺口,得新增 `src/datasets/campaign.dataset.ts`:那是改原始碼加重新部署,不是一個設定項。行銷活動記錄今天能看到什麼,見 [行銷活動](/zh-Hant/docs/marketing/campaigns)。

Expand Down
Loading
Loading