From 9f9f22c3f3e31618de7d2aebe6099300c7d24cc9 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 31 Aug 2026 04:31:51 +0000 Subject: [PATCH] docs(service): document the triage claim gesture in all three locales MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The claim seam shipped without its documentation half. Moving an unowned case to In Progress, Waiting on Customer or Waiting on Support makes the person doing it the case's owner, in the same save — real behaviour with nothing written down, because the PR that landed it could not touch content/docs. Re-derived from src/ rather than from the card: - the three claiming statuses are CLAIMABLE_TARGET_STATUSES in src/objects/_case-assignment.ts, and the hook stands down on a payload carrying owner_id, on an already-owned case, on a closed case, and on a write with no user (seed / system); - the destination view is labelled My Open Cases, not "My Cases"; - case_unassigned_triage_sharing excludes resolved AND closed (record.owner_id == null && status != "resolved" && status != "closed"), unlike the two escalation rules beside it, which really are is_closed == false. service/cases gains the gesture end to end — the three statuses that claim, the four that deliberately do not, and why the claim cannot be spelled as an owner edit. sharing-and-security gains the admin half: Unassigned Cases — Triage is the one shipped rule meant to be spent rather than held, and the claim is what ends the grant. Claiming joins the everyday actions that write Owner without being transfers, which is why it needs no new permission. The rule's own row said "open cases with no owner" / "没有负责人的未关闭工单", which overstated the grant by omitting Resolved; corrected in all three locales. Part of #1144 — piece 2 (a claim_case action) is deliberately not built. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QaBNJyp9XkRodoRNfGuUTo --- .../document-the-triage-claim-gesture.md | 33 +++++++++++++++++++ .../administration/sharing-and-security.mdx | 31 +++++++++++++++-- .../sharing-and-security.zh-Hans.mdx | 15 +++++++-- .../sharing-and-security.zh-Hant.mdx | 15 +++++++-- content/docs/service/cases.mdx | 18 ++++++++++ content/docs/service/cases.zh-Hans.mdx | 18 ++++++++++ content/docs/service/cases.zh-Hant.mdx | 18 ++++++++++ content/docs/service/index.mdx | 1 + content/docs/service/index.zh-Hans.mdx | 1 + content/docs/service/index.zh-Hant.mdx | 1 + 10 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 .changeset/document-the-triage-claim-gesture.md diff --git a/.changeset/document-the-triage-claim-gesture.md b/.changeset/document-the-triage-claim-gesture.md new file mode 100644 index 000000000..b0eb3376c --- /dev/null +++ b/.changeset/document-the-triage-claim-gesture.md @@ -0,0 +1,33 @@ +--- +'hotcrm': patch +--- + +Document the triage claim gesture, in all three locales. + +The claim seam shipped without its documentation half: an unowned case in +**Unassigned — triage** becomes yours when you move it to *In Progress*, +*Waiting on Customer* or *Waiting on Support* — the app stamps you as its Owner +in the same save — after which it leaves that tab and appears in **My Open +Cases**. That was real behaviour with nothing written down, because the PR that +landed it could not touch `content/docs/**`. + +`service/cases` now carries the gesture end to end: the three statuses that +claim, the four that deliberately do not (*New* is the state the row is already +in; *Escalated* belongs to the escalation hand-off; resolving or closing a case +is not picking it up, and leaves it ownerless), and the reason the claim cannot +be spelled as an owner edit — a save carrying Owner is refused for an agent +whatever name it holds, so the status move is the only spelling and the only +name it can write is the caller's own. + +`administration/sharing-and-security` gains the admin-facing half: +*Unassigned Cases — Triage* is the one shipped rule meant to be **spent** rather +than held — it opens an unowned case to every `service_agent`, and the claim is +what ends the grant. Claiming is added to the list of everyday actions that +write Owner without being transfers, which is why the gesture needs no new +permission. + +Two accuracy fixes ride along on the pages being edited. The rule's row said +`service_agent` gets unowned **cases that are not closed**; the rule also +excludes *Resolved*, so the row overstated the grant in all three locales. And +the two Chinese pages' rows are confirmed present — the earlier gap they were +filed for is already closed. diff --git a/content/docs/administration/sharing-and-security.mdx b/content/docs/administration/sharing-and-security.mdx index b09602904..1fbb85afd 100644 --- a/content/docs/administration/sharing-and-security.mdx +++ b/content/docs/administration/sharing-and-security.mdx @@ -94,7 +94,7 @@ Criteria-based rules are the enforced flavour: matching records materialise real | Large Open Deals — Executive | Opportunity | Read | `executive` — the same deals, one rung up | | Escalated Cases Sharing | Case | Edit | `service_manager` — open critical cases | | Escalated Cases — Service Director | Case | Read | `service_director` — the same cases, one rung up | -| Unassigned Cases — Triage | Case | Edit | `service_agent` — open cases with no owner | +| Unassigned Cases — Triage | Case | Edit | `service_agent` — unowned cases, until they are Resolved or Closed | | Live Campaigns — Marketing Manager | Campaign | Edit | `marketing_manager` — planning / in-progress campaigns | | Live Campaigns — Marketing Director | Campaign | Edit | `marketing_director` — the same campaigns | @@ -111,6 +111,28 @@ Create your own in **Setup → Sharing Rules**. > UI marks such a rule as broken, so when a team reports missing records, check > that every field the rule names is a plain field on the object. +### A grant meant to be spent: *Unassigned Cases — Triage* + +Most sharing rules are standing openings: a rule that matches a record today matches it again tomorrow, and the recipients keep the access for as long as the record fits the criteria. *Unassigned Cases — Triage* is the one rule built to be **used up**. It grants every `service_agent` **Edit** on cases that have no owner and are neither *Resolved* nor *Closed* — the grant behind the case list's **Unassigned — triage** tab — and it exists so that an agent can take one of those cases. Taking it is what ends the grant: + +1. A case arrives with **no owner** — a web-to-case submission that landed while nobody held the Service Agent position. The rule matches it, so every service agent can see and edit it. +2. An agent moves it to **In Progress**, **Waiting on Customer** or **Waiting on Support**. The app stamps that agent as the case's **Owner** in the same save. +3. The case now has an owner, so the rule no longer matches. It drops out of the shared pool and out of the tab, and the agent holds it the ordinary way — as its owner. + +> **The claim writes Owner without anyone holding a transfer permission, and +> that is the design rather than a gap.** Service Agent may reassign tasks only +> (see *Ownership and transfers* below), and a save that carries Owner is +> refused for an agent whatever name it holds — their own included. So the claim +> is not an owner edit that got approved: it is a **status move the app reads as +> "I am taking this"**, and the only name it can write is the caller's own, onto +> a case that has no owner yet. *Claim it for somebody else* and *claim a case +> somebody already owns* have no spelling at all, which is why the gesture needs +> no new permission. It is not agent-only either: anyone who moves an unowned +> open case into one of those three statuses claims it that way, an +> administrator or a service manager included. Automation does not — a seeded or +> system write leaves the case ownerless, which is what keeps first-install +> intake visible in the tab. + ### A rule widens one object, not the records underneath it Sharing rules are authored **per object**. Widening `Account` widens accounts — the records hanging off a shared account keep their own baseline, and Contact is the only one derived from it: @@ -166,7 +188,7 @@ from ordinary edit rights: | Service Agent | tasks only (so an escalation can hand work to the account owner) | | Sales Rep, Marketing User | nothing — records are assigned *to* them | -Three everyday actions are **not** transfers and need no such permission: +Four everyday actions are **not** transfers and need no such permission: - **Creating a record.** New records are stamped to their creator automatically — you never pick yourself. @@ -174,6 +196,11 @@ Three everyday actions are **not** transfers and need no such permission: field. - **Automation acting on your behalf** — the round-robin that routes an incoming lead, the nightly sweeps that book renewal and follow-up tasks. +- **Claiming an unowned case.** Moving a case that has nobody on it into *In + Progress*, *Waiting on Customer* or *Waiting on Support* makes you its owner + (see *A grant meant to be spent* above). Owner does change — but the move + names no one, takes the record away from no one, and works only while the case + is ownerless, so it is not a reassignment and needs no reassignment right. A user without the permission who tries to reassign gets a clear refusal rather than a silent no-op. If you need to move a book of business, ask an diff --git a/content/docs/administration/sharing-and-security.zh-Hans.mdx b/content/docs/administration/sharing-and-security.zh-Hans.mdx index 1bae34380..194c80924 100644 --- a/content/docs/administration/sharing-and-security.zh-Hans.mdx +++ b/content/docs/administration/sharing-and-security.zh-Hans.mdx @@ -94,7 +94,7 @@ na_sales_team eu_sales_team (区域分组) | Large Open Deals — Executive | 商机 | 读取 | `executive` —— 同一批交易,上一层级 | | Escalated Cases Sharing | 工单 | 编辑 | `service_manager` —— 未关闭的紧急工单 | | Escalated Cases — Service Director | 工单 | 读取 | `service_director` —— 同一批工单,上一层级 | -| Unassigned Cases — Triage | 工单 | 编辑 | `service_agent` —— 没有负责人的未关闭工单 | +| Unassigned Cases — Triage | 工单 | 编辑 | `service_agent` —— 没有负责人的工单,直到它被 Resolved 或 Closed | | Live Campaigns — Marketing Manager | 营销活动 | 编辑 | `marketing_manager` —— 筹划中 / 进行中的活动 | | Live Campaigns — Marketing Director | 营销活动 | 编辑 | `marketing_director` —— 同一批活动 | @@ -102,6 +102,16 @@ na_sales_team eu_sales_team (区域分组) > **条件只能过滤普通字段,不能过滤地址的某一部分。** 两条区域规则匹配的是客户上的 **账单国家** —— 一个只读的两位国家代码,由你在 **账单地址** 中填写的国家推导而来 —— 而不是地址本身。条件规则必须以数据库查询的形式运行,而查询无法深入结构化的地址或位置值内部。因此,针对 `账单地址 → 国家` 编写的规则会被**直接拒绝**,而不是被悄悄放宽成"所有客户":它根本不会被安装,它指定的岗位也就什么都拿不到。界面上不会把这样的规则标记为失效,所以当某个团队反馈记录缺失时,请检查规则里引用的每个字段是否都是该对象上的普通字段。 +### 一条为「被用掉」而设的授权:*Unassigned Cases — Triage* + +大多数共享规则是常设的开口:今天匹配某条记录的规则明天照样匹配它,只要记录还符合条件,接收方就一直持有那份访问权。*Unassigned Cases — Triage* 是唯一一条**为被用掉而设计**的规则。它把**编辑**权授予每一位 `service_agent`,覆盖没有负责人、且既不是 *Resolved* 也不是 *Closed* 的工单——也就是工单列表里 **Unassigned — triage** 标签页背后的那条授权——它存在的意义,就是让某位客服把其中一张工单接走。而接走它,正是这份授权终结的方式: + +1. 一张工单**没有负责人**地到达——比如没有人担任服务坐席时 Web 提交进来的那种。规则匹配上了它,于是每一位客服都能看到并编辑它。 +2. 某位客服把它转到 **In Progress**、**Waiting on Customer** 或 **Waiting on Support**。应用在同一次保存里把这位客服标记为该工单的**负责人**。 +3. 工单现在有负责人了,规则不再匹配它。它退出共享池、也退出那个标签页,而这位客服从此以负责人的身份、用最普通的方式持有它。 + +> **认领会写入负责人,却不需要任何人持有转移权限——这是设计,不是漏洞。** 客服专员只能转移任务(见下文*归属与转移*),而带着负责人字段的保存对客服一律被拒绝,无论填的是谁,填他自己也一样。所以认领不是一次「被批准的负责人编辑」,而是一个**被应用读作「我把这张接了」的状态变更**:它能写入的名字只有调用者自己,而且只能写到一张还没有负责人的工单上。「替别人认领」和「认领一张已经有主的工单」根本没有写法,这正是这个动作不需要任何新权限的原因。它也不是客服专属的:任何人把一张无主的未结工单转入那三种状态,都以同样的方式认领了它,管理员和服务经理也不例外。自动化则不会——种子写入或系统写入让工单保持无主,这正是首次安装时那些工单还能留在标签页里被看见的原因。 + ### 一条规则放开的是一个对象,而不是它下面的记录 共享规则是 **按对象** 编写的。放开 `Account` 只放开客户本身 —— 挂在这个客户下的记录仍然各自守着自己的基线,其中只有联系人是从客户派生的: @@ -152,11 +162,12 @@ HotCRM **不提供客户团队对象** —— 客户上没有团队名单,也 | 客服专员 | 仅任务(以便升级时把工作交给客户负责人) | | 销售代表、市场用户 | 无——记录是被指派给他们的 | -有三类日常操作**不算**转移,因而不需要该权限: +有四类日常操作**不算**转移,因而不需要该权限: - **新建记录。** 新记录会自动归属到创建者,你无需手动选择自己。 - **保存表单**时未改动负责人——即使表单会把该字段一并提交。 - **自动化代你执行**——分配新线索的轮询、夜间生成续约与跟进任务的批处理。 +- **认领一张无主工单。** 把一张没有任何人负责的工单转入 *In Progress*、*Waiting on Customer* 或 *Waiting on Support*,你就成了它的负责人(见上文*一条为「被用掉」而设的授权*)。负责人确实变了——但这个动作没有指定任何人、没有把记录从任何人手里拿走,而且只在工单无主时才起作用,所以它不是一次转移,也不需要转移权限。 没有该权限的用户尝试转移时会收到明确的拒绝提示,而不是悄无声息地无效。需要整体移交业务簿时,请联系管理员或你的销售经理。 diff --git a/content/docs/administration/sharing-and-security.zh-Hant.mdx b/content/docs/administration/sharing-and-security.zh-Hant.mdx index ef4c9612a..f76870c57 100644 --- a/content/docs/administration/sharing-and-security.zh-Hant.mdx +++ b/content/docs/administration/sharing-and-security.zh-Hant.mdx @@ -94,7 +94,7 @@ na_sales_team eu_sales_team (區域分組) | Large Open Deals — Executive | 商機 | 讀取 | `executive` —— 同一批交易,上一層級 | | Escalated Cases Sharing | 案件 | 編輯 | `service_manager` —— 未關閉的緊急案件 | | Escalated Cases — Service Director | 案件 | 讀取 | `service_director` —— 同一批案件,上一層級 | -| Unassigned Cases — Triage | 案件 | 編輯 | `service_agent` —— 沒有負責人的未關閉案件 | +| Unassigned Cases — Triage | 案件 | 編輯 | `service_agent` —— 沒有負責人的案件,直到它被 Resolved 或 Closed | | Live Campaigns — Marketing Manager | 行銷活動 | 編輯 | `marketing_manager` —— 籌劃中 / 進行中的活動 | | Live Campaigns — Marketing Director | 行銷活動 | 編輯 | `marketing_director` —— 同一批活動 | @@ -102,6 +102,16 @@ na_sales_team eu_sales_team (區域分組) > **條件只能過濾普通欄位,不能過濾地址的某一部分。** 兩條區域規則比對的是客戶上的 **帳單國家** —— 一個唯讀的兩位國家代碼,由你在 **帳單地址** 中填寫的國家推導而來 —— 而不是地址本身。條件規則必須以資料庫查詢的形式執行,而查詢無法深入結構化的地址或位置值內部。因此,針對 `帳單地址 → 國家` 撰寫的規則會被**直接拒絕**,而不是被悄悄放寬成「所有客戶」:它根本不會被安裝,它指定的職位也就什麼都拿不到。介面上不會把這樣的規則標記為失效,所以當某個團隊回報記錄缺失時,請檢查規則裡引用的每個欄位是否都是該物件上的普通欄位。 +### 一條為「被用掉」而設的授權:*Unassigned Cases — Triage* + +大多數共用規則是常設的開口:今天符合某筆記錄的規則明天照樣符合它,只要記錄還符合條件,接收方就一直持有那份存取權。*Unassigned Cases — Triage* 是唯一一條**為被用掉而設計**的規則。它把**編輯**權授予每一位 `service_agent`,涵蓋沒有負責人、且既不是 *Resolved* 也不是 *Closed* 的案件——也就是案件清單裡 **Unassigned — triage** 標籤頁背後的那條授權——它存在的意義,就是讓某位客服把其中一張案件接走。而接走它,正是這份授權終結的方式: + +1. 一張案件**沒有負責人**地抵達——比如沒有人擔任服務座席時 Web 提交進來的那種。規則符合了它,於是每一位客服都能看到並編輯它。 +2. 某位客服把它轉到 **In Progress**、**Waiting on Customer** 或 **Waiting on Support**。應用在同一次儲存裡把這位客服標記為該案件的**負責人**。 +3. 案件現在有負責人了,規則不再符合它。它退出共用池、也退出那個標籤頁,而這位客服從此以負責人的身分、用最普通的方式持有它。 + +> **認領會寫入負責人,卻不需要任何人持有轉移權限——這是設計,不是漏洞。** 客服專員只能轉移任務(見下文*歸屬與轉移*),而帶著負責人欄位的儲存對客服一律被拒絕,無論填的是誰,填他自己也一樣。所以認領不是一次「被批准的負責人編輯」,而是一個**被應用讀作「我把這張接了」的狀態變更**:它能寫入的名字只有呼叫者自己,而且只能寫到一張還沒有負責人的案件上。「替別人認領」和「認領一張已經有主的案件」根本沒有寫法,這正是這個動作不需要任何新權限的原因。它也不是客服專屬的:任何人把一張無主的未結案件轉入那三種狀態,都以同樣的方式認領了它,管理員和服務經理也不例外。自動化則不會——種子寫入或系統寫入讓案件保持無主,這正是首次安裝時那些案件還能留在標籤頁裡被看見的原因。 + ### 一條規則放開的是一個物件,而不是它底下的記錄 共用規則是 **按物件** 撰寫的。放開 `Account` 只放開客戶本身 —— 掛在這個客戶底下的記錄仍各自守著自己的基線,其中只有聯絡人是從客戶衍生的: @@ -152,11 +162,12 @@ HotCRM **不提供客戶團隊物件** —— 客戶上沒有團隊名單,也 | 客服專員 | 僅任務(以便升級時把工作交給客戶負責人) | | 銷售代表、行銷使用者 | 無——記錄是被指派給他們的 | -有三類日常操作**不算**轉移,因此不需要該權限: +有四類日常操作**不算**轉移,因此不需要該權限: - **建立記錄。** 新記錄會自動歸屬到建立者,你無需手動選擇自己。 - **儲存表單**時未變更負責人——即使表單會把該欄位一併送出。 - **自動化代你執行**——指派新潛在客戶的輪詢、夜間產生續約與跟進任務的批次作業。 +- **認領一張無主案件。** 把一張沒有任何人負責的案件轉入 *In Progress*、*Waiting on Customer* 或 *Waiting on Support*,你就成了它的負責人(見上文*一條為「被用掉」而設的授權*)。負責人確實變了——但這個動作沒有指定任何人、沒有把記錄從任何人手裡拿走,而且只在案件無主時才起作用,所以它不是一次轉移,也不需要轉移權限。 沒有該權限的使用者嘗試轉移時會收到明確的拒絕提示,而不是悄無聲息地失效。需要整體移交業務簿時,請聯絡管理員或你的銷售經理。 diff --git a/content/docs/service/cases.mdx b/content/docs/service/cases.mdx index a6dd6a99f..e4af28866 100644 --- a/content/docs/service/cases.mdx +++ b/content/docs/service/cases.mdx @@ -95,6 +95,7 @@ The two are not one screen wearing different chrome. **Case Type** is on the det ## What happens automatically +- **Owner, when a case is claimed** — a case with **no owner** gets one the moment somebody moves it to *In Progress*, *Waiting on Customer* or *Waiting on Support*: whoever makes that change is stamped as the case's Owner in the same save. A case that already has an owner is never touched, and an automated or seeded write never claims — those leave the case ownerless, for the **Unassigned — triage** tab to keep showing. See *Claiming a case out of triage* below. - **First response date** (`first_response_date`) — stamped the first time an interaction that **already took place** is recorded against the case. Its single writer is the `event_activity_bubble` hook (`src/objects/event.hook.ts`), which fires on any `crm_event` reaching **Held** status with the case as its related record — so **Log a Call** and **Log a Meeting** stamp it, and so does an interaction entered any other way, including straight onto the case's activity list. It reads the stored value back before writing, so a second interaction never overwrites the first. Two things are deliberately *not* a first response: a **status change** (an agent can move a case to *In Progress* and investigate for an hour while the customer hears nothing) and a meeting merely *scheduled*, which is `planned` rather than held. On a case worked entirely through comments the field stays empty. - **Closed flag** — set automatically when status changes to *Closed*. - **Closed date** — stamped to NOW when status changes to *Closed*. @@ -138,10 +139,27 @@ Two things this list deliberately does not claim, because the escalation does no See [SLA & Escalation](/docs/service/sla-and-escalation) for the full mechanics. +## Claiming a case out of triage + +Some cases arrive with **no owner at all** — a web-to-case submission that landed while nobody held the Service Agent position is the usual way. They wait in the **Unassigned — triage** tab, where every service agent can see and edit them until somebody picks one up. + +**Taking a case is a status move, not an owner edit.** Move an unowned case to **In Progress**, **Waiting on Customer** or **Waiting on Support** and it becomes yours: the app stamps you as its Owner in that same save. The case then leaves **Unassigned — triage** — that tab lists unowned cases only — and appears in **My Open Cases**. + +Nothing else claims a case, and each exclusion is deliberate: + +| Move an unowned case to | What happens to ownership | +| --- | --- | +| **New** | Nothing — it is the state a triage row is already in, so it is not a move at all | +| **Escalated** | Nothing for you: that transition belongs to the escalation hand-off, which sends the case to the least-loaded **Service Manager** (see *Case escalation* above) | +| **Resolved**, **Closed** | Nothing — finishing a case is not picking it up. You may resolve an unowned case straight out of triage; it stays ownerless, and the record shows you as the one who last updated it | + +> **You cannot claim a case by editing Owner, and you cannot claim one for anybody but yourself.** Owner is not a field an agent sets on a case — a save carrying it is refused whatever name it holds, your own included — so the status move is the claim's only spelling, and the only name it can write is yours. The gesture is equally inert on a case that already has an owner: move that case's status and the status is all that changes. A case that genuinely has to change hands needs an administrator or a service manager; see [Sharing & Security](/docs/administration/sharing-and-security). + ## Sharing — who can see which case - By default, cases are **private** — only the owner. Positions are flat and **nothing rolls up**, so no manager sees a case by sitting above its owner. - **Critical open cases** are auto-shared by two rules, one per rung: *Escalated Cases Sharing* grants read/edit to `service_manager`, and *Escalated Cases — Service Director* grants read to `service_director`. Both rungs are named explicitly because neither inherits from the other. +- **Unowned open cases** are shared with every `service_agent` by *Unassigned Cases — Triage*, read and edit — the grant behind the **Unassigned — triage** tab. It lasts exactly as long as the case has no owner and is neither *Resolved* nor *Closed*, and claiming the case is what ends it: from that point you hold the case the ordinary way, as its owner. ## Field-level security diff --git a/content/docs/service/cases.zh-Hans.mdx b/content/docs/service/cases.zh-Hans.mdx index 53a0c4fff..27e9b72a0 100644 --- a/content/docs/service/cases.zh-Hans.mdx +++ b/content/docs/service/cases.zh-Hans.mdx @@ -95,6 +95,7 @@ description: 客户支持工单——主题、优先级、状态、解决方案 ## 自动发生的事 +- **认领时写入的负责人**——一张**没有负责人**的工单,只要有人把它转到 *In Progress*、*Waiting on Customer* 或 *Waiting on Support*,就会在同一次保存里把做这个动作的人标记为它的负责人。已经有负责人的工单不受影响;自动化写入或种子写入也永远不构成认领——它们让工单保持无主,继续留在 **Unassigned — triage** 标签页里被看见。见下文*认领待分流的工单*。 - **首次响应日期**(`first_response_date`)——在工单上记录一次**已经发生过**的互动时才打戳,而且只打第一次。它唯一的写入方是 `event_activity_bubble` 钩子(`src/objects/event.hook.ts`):任何一条以该工单为关联记录、状态到达 **Held** 的 `crm_event` 都会触发它——所以 **Log a Call** 与 **Log a Meeting** 会打戳,用别的方式录入的互动(包括直接在工单的活动列表上录入)同样会。它写之前先把库里存着的值读回来,所以第二次互动不会覆盖第一次。有两件事被刻意排除在「首次响应」之外:**状态变更**(客服可以把工单转到 *In Progress* 然后自己查一小时,客户什么都没听到),以及仅仅**预约**了一场会议——那是 `planned` 而不是 held。所以一张全程靠评论处理的工单,这个字段始终是空的。 - **关闭标记**——状态变为 *Closed* 时自动设置。 - **关闭日期**——状态变为 *Closed* 时标记为 NOW。 @@ -138,10 +139,27 @@ description: 客户支持工单——主题、优先级、状态、解决方案 完整机制参见 [SLA 与升级](/zh-Hans/docs/service/sla-and-escalation)。 +## 认领待分流的工单 + +有些工单到达时**完全没有负责人**——最常见的一种:没有人担任服务坐席时,Web 提交的工单就这样落了下来。它们停在 **Unassigned — triage** 标签页里,在有人接手之前,每一位客服都能看到并编辑它们。 + +**接手一张工单靠的是改状态,不是改负责人。** 把一张无主工单转到 **In Progress**、**Waiting on Customer** 或 **Waiting on Support**,它就归你了:应用会在同一次保存里把你标记为它的负责人。随后这张工单离开 **Unassigned — triage**(该标签页只列无主工单),出现在 **My Open Cases** 里。 + +除此之外没有任何操作构成认领,每一项排除都是刻意的: + +| 把无主工单转到 | 归属会怎样 | +| --- | --- | +| **New** | 什么都不会发生——待分流的行本来就处在这个状态,这根本算不上一次转移 | +| **Escalated** | 与你无关:这个转换属于升级移交,工单会交给未结工单最少的那位**服务经理**(见上文*工单升级*) | +| **Resolved**、**Closed** | 什么都不会发生——把工单做完不等于把它接过来。你完全可以把一张无主工单直接从待分流状态解决掉;它仍然无主,记录上留下的只是你这位最后更新人 | + +> **你无法靠编辑负责人来认领工单,也无法替别人认领。** 负责人不是客服能在工单上设置的字段——带着这个字段的保存一律被拒绝,无论填的是谁,填你自己也一样——所以改状态是认领唯一的写法,而它能写入的名字只有你自己。对已经有负责人的工单,这个动作同样是空转:改它的状态,变的就只有状态。真正需要易主的工单要找管理员或服务经理,见[共享与安全](/docs/administration/sharing-and-security)。 + ## 共享——谁可以看到哪个工单 - 默认情况下,工单是**私有的**——只有所有者可见。岗位是扁平的,**什么都不会上卷**,没有哪位经理因为“在所有者之上”就能看到某个工单。 - **紧急未结工单**由两条规则自动共享,一个层级一条:*Escalated Cases Sharing* 把读/写授予 `service_manager`,*Escalated Cases — Service Director* 把读授予 `service_director`。两个层级都被显式点名,因为谁也不会从对方那里继承。 +- **无主的未结工单**由 *Unassigned Cases — Triage* 共享给每一位 `service_agent`,读 + 编辑——这就是 **Unassigned — triage** 标签页背后的那条授权。它的有效期恰好是「这张工单没有负责人,且既不是 *Resolved* 也不是 *Closed*」这段时间,而认领正是终结它的那个动作:从那一刻起,你以负责人的身份、用最普通的方式持有这张工单。 ## 字段级安全 diff --git a/content/docs/service/cases.zh-Hant.mdx b/content/docs/service/cases.zh-Hant.mdx index 7a3b86d8e..fe8a50b2a 100644 --- a/content/docs/service/cases.zh-Hant.mdx +++ b/content/docs/service/cases.zh-Hant.mdx @@ -95,6 +95,7 @@ description: 客戶支援工單——主題、優先順序、狀態、解決方 ## 自動發生的事 +- **認領時寫入的負責人**——一張**沒有負責人**的工單,只要有人把它轉到 *In Progress*、*Waiting on Customer* 或 *Waiting on Support*,就會在同一次儲存裡把做這個動作的人標記為它的負責人。已經有負責人的工單不受影響;自動化寫入或種子寫入也永遠不構成認領——它們讓工單保持無主,繼續留在 **Unassigned — triage** 標籤頁裡被看見。見下文*認領待分流的工單*。 - **首次回應日期**(`first_response_date`)——在工單上記錄一次**已經發生過**的互動時才打戳,而且只打第一次。它唯一的寫入方是 `event_activity_bubble` 鉤子(`src/objects/event.hook.ts`):任何一筆以該工單為關聯記錄、狀態到達 **Held** 的 `crm_event` 都會觸發它——所以 **Log a Call** 與 **Log a Meeting** 會打戳,用別的方式錄入的互動(包括直接在工單的活動列表上錄入)同樣會。它寫之前先把庫裡存著的值讀回來,所以第二次互動不會覆蓋第一次。有兩件事被刻意排除在「首次回應」之外:**狀態變更**(客服可以把工單轉到 *In Progress* 然後自己查一小時,客戶什麼都沒聽到),以及僅僅**預約**了一場會議——那是 `planned` 而不是 held。所以一張全程靠評論處理的工單,這個欄位始終是空的。 - **關閉標記**——狀態變為 *Closed* 時自動設定。 - **關閉日期**——狀態變為 *Closed* 時標記為 NOW。 @@ -138,10 +139,27 @@ description: 客戶支援工單——主題、優先順序、狀態、解決方 完整機制參見 [SLA 與升級](/zh-Hant/docs/service/sla-and-escalation)。 +## 認領待分流的工單 + +有些工單抵達時**完全沒有負責人**——最常見的一種:沒有人擔任服務座席時,Web 提交的工單就這樣落了下來。它們停在 **Unassigned — triage** 標籤頁裡,在有人接手之前,每一位客服都能看到並編輯它們。 + +**接手一張工單靠的是改狀態,不是改負責人。** 把一張無主工單轉到 **In Progress**、**Waiting on Customer** 或 **Waiting on Support**,它就歸你了:應用會在同一次儲存裡把你標記為它的負責人。隨後這張工單離開 **Unassigned — triage**(該標籤頁只列無主工單),出現在 **My Open Cases** 裡。 + +除此之外沒有任何操作構成認領,每一項排除都是刻意的: + +| 把無主工單轉到 | 歸屬會怎樣 | +| --- | --- | +| **New** | 什麼都不會發生——待分流的列本來就處在這個狀態,這根本算不上一次轉移 | +| **Escalated** | 與你無關:這個轉換屬於升級移交,工單會交給未結工單最少的那位**服務經理**(見上文*工單升級*) | +| **Resolved**、**Closed** | 什麼都不會發生——把工單做完不等於把它接過來。你完全可以把一張無主工單直接從待分流狀態解決掉;它仍然無主,記錄上留下的只是你這位最後更新人 | + +> **你無法靠編輯負責人來認領工單,也無法替別人認領。** 負責人不是客服能在工單上設定的欄位——帶著這個欄位的儲存一律被拒絕,無論填的是誰,填你自己也一樣——所以改狀態是認領唯一的寫法,而它能寫入的名字只有你自己。對已經有負責人的工單,這個動作同樣是空轉:改它的狀態,變的就只有狀態。真正需要易主的工單要找管理員或服務經理,見[共用與安全](/docs/administration/sharing-and-security)。 + ## 共享——誰可以看到哪個工單 - 預設情況下,工單是**私有的**——只有所有者可見。職位是扁平的,**什麼都不會上捲**,沒有哪位經理因為「在所有者之上」就能看到某個工單。 - **緊急未結工單**由兩條規則自動共享,一個層級一條:*Escalated Cases Sharing* 把讀/寫授予 `service_manager`,*Escalated Cases — Service Director* 把讀授予 `service_director`。兩個層級都被顯式點名,因為誰也不會從對方那裡繼承。 +- **無主的未結工單**由 *Unassigned Cases — Triage* 共享給每一位 `service_agent`,讀 + 編輯——這就是 **Unassigned — triage** 標籤頁背後的那條授權。它的有效期恰好是「這張工單沒有負責人,且既不是 *Resolved* 也不是 *Closed*」這段時間,而認領正是終結它的那個動作:從那一刻起,你以負責人的身分、用最普通的方式持有這張工單。 ## 欄位級安全 diff --git a/content/docs/service/index.mdx b/content/docs/service/index.mdx index 60d188fcf..3bbaaf2ed 100644 --- a/content/docs/service/index.mdx +++ b/content/docs/service/index.mdx @@ -36,6 +36,7 @@ New ──► In Progress ──► Waiting on Customer ──► Resolved ─ - **Auto-escalate** Critical cases — the flow flags them *Escalated* and alerts the agent who had them, and the case moves to the service manager with the fewest open cases (or stays put, if nobody holds that position). A High case is never escalated automatically, whatever the account is: raising one is the manual **Escalate Case** button. - **Notify on critical** — inbox message + email to the **case owner** whenever a case is set to Critical. That is the Case Escalation flow's notify node, whose recipient list is `{caseRecord.owner_id}` alone; there is no `support_manager@example.com` recipient anywhere in this app. - **Notify on escalation** — no email goes to an escalation team: `escalation_team@example.com` exists nowhere in this app. What the *Escalated* status fires is the `case_status_side_effects` hook, which opens an **Urgent follow-up task due tomorrow for the account owner**. +- **Hand an unowned case to whoever picks it up** — a case waiting in **Unassigned — triage** becomes yours when you move it to *In Progress*, *Waiting on Customer* or *Waiting on Support*, and it moves to **My Open Cases**. See [Claiming a case out of triage](/docs/service/cases). - **Stamp resolution time** automatically when a case is closed. - **Flag SLA breaches** once the SLA target passes — the case is marked **SLA Violated**, escalated, and its owner alerted by inbox + email. No red banner: this app has no banner mechanism. - **Block bad closes** — you can't mark a case Closed without a resolution written. diff --git a/content/docs/service/index.zh-Hans.mdx b/content/docs/service/index.zh-Hans.mdx index 50cffc1a5..da85498cb 100644 --- a/content/docs/service/index.zh-Hans.mdx +++ b/content/docs/service/index.zh-Hans.mdx @@ -36,6 +36,7 @@ New ──► In Progress ──► Waiting on Customer ──► Resolved ─ - **自动升级**——只针对 Critical 工单:流程把它们标记为 *Escalated*、提醒原来那位客服,并把工单交给未结工单最少的那位服务经理(若无人持有该岗位,则原地不动)。High 工单永远不会被自动升级,无论账户是什么:要升级它,靠的是手动的 **Escalate Case** 按钮。 - **紧急时通知**——每当工单被设为 Critical 时,站内消息 + 邮件只发给**工单负责人**。这就是工单升级流程的 notify 节点,其收件人列表只有 `{caseRecord.owner_id}` 一项;本应用中不存在 `support_manager@example.com` 这个收件人。 - **升级时通知**——不会给任何升级团队发邮件:`escalation_team@example.com` 在本应用中根本不存在。状态转为 *Escalated* 真正触发的,是 `case_status_side_effects` 钩子开出的那条**次日到期、优先级为紧急、归账户负责人的跟进任务**。 +- **谁接手就归谁**——停在 **Unassigned — triage** 里的工单,只要你把它转到 *In Progress*、*Waiting on Customer* 或 *Waiting on Support*,它就归你,并转入 **My Open Cases**。见[认领待分流的工单](/docs/service/cases)。 - **标记解决时间**——工单关闭时自动标记。 - **标记 SLA 违约**——一旦 SLA 目标时间过去,工单会被标记为 **SLA 已违约**并升级,其负责人收到站内消息 + 邮件提醒。没有红色横幅:本应用没有任何横幅机制。 - **阻止错误关闭**——未填写解决方案就不能将工单标记为已关闭。 diff --git a/content/docs/service/index.zh-Hant.mdx b/content/docs/service/index.zh-Hant.mdx index 1345a3db2..3f389fed2 100644 --- a/content/docs/service/index.zh-Hant.mdx +++ b/content/docs/service/index.zh-Hant.mdx @@ -36,6 +36,7 @@ New ──► In Progress ──► Waiting on Customer ──► Resolved ─ - **自動升級**——只針對 Critical 工單:流程把它們標記為 *Escalated*、提醒原來那位客服,並把工單交給未結工單最少的那位服務經理(若無人持有該職位,則原地不動)。High 工單永遠不會被自動升級,無論帳戶是什麼:要升級它,靠的是手動的 **Escalate Case** 按鈕。 - **緊急時通知**——每當工單被設為 Critical 時,站內訊息 + 郵件只發給**工單負責人**。這就是工單升級流程的 notify 節點,其收件人列表只有 `{caseRecord.owner_id}` 一項;本應用中不存在 `support_manager@example.com` 這個收件人。 - **升級時通知**——不會給任何升級團隊發郵件:`escalation_team@example.com` 在本應用中根本不存在。狀態轉為 *Escalated* 真正觸發的,是 `case_status_side_effects` 鉤子開出的那條**次日到期、優先順序為緊急、歸帳戶負責人的跟進任務**。 +- **誰接手就歸誰**——停在 **Unassigned — triage** 裡的工單,只要你把它轉到 *In Progress*、*Waiting on Customer* 或 *Waiting on Support*,它就歸你,並轉入 **My Open Cases**。見[認領待分流的工單](/docs/service/cases)。 - **標記解決時間**——工單關閉時自動標記。 - **標記 SLA 違約**——一旦 SLA 目標時間過去,工單會被標記為 **SLA 已違約**並升級,其負責人收到站內訊息 + 郵件提醒。沒有紅色橫幅:本應用沒有任何橫幅機制。 - **阻止錯誤關閉**——未填寫解決方案就不能將工單標記為已關閉。