From af7ca9f355cb5cae37988419d0afcd2ee9a6a74d Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Aug 2026 09:03:01 +0000 Subject: [PATCH] docs(service): write the sla page's views, report dimensions and business-hours claims to source (#917) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six claims on `service/sla-and-escalation` pointed at views, report breakdowns and configuration switches this app does not ship: - business hours configurable (callout + admin tip) — no calendar, no holiday list; `case.hook.ts` adds 4 wall-clock hours - SLA Performance's four breakdowns — `rows: ['priority']` only, and agent / account tier / month are unreachable in `case_metrics` - "Breached SLA" / "Critical Cases" list views — `crm_case` ships seven views, none filtering `is_sla_violated`; the breach filter lives on two Service Dashboard tiles - "Service Board" kanban — the board is `case_workflow`, labelled "Service Workflow", tabbed as "Workflow" - My Open Cases sorted by SLA Due Date — `priority_rank` desc is the primary key, due date only a tie-breaker - Waiting on Customer pausing the SLA clock — nothing pauses it, and `case_sla_monitor`'s `$nin` does not exclude `waiting_customer` Each keeps its name and gains the real attribution. Three locales; no metadata under `src/` changed. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01VHrPAGEgFDoHjphqYG4BMa --- .changeset/sla-views-reports-write-real.md | 61 +++++++++++++++++++ content/docs/service/sla-and-escalation.mdx | 31 ++++++---- .../service/sla-and-escalation.zh-Hans.mdx | 31 ++++++---- .../service/sla-and-escalation.zh-Hant.mdx | 31 ++++++---- 4 files changed, 118 insertions(+), 36 deletions(-) create mode 100644 .changeset/sla-views-reports-write-real.md diff --git a/.changeset/sla-views-reports-write-real.md b/.changeset/sla-views-reports-write-real.md new file mode 100644 index 000000000..6f402ba62 --- /dev/null +++ b/.changeset/sla-views-reports-write-real.md @@ -0,0 +1,61 @@ +--- +'hotcrm': patch +--- + +Write the views / report / configuration half of `service/sla-and-escalation` to +what the app actually ships, in all three locales. Six claims sent readers +looking for screens, dropdowns and switches that do not exist; each was +re-confirmed against `origin/main` before being rewritten, and each keeps the +name it used so a reader who remembers it can find out what happened to it. + +**Business hours are not configurable — there is no business-hours anything.** +The callout and the admin tip both promised that the clock could be told to +count 9-5 Mon-Fri instead of calendar hours, "controlled by your tenant's +business-hours setup". No working-day calendar, holiday list or setting of that +kind exists anywhere in `src/`; the only code that computes an SLA deadline is +`due.setHours(due.getHours() + 4)` in `src/objects/case.hook.ts`, straight off +the wall clock. Both places now say so, with the consequence spelled out: a +Critical case opened at 4pm Friday is due 8pm Friday, and nights, weekends and +holidays all count. + +**The SLA Performance report has one breakdown, not four.** `sla_performance` +declares `rows: ['priority']` (`src/reports/case.report.ts`), so *Priority* was +the only one of the four bullets that was real — and the other three are not +merely absent from the report, they are unreachable in the semantic layer +underneath it. `case_metrics` (`src/datasets/case.dataset.ts`) declares five +dimensions — Status, Priority, Origin, Type, Created — with no owner/agent +dimension, no crossing over to `crm_account.tier`, and `created_date` bucketed +by **day** rather than month and not in that report's `rows` at all. The section +now states the one dimension, names each missing one with why it cannot be +selected, and records that the report measures the **SLA Violation Rate** over +closed cases (`runtimeFilter: { is_closed: true }`) rather than a compliance +percentage. + +**Breached SLA and Critical Cases are not list views.** `crm_case` ships seven +(`src/views/case.view.ts`): *All Cases*, *Service Workflow*, *SLA Calendar*, +*Case Timeline*, *My Open Cases*, *Escalated Cases*, *⏰ SLA at Risk* — and none +of them filters on `is_sla_violated`. The two surfaces that do are metric tiles +on the Service Dashboard. The cadence table and the manager tip now point at +**Escalated Cases** (every case the sweep flags gets escalated into it) plus the +**SLA Violations** tile, and say plainly that the two old names name nothing. + +**The kanban board is called Service Workflow.** `case_workflow` carries +`label: 'Service Workflow'` and appears on the case list as the **Workflow** +tab; *Service Board* exists nowhere in the app. + +**My Open Cases is a priority queue, not a deadline queue.** Its sort is +`priority_rank` descending first, `sla_due_date` ascending only as a +tie-breaker — and since only Critical cases are stamped with a due date, the +tie-breaker has nothing to order the lower bands by. + +**Waiting on Customer does not pause the SLA clock**, and there is no config +that makes it. `sla_due_date` is written once and never recomputed, and +`case_sla_monitor`'s `status: { $nin: ['resolved', 'closed'] }` does not exclude +`waiting_customer` — so a case parked on the customer keeps running down its +four hours and is flagged and escalated on schedule. This was the costly one: +an agent who believed the tip stopped watching a live clock. + +Whether the platform *should* offer a business-hours calendar, per-agent or +per-tier SLA breakdowns, or a pausable clock stays open in #595 — this change +records today's behaviour only. Documentation in three locales; no metadata +under `src/` changed. Refs #917, #903, #886. diff --git a/content/docs/service/sla-and-escalation.mdx b/content/docs/service/sla-and-escalation.mdx index e36b077fc..daf53dbdf 100644 --- a/content/docs/service/sla-and-escalation.mdx +++ b/content/docs/service/sla-and-escalation.mdx @@ -24,7 +24,7 @@ In a list view, the thing that actually reports a breach is the **SLA Violated** Critical's four hours is the one target the system keeps, and it lives in the hook rather than on a Setup screen — see the *Tips for admins* section below. -> **Business hours** — the system can be configured to count only business hours (e.g., 9-5 Mon-Fri) rather than calendar hours. See [Administration › Setup](/docs/administration/setup). +> **Those four hours are calendar hours, not business hours.** This app has no business-hours setting — no working-day calendar, no holiday list, nothing anywhere in its metadata that a deadline could be counted against. The hook adds four hours to the wall clock (`due.setHours(due.getHours() + 4)` in `src/objects/case.hook.ts`), so a Critical case opened at 4pm on a Friday is due at 8pm that same Friday, and one opened at 11pm is due at 3am. Nights, weekends and holidays all count against the target. ## How the SLA is tracked @@ -44,12 +44,15 @@ Two views help with that, neither of them a timer: ## SLA performance reporting -The **SLA Performance** report shows the percentage of cases resolved within their SLA target, broken down by: +The **SLA Performance** report breaks its numbers down by **one** dimension: **priority**. Its `rows` are `['priority']` and nothing else (`src/reports/case.report.ts`). What it reports is not a compliance percentage either, but the **SLA Violation Rate** — the average of the **SLA Violated** flag — shown next to the case count and the average resolution time, and computed over **closed cases only** (`runtimeFilter: { is_closed: true }`). Of the four questions this page used to promise, it answers one: *which priority bucket is leaking?* -- Agent (who's hitting their SLA?) -- Priority (which priority bucket is leaking?) -- Account tier (are customers being treated worse than prospects?) -- Month (is performance trending up or down?) +The other three are not merely missing from the report — they are unreachable in the semantic layer underneath it. The `case_metrics` dataset (`src/datasets/case.dataset.ts`) declares exactly five dimensions — **Status**, **Priority**, **Origin**, **Type** and **Created** — so: + +- **Agent** — there is no owner or agent dimension. `owner_id` is a field on the case, but the dataset does not expose it, so no report and no dashboard widget can group by it. +- **Account tier** — `crm_account.tier` exists on the account object, but `case_metrics` reads `crm_case` alone and never crosses over to the account, so tier is not selectable anywhere in analytics. +- **Month** — **Created** buckets by **day** (`dateGranularity: 'day'`), not by month, and the SLA Performance report does not put it in `rows` at all. The report that does use it is **Cases Opened by Priority × Day**, a matrix of priority against day. + +Any of the three would mean changing `case_metrics` first; no setting on the report itself can bring them back. This report is the support team's most-used KPI. @@ -119,26 +122,30 @@ If priority resolves to **Critical**, the Copilot immediately recommends escalat | Role | What to check | When | | --- | --- | --- | -| **Agent** | My Open Cases (sorted by SLA Due Date) | Hourly during your shift | -| **Service Manager** | Breached SLA + Critical Cases | First thing every morning | +| **Agent** | My Open Cases — a priority queue, not a deadline queue | Hourly during your shift | +| **Service Manager** | Escalated Cases and SLA at Risk, plus the Service Dashboard's **SLA Violations** tile | First thing every morning | | **Service Director** | SLA Performance report | Weekly | | **Executive** | Service Dashboard | Weekly | +Two names this table used to carry are not views at all. **Breached SLA** and **Critical Cases** do not exist as list views: `crm_case` ships seven — *All Cases*, *Service Workflow*, *SLA Calendar*, *Case Timeline*, *My Open Cases*, *Escalated Cases* and *⏰ SLA at Risk* (`src/views/case.view.ts`) — and not one of them filters on **SLA Violated**. The only two surfaces that do filter on a breach are metric tiles on the [Service Dashboard](/docs/analytics/dashboards): **SLA Violations** (`is_sla_violated: true`) and **Critical Cases** (open and Critical). For a list you can actually work through, **Escalated Cases** is the closest thing: `case_sla_monitor` escalates every case it flags as breached, so each breach lands in it — mixed in with the cases escalated on priority alone. + +**My Open Cases is sorted by priority, not by SLA Due Date.** Its keys are `priority_rank` descending first, and `sla_due_date` ascending only as a tie-breaker (`src/views/case.view.ts`) — so a Low case due within the hour still sits below every Critical one. And because only Critical cases are stamped with a due date at all, the tie-breaker has no values to order the bands below Critical by: inside those bands the order is whatever the store returns. Keep **SLA at Risk** or **SLA Calendar** open next to it if you are working to deadlines. + ## Tips for service agents - ✅ Watch **SLA Due Date** yourself — there is no countdown and no amber zone to warn you, so keep **SLA at Risk** or **SLA Calendar** open during your shift and ask for help before the date passes. -- ✅ Use **Waiting on Customer** when you're genuinely blocked — depending on your config, this can pause the SLA clock. +- ✅ Use **Waiting on Customer** when you're genuinely blocked — but know that it **does not pause the SLA clock**, whatever your configuration. Nothing in this app pauses, extends or recomputes a deadline: `sla_due_date` is written once, the first time the case is Critical, and no later status change touches it; the hourly `case_sla_monitor` sweep collects open cases whose status is neither *Resolved* nor *Closed*, and *Waiting on Customer* is not on that exclusion list (`src/flows/case-sla-monitor.flow.ts`). So a Critical case parked on the customer runs its four hours down and is flagged **SLA Violated** and escalated on schedule. Set the status — it tells the team where the case stands — but keep watching the clock. - ✅ Don't artificially down-prioritise to extend your SLA — managers see priority change history. ## Tips for service managers -- ✅ Run the **Breached SLA** list view every morning. -- ✅ Use the **Service Board** kanban for daily standups. +- ✅ There is no **Breached SLA** list view to run. Work the **Escalated Cases** view instead — every case the SLA sweep flags gets escalated into it — and read the **SLA Violations** tile on the Service Dashboard for the count. +- ✅ Use the kanban board for daily standups — it is named **Service Workflow** (`case_workflow`) and reaches the case list as the **Workflow** tab. Nothing in this app is called *Service Board*. - ✅ Coach agents whose breach rate trends up — surface it 1:1 before it becomes a pattern. ## Tips for admins - The SLA target per priority is set via the case object's automation (a SLA-calculation hook). To adjust, edit `src/objects/case.hook.ts` (binds to `crm_case`) or change the underlying configuration — see [Administration › Automation](/docs/administration/automation). -- Business-hours vs. calendar-hours behaviour is controlled by your tenant's business-hours setup. See [Administration › Setup](/docs/administration/setup). +- **There is no business-hours vs. calendar-hours switch**, and no tenant business-hours setup behind it — this app ships no working-day calendar and no holiday list at all. The four-hour Critical target is added to the wall clock in `src/objects/case.hook.ts`, so nights, weekends and holidays count like any other hours; making a deadline skip non-working time means teaching that hook a calendar. - The escalation trigger — Critical priority, and nothing else; there is no High+Customer condition — lives in the [Case Escalation flow definition](/docs/administration/automation#flows-multi-step), i.e. `src/flows/case-escalation.flow.ts`. Two flows carry it: `case_escalation` (on update) and `case_escalation_on_create` (on insert). Change the condition in **both**, or a case created at the new priority still slips through. - Neither recipient list is configurable on a Setup screen. *Notify on Critical* is the Case Escalation flow's `notify` node, and its list is the single entry `{caseRecord.owner_id}` — edit it in `src/flows/case-escalation.flow.ts`. *Notify on Escalation* has no recipient list at all, because it sends no message: what the escalated status fires is the `case_status_side_effects` hook in `src/objects/case.hook.ts`, and the person it reaches is the account owner, through the follow-up task. diff --git a/content/docs/service/sla-and-escalation.zh-Hans.mdx b/content/docs/service/sla-and-escalation.zh-Hans.mdx index bcf64a64a..5f5485434 100644 --- a/content/docs/service/sla-and-escalation.zh-Hans.mdx +++ b/content/docs/service/sla-and-escalation.zh-Hans.mdx @@ -24,7 +24,7 @@ SLA(服务级别协议)系统为 Critical 工单打上一个**截止时间** Critical 的 4 小时是系统唯一会盯的目标,而且它写在钩子里,不在任何设置页面上——参见下方的*给管理员的提示*部分。 -> **营业时间**——系统可以配置为只计算营业时间(例如周一至周五 9-5),而非日历时间。参见 [管理 › 设置](/zh-Hans/docs/administration/setup)。 +> **这 4 小时是日历小时,不是营业时间。** 本应用没有任何营业时间设置——没有工作日日历,没有节假日清单,元数据里也不存在任何可供截止时间去对照的东西。钩子只是往当前时钟上加 4 小时(`src/objects/case.hook.ts` 里的 `due.setHours(due.getHours() + 4)`),所以一个周五下午 4 点建的 Critical 工单,截止时间就是同一个周五晚上 8 点;晚上 11 点建的,截止时间是凌晨 3 点。夜间、周末与节假日一律照算进这个目标里。 ## SLA 如何被跟踪 @@ -44,12 +44,15 @@ Critical 的 4 小时是系统唯一会盯的目标,而且它写在钩子里 ## SLA 表现报表 -**SLA 表现**报表显示在 SLA 目标内解决的工单百分比,并按以下维度细分: +**SLA 表现**报表只按**一个**维度细分:**优先级**。它的 `rows` 就是 `['priority']`,没有别的(`src/reports/case.report.ts`)。而且它报的也不是"在目标内解决的百分比",而是 **SLA 违约率**——**SLA 已违约**标记的平均值——与工单数、平均解决时长并列,并且只统计**已关闭的工单**(`runtimeFilter: { is_closed: true }`)。所以本页过去许诺的四个问题,它只回答其中一个:*哪个优先级桶在漏单?* -- 客服(谁达成了他们的 SLA?) -- 优先级(哪个优先级桶在漏单?) -- 账户等级(客户是否被比潜在客户更差地对待?) -- 月份(表现是趋升还是趋降?) +另外三个不只是"报表里没放",而是在它底下的语义层里根本够不着。`case_metrics` 数据集(`src/datasets/case.dataset.ts`)总共只声明了五个维度——**状态**、**优先级**、**来源**、**类型**、**创建时间**——因此: + +- **客服**——不存在负责人或客服维度。`owner_id` 是工单上的字段,但数据集没有把它暴露成维度,所以没有任何报表、也没有任何仪表盘部件能按它分组。 +- **账户等级**——`crm_account.tier` 确实存在于账户对象上,但 `case_metrics` 只读 `crm_case`,从不跨到账户上去取它,所以分析侧任何地方都选不到账户等级。 +- **月份**——**创建时间**这个维度按**天**分桶(`dateGranularity: 'day'`),不是按月;而且 SLA 表现报表压根没把它放进 `rows`。真正用到它的是**按优先级 × 天的建单量**报表,那是一张优先级对天的矩阵。 + +想要这三个里的任何一个,都得先改 `case_metrics`;报表本身没有任何设置能把它们变出来。 这份报表是支持团队最常用的 KPI。 @@ -119,26 +122,30 @@ Critical 的 4 小时是系统唯一会盯的目标,而且它写在钩子里 | 角色 | 查看什么 | 何时 | | --- | --- | --- | -| **客服** | My Open Cases(按 SLA 截止日期排序) | 当班期间每小时 | -| **服务经理** | Breached SLA + Critical Cases | 每天一早 | +| **客服** | My Open Cases——一个按优先级排的队列,不是按截止时间排的队列 | 当班期间每小时 | +| **服务经理** | Escalated Cases 与 SLA at Risk 两个视图,外加服务仪表盘上的 **SLA Violations** 磁贴 | 每天一早 | | **服务总监** | SLA 表现报表 | 每周 | | **高管** | 服务仪表盘 | 每周 | +这张表过去写的两个名字根本不是视图。**Breached SLA** 与 **Critical Cases** 都不存在于列表视图里:`crm_case` 随产品提供的视图一共七个——*All Cases*、*Service Workflow*、*SLA Calendar*、*Case Timeline*、*My Open Cases*、*Escalated Cases* 与 *⏰ SLA at Risk*(`src/views/case.view.ts`)——其中没有任何一个以 **SLA 已违约**为过滤条件。真正按违约过滤的只有[服务仪表盘](/zh-Hans/docs/analytics/dashboards)上的两个指标磁贴:**SLA Violations**(`is_sla_violated: true`)与 **Critical Cases**(未结 + Critical)。如果你要的是一份能逐条处理的列表,**Escalated Cases** 是最接近的那个:`case_sla_monitor` 会把它标记为违约的每一个工单都升级掉,所以每一次违约都会落进这个视图——只是会和那些仅因优先级而升级的工单混在一起。 + +**My Open Cases 是按优先级排序的,不是按 SLA 截止日期。** 它的排序键是 `priority_rank` 降序在先、`sla_due_date` 升序仅作次级键(`src/views/case.view.ts`)——所以一个一小时后就到期的 Low 工单,仍然排在每一个 Critical 工单下面。又因为只有 Critical 工单才会被打上截止日期,次级键在 Critical 以下的各档里根本无值可排:同一档内的先后顺序,取决于存储返回的顺序。如果你是按截止时间在干活,请在它旁边同时开着 **SLA at Risk** 或 **SLA Calendar**。 + ## 给服务客服的提示 - ✅ 自己盯着 **SLA 截止日期**——没有倒计时,也没有琥珀色区域会来提醒你,所以当班时把 **SLA at Risk** 或 **SLA Calendar** 视图开着,赶在日期过去之前求助。 -- ✅ 当你确实被阻塞时使用 **Waiting on Customer**——取决于你的配置,这可以暂停 SLA 计时。 +- ✅ 当你确实被阻塞时使用 **Waiting on Customer**——但要知道它**不会暂停 SLA 计时**,无论你怎么配置。本应用里没有任何东西会暂停、顺延或重算一个截止时间:`sla_due_date` 只在工单第一次成为 Critical 时写入一次,此后任何状态流转都不会再碰它;每小时一轮的 `case_sla_monitor` 扫描捞的是状态既不是 *Resolved* 也不是 *Closed* 的未结工单,而 *Waiting on Customer* 不在这份排除清单里(`src/flows/case-sla-monitor.flow.ts`)。所以一个挂在等客户回复上的 Critical 工单,4 小时照走,到点照样被标 **SLA 已违约**并升级。该切状态还是要切——它让团队知道这单卡在哪儿——但别因此不盯表了。 - ✅ 不要人为降低优先级来延长你的 SLA——经理可以看到优先级变更历史。 ## 给服务经理的提示 -- ✅ 每天早上运行 **Breached SLA** 列表视图。 -- ✅ 使用 **Service Board** 看板进行每日站会。 +- ✅ 没有 **Breached SLA** 这个列表视图可以运行。改去处理 **Escalated Cases** 视图——SLA 扫描标记的每一个工单都会被升级进这个视图——数量则看服务仪表盘上的 **SLA Violations** 磁贴。 +- ✅ 每日站会用那块看板,但它叫 **Service Workflow**(`case_workflow`),在工单列表上以 **Workflow** 页签出现。本应用里不存在叫 *Service Board* 的东西。 - ✅ 辅导那些违约率趋升的客服——在它形成模式之前于 1:1 中提出。 ## 给管理员的提示 - 每个优先级的 SLA 目标通过工单对象的自动化(一个 SLA 计算钩子)设置。要调整,请编辑 `src/objects/case.hook.ts`(绑定到 `crm_case`)或更改底层配置——参见 [管理 › 自动化](/zh-Hans/docs/administration/automation)。 -- 营业时间与日历时间的行为由你租户的营业时间设置控制。参见 [管理 › 设置](/zh-Hans/docs/administration/setup)。 +- **不存在"营业时间 vs. 日历时间"这个开关**,它背后也不存在什么租户级的营业时间设置——本应用根本没有工作日日历,也没有节假日清单。Critical 的 4 小时目标是在 `src/objects/case.hook.ts` 里往当前时钟上加出来的,所以夜间、周末与节假日一律照算;要让截止时间跳过非工作时段,就得先把一套日历教给这个钩子。 - 升级触发条件——只有 Critical 优先级这一项,不存在 High+Customer 这个条件——写在 [工单升级流程定义](/zh-Hans/docs/administration/automation)里,即 `src/flows/case-escalation.flow.ts`。承载它的是两个流程:`case_escalation`(更新时)与 `case_escalation_on_create`(新建时)。要改就**两个一起改**,否则以新条件新建的工单仍会漏掉。 - 这两处的收件人列表都不是 Setup 界面上的配置项。*紧急时通知* 就是工单升级流程的 `notify` 节点,其列表只有 `{caseRecord.owner_id}` 一项——要改就改 `src/flows/case-escalation.flow.ts`。*升级时通知* 根本没有收件人列表,因为它不发出任何消息:状态转为已升级触发的是 `src/objects/case.hook.ts` 里的 `case_status_side_effects` 钩子,它触达的是账户负责人,靠的是那条跟进任务。 diff --git a/content/docs/service/sla-and-escalation.zh-Hant.mdx b/content/docs/service/sla-and-escalation.zh-Hant.mdx index e4d2f17e6..b046ee9be 100644 --- a/content/docs/service/sla-and-escalation.zh-Hant.mdx +++ b/content/docs/service/sla-and-escalation.zh-Hant.mdx @@ -24,7 +24,7 @@ SLA(服務級別協議)系統為 Critical 工單打上一個**截止時間** Critical 的 4 小時是系統唯一會盯的目標,而且它寫在鉤子裡,不在任何設定頁面上——參見下方的*給管理員的提示*部分。 -> **營業時間**——系統可以配置為只計算營業時間(例如週一至週五 9-5),而非日曆時間。參見 [管理 › 設定](/zh-Hant/docs/administration/setup)。 +> **這 4 小時是日曆小時,不是營業時間。** 本應用沒有任何營業時間設定——沒有工作日日曆,沒有假日清單,中繼資料裡也不存在任何可供截止時間去對照的東西。鉤子只是往當前時鐘上加 4 小時(`src/objects/case.hook.ts` 裡的 `due.setHours(due.getHours() + 4)`),所以一個週五下午 4 點建的 Critical 工單,截止時間就是同一個週五晚上 8 點;晚上 11 點建的,截止時間是凌晨 3 點。夜間、週末與假日一律照算進這個目標裡。 ## SLA 如何被追蹤 @@ -44,12 +44,15 @@ Critical 的 4 小時是系統唯一會盯的目標,而且它寫在鉤子裡 ## SLA 表現報表 -**SLA 表現**報表顯示在 SLA 目標內解決的工單百分比,並按以下維度細分: +**SLA 表現**報表只按**一個**維度細分:**優先順序**。它的 `rows` 就是 `['priority']`,沒有別的(`src/reports/case.report.ts`)。而且它報的也不是"在目標內解決的百分比",而是 **SLA 違約率**——**SLA 已違約**標記的平均值——與工單數、平均解決時長並列,並且只統計**已關閉的工單**(`runtimeFilter: { is_closed: true }`)。所以本頁過去許諾的四個問題,它只回答其中一個:*哪個優先順序桶在漏單?* -- 客服(誰達成了他們的 SLA?) -- 優先順序(哪個優先順序桶在漏單?) -- 帳戶等級(客戶是否被比潛在客戶更差地對待?) -- 月份(表現是趨升還是趨降?) +另外三個不只是"報表裡沒放",而是在它底下的語意層裡根本搆不著。`case_metrics` 資料集(`src/datasets/case.dataset.ts`)總共只宣告了五個維度——**狀態**、**優先順序**、**來源**、**類型**、**建立時間**——因此: + +- **客服**——不存在負責人或客服維度。`owner_id` 是工單上的欄位,但資料集沒有把它暴露成維度,所以沒有任何報表、也沒有任何儀表板部件能按它分組。 +- **帳戶等級**——`crm_account.tier` 確實存在於帳戶物件上,但 `case_metrics` 只讀 `crm_case`,從不跨到帳戶上去取它,所以分析側任何地方都選不到帳戶等級。 +- **月份**——**建立時間**這個維度按**天**分桶(`dateGranularity: 'day'`),不是按月;而且 SLA 表現報表壓根沒把它放進 `rows`。真正用到它的是**按優先順序 × 天的建單量**報表,那是一張優先順序對天的矩陣。 + +想要這三個裡的任何一個,都得先改 `case_metrics`;報表本身沒有任何設定能把它們變出來。 這份報表是支援團隊最常用的 KPI。 @@ -119,26 +122,30 @@ Critical 的 4 小時是系統唯一會盯的目標,而且它寫在鉤子裡 | 角色 | 查看什麼 | 何時 | | --- | --- | --- | -| **客服** | My Open Cases(按 SLA 截止日期排序) | 當班期間每小時 | -| **服務經理** | Breached SLA + Critical Cases | 每天一早 | +| **客服** | My Open Cases——一個按優先順序排的佇列,不是按截止時間排的佇列 | 當班期間每小時 | +| **服務經理** | Escalated Cases 與 SLA at Risk 兩個檢視,外加服務儀表板上的 **SLA Violations** 磁貼 | 每天一早 | | **服務總監** | SLA 表現報表 | 每週 | | **高管** | 服務儀表板 | 每週 | +這張表過去寫的兩個名字根本不是檢視。**Breached SLA** 與 **Critical Cases** 都不存在於列表檢視裡:`crm_case` 隨產品提供的檢視一共七個——*All Cases*、*Service Workflow*、*SLA Calendar*、*Case Timeline*、*My Open Cases*、*Escalated Cases* 與 *⏰ SLA at Risk*(`src/views/case.view.ts`)——其中沒有任何一個以 **SLA 已違約**為過濾條件。真正按違約過濾的只有[服務儀表板](/zh-Hant/docs/analytics/dashboards)上的兩個指標磁貼:**SLA Violations**(`is_sla_violated: true`)與 **Critical Cases**(未結 + Critical)。如果你要的是一份能逐條處理的列表,**Escalated Cases** 是最接近的那個:`case_sla_monitor` 會把它標記為違約的每一個工單都升級掉,所以每一次違約都會落進這個檢視——只是會和那些僅因優先順序而升級的工單混在一起。 + +**My Open Cases 是按優先順序排序的,不是按 SLA 截止日期。** 它的排序鍵是 `priority_rank` 降序在先、`sla_due_date` 升序僅作次級鍵(`src/views/case.view.ts`)——所以一個一小時後就到期的 Low 工單,仍然排在每一個 Critical 工單下面。又因為只有 Critical 工單才會被打上截止日期,次級鍵在 Critical 以下的各檔裡根本無值可排:同一檔內的先後順序,取決於儲存返回的順序。如果你是按截止時間在幹活,請在它旁邊同時開著 **SLA at Risk** 或 **SLA Calendar**。 + ## 給服務客服的提示 - ✅ 自己盯著 **SLA 截止日期**——沒有倒數計時,也沒有琥珀色區域會來提醒你,所以當班時把 **SLA at Risk** 或 **SLA Calendar** 檢視開著,趕在日期過去之前求助。 -- ✅ 當你確實被阻塞時使用 **Waiting on Customer**——取決於你的配置,這可以暫停 SLA 計時。 +- ✅ 當你確實被阻塞時使用 **Waiting on Customer**——但要知道它**不會暫停 SLA 計時**,無論你怎麼配置。本應用裡沒有任何東西會暫停、順延或重算一個截止時間:`sla_due_date` 只在工單第一次成為 Critical 時寫入一次,此後任何狀態流轉都不會再碰它;每小時一輪的 `case_sla_monitor` 掃描撈的是狀態既不是 *Resolved* 也不是 *Closed* 的未結工單,而 *Waiting on Customer* 不在這份排除清單裡(`src/flows/case-sla-monitor.flow.ts`)。所以一個掛在等客戶回覆上的 Critical 工單,4 小時照走,到點照樣被標 **SLA 已違約**並升級。該切狀態還是要切——它讓團隊知道這單卡在哪兒——但別因此不盯錶了。 - ✅ 不要人為降低優先順序來延長你的 SLA——經理可以看到優先順序變更歷史。 ## 給服務經理的提示 -- ✅ 每天早上執行 **Breached SLA** 列表檢視。 -- ✅ 使用 **Service Board** 看板進行每日站會。 +- ✅ 沒有 **Breached SLA** 這個列表檢視可以執行。改去處理 **Escalated Cases** 檢視——SLA 掃描標記的每一個工單都會被升級進這個檢視——數量則看服務儀表板上的 **SLA Violations** 磁貼。 +- ✅ 每日站會用那塊看板,但它叫 **Service Workflow**(`case_workflow`),在工單列表上以 **Workflow** 頁籤出現。本應用裡不存在叫 *Service Board* 的東西。 - ✅ 輔導那些違約率趨升的客服——在它形成模式之前於 1:1 中提出。 ## 給管理員的提示 - 每個優先順序的 SLA 目標透過工單物件的自動化(一個 SLA 計算鉤子)設定。要調整,請編輯 `src/objects/case.hook.ts`(綁定到 `crm_case`)或更改底層配置——參見 [管理 › 自動化](/zh-Hant/docs/administration/automation)。 -- 營業時間與日曆時間的行為由你租戶的營業時間設定控制。參見 [管理 › 設定](/zh-Hant/docs/administration/setup)。 +- **不存在"營業時間 vs. 日曆時間"這個開關**,它背後也不存在什麼租戶級的營業時間設定——本應用根本沒有工作日日曆,也沒有假日清單。Critical 的 4 小時目標是在 `src/objects/case.hook.ts` 裡往當前時鐘上加出來的,所以夜間、週末與假日一律照算;要讓截止時間跳過非工作時段,就得先把一套日曆教給這個鉤子。 - 升級觸發條件——只有 Critical 優先順序這一項,不存在 High+Customer 這個條件——寫在 [工單升級流程定義](/zh-Hant/docs/administration/automation)裡,即 `src/flows/case-escalation.flow.ts`。承載它的是兩個流程:`case_escalation`(更新時)與 `case_escalation_on_create`(新建時)。要改就**兩個一起改**,否則以新條件新建的工單仍會漏掉。 - 這兩處的收件人列表都不是 Setup 介面上的設定項。*緊急時通知* 就是工單升級流程的 `notify` 節點,其列表只有 `{caseRecord.owner_id}` 一項——要改就改 `src/flows/case-escalation.flow.ts`。*升級時通知* 根本沒有收件人列表,因為它不發出任何訊息:狀態轉為已升級觸發的是 `src/objects/case.hook.ts` 裡的 `case_status_side_effects` 鉤子,它觸達的是帳戶負責人,靠的是那條跟進任務。