Skip to content

docs(sales): 按 fieldGroups 与 contact_welcome 流程重写线索/联系人的字段区块表与欢迎提醒 (#792, #796) - #804

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-792-field-block-tables
Aug 5, 2026
Merged

yinlianghui merged 1 commit into
mainfrom
claude/issue-792-field-block-tables

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #792
Fixes #796

两单同在 contacts / leads 页面族,合成一个 PR。基线是 #794 合并后的 origin/main = 131daf9,两单条目已逐条重核(结论见文末「前提复核」)。纯文档改动,未动 src/**、语言包与 content/docs/releases/。

#792 半:区块表按 fieldGroups 重写

leads(三语)

  • tags 是幽灵字段:全对象 grep,tags 只存在于 crm_knowledge_article,crm_lead 上没有。删。
  • Company Information 行原先写着年营收、员工人数、网站:前两个声明在 additional,website 声明在 contact_info(lead.object.ts:262/268/175),三个都归位。
  • 对象声明的是 10 个 fieldGroup(lead.object.ts:17-28),页面写 9,并且整个 duplicates 组在表里没有行——而同页下方就有一整节在教怎么用这些字段。补为独立一行,并指向下文的「重复线索」小节。
  • company_normalized 是 hidden: true 的派生字段,不在界面上,因此不作为普通成员并列,而是写成公司信息行末尾的一句说明(它正是转化与重复检测的匹配键)。

contacts(三语)

  • is_primary 声明在 preferences(contact.object.ts:165-170),不是 account_info;reports_to 声明在 account_info(:110),不是 additional。两行互换回来。
  • 表里从来没有出现过 owner_id(:28)、avatar(:72)、last_contacted_date(:195),补齐到各自的区块。
  • 邮寄地址行原来只写「完整的结构化地址」,实际是五个独立文本字段,按字段列出。

zh 页的叫法:每个被重写的单元格都按该对象自己的 zh-CN 包写。⚠️ 两个对象的同名字段中文标签本就不同——crm_lead.email_opt_out 是「拒收邮件」(zh-CN.ts:373),crm_contact.email_opt_out 是「拒绝邮件」(:178)——各页各按自己的包,没有统一。leads zh 页的「沟通偏好」行(原「邮件退订、请勿致电」)即 #793 追评划归本单的那半边。

#796 半:欢迎提醒按 flow 实测改

contact-welcome.flow.ts 三处与原文不符,全部改写(三语):

  1. 收件人是负责人不是联系人本人:recipients: ['{record.owner_id}']、channels: ['inbox','email'],正文 "Reach out to welcome them."(:70-79)。
  2. contact_welcome 是 flow 的 name 与 notify 的 topic(:23、:75),不是邮件模板;全仓没有任何邮件模板资源,也没有发给客户的欢迎信。
  3. start 条件是 has(record.owner_id) && record.owner_id != null && (!has(record.email_opt_out) || record.email_opt_out != true)(:66-67)——无负责人(种子/集成/系统写入,Ownership model mismatch: app-authored owner lookups vs the platform's owner_id — reassigning Owner in the UI does not move record access #548)整条链路不触发。

顺带修正同页管理员提示:「欢迎邮件模板可以在你的邮件模板设置中自定义」重复了同一个不存在的模板,只改「内置规则」而留着它,等于两屏之后再说一遍原来的错话,因此按 #794 对 presented 的先例一并对齐,改为指向 src/flows/contact-welcome.flow.ts。#794 已改对的「沟通偏好」小节未回改。

⚠️ 一处前提修正:leads 的「详情界面有 N 个可折叠区块」这句话本身不成立

#792 建议把「9 个区块」改成实际数量。改成 10 会把一个错数字换成另一个错说法——crm_lead 是这批文档对象里唯一自带记录页的:

  • src/pages/lead_detail.page.ts:147-178(type: 'record', object: 'crm_lead')的 Details 标签页自己声明了 5 个 record:details 分区:Lead Information / Contact / Lead Detail / Address / Description;
  • src/views/lead.view.ts:197 起的 form 又自己声明了 6 个 collapsible: true 分区:Contact Information / Lead Classification / Company Information / Address / Additional Information / Privacy;
  • 对象的 fieldGroups 是 10 个,跟上面两个都不是一回事。

所以「详情界面有 N 个可折叠区块」在任何 N 下都不成立。本 PR 保留 fieldGroups 作为事实来源(PM 裁定),但把这句话改成它实际描述的东西——记录声明的字段区块全集,并说明详情页只挑了其中一部分。contacts 没有自带记录页,那句「详情界面有 6 个可折叠区块」成立,未改。残余问题(没有任何页面描述线索详情页实际展示什么)已另立 issue。

验证

pnpm hygiene / pnpm typecheck / pnpm validate / pnpm test 全绿(63 test files, 1534 passed, 1 skipped);validate 只剩 main 上原有的 5 条 warning。控制字符自扫零命中。changeset 已加,站内路径用反引号内联代码而非链接语法(#797 的教训)。

不为散文加钉子测试(#792 明确要求)。已有的 test/docs-contact-email-uniqueness.test.ts 仍绿——它锁的是同一小节的第一条 email 唯一性要点,本 PR 改的是第二条。


Generated by Claude Code

…s, and the welcome prompt against the flow (#792, #796)

The "what a record stores" table at the top of the Leads and Contacts pages
(and their zh-Hans / zh-Hant siblings) described a field layout the objects
never declared, so a reader looked for a field in the wrong section — or for a
field that does not exist at all.

Leads. `crm_lead` has no `tags` field (grep over the object finds the key only
on `crm_knowledge_article`), so the Additional Info row is rewritten from the
real `additional` group: annual_revenue, number_of_employees, description,
notes. Those first two were listed under Company Information, and `website`
too, though it is declared in `contact_info` — all three rows move. The object
declares TEN fieldGroups (lead.object.ts:17-28); the page counted nine and had
no row for `duplicates` at all, even though the same page teaches you how to
work duplicates further down. That group is now a row of its own, and
`company_normalized` is named as the hidden match key it is rather than
silently dropped.

The lead intro no longer attributes those groups to the detail SCREEN.
`crm_lead` is the one documented object with an authored record page, and
`lead_detail.page.ts:147-178` curates five `record:details` sections of its own
(Lead Information / Contact / Lead Detail / Address / Description) — while
`lead.view.ts:197` authors six collapsible FORM sections. Neither is the
object's ten groups, so "the detail screen has N collapsible sections" is not a
sentence the metadata supports at any N. The table is now stated for what it
is: the record's declared field groups.

Contacts. `is_primary` is declared in `preferences`, not `account_info`
(contact.object.ts:165-170), and `reports_to` in `account_info`, not
`additional` (:110) — the two rows that named them are swapped back. The table
never mentioned `owner_id` (:28), `avatar` (:72) or `last_contacted_date`
(:195), which are real members of Account & Role, Identity and Additional Info;
they are listed now, and the Mailing Address row names the five fields it
holds instead of "full structured address".

Built-in rules. `contact_welcome` is not an email template: it is the name of
a record-change flow and of its notify topic (contact-welcome.flow.ts:23, :75).
The notification goes to the contact's OWNER on the inbox and by email —
"Reach out to welcome them" (:71-79) — and the start condition requires
`has(record.owner_id)` (:66-67), so a contact written without an owner (seed
data, an integration, any `runAs: 'system'` write — #548) produces no
notification at all. The page promised the new contact a welcome email; nothing
reaches them, and no outbound welcome mail ships. The admin tip pointing at
"email-template settings" for the same non-existent template is corrected with
it, since leaving it would restate the claim two screens down.

Chinese pages follow the shipped zh-CN pack for every cell they rewrite. The
two objects deliberately differ there: `crm_lead.email_opt_out` is 拒收邮件
(zh-CN.ts:373) while `crm_contact.email_opt_out` is 拒绝邮件 (:178), so each
page follows its own object rather than being unified.

Documentation only — no metadata, behaviour or field changes.

Fixes #792
Fixes #796

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHrPAGEgFDoHjphqYG4BMa
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hotcrm Ignored Ignored Aug 5, 2026 8:52pm

Request Review

@yinlianghui
yinlianghui marked this pull request as ready for review August 5, 2026 20:56
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit f68fa3a Aug 5, 2026
9 checks passed
yinlianghui added a commit to yinlianghui/hotcrm that referenced this pull request Aug 10, 2026
…d field-group headings with the locale pack (objectstack-ai#801) (objectstack-ai#825)

The Chinese sales pages are supposed to spell every label the way
`src/translations/zh-CN.ts` ships it — that pack is what the reader sees on
screen. Four pages had drifted:

- `crm_lead.status` ships 已确认 / 未通过 / 已转化; the leads pages said
  已审核 / 不合格 / 已转换, in the status table and in every sentence
  downstream of it. The convert verb face follows `convert_lead` (转化线索)
  and `is_converted` (已转化), so 转换 becomes 转化.
- `expiration_date` is 到期日期; quotes.zh-Hans called it 过期日期 in four
  places while already using 到期日期 in three others.
- The `expired` status is 已过期; sales/index.zh-Hant said 已到期 — the same
  word corrected on the quotes page in objectstack-ai#803, on a page that fix did not reach.
- `reports_to` is 直属上级; the contacts prose still said 汇报对象 after objectstack-ai#804
  corrected the table cell.
- Field-group headings on the leads / contacts block tables now use each
  object's `_sections` labels instead of independently translated ones.

Verb and mechanism usages are preserved (报价到期, 每日过期扫描, 即过期的报价,
通过资格审核), and terms belonging to another object keep that object's
wording. Docs follow the pack, so nothing under `src/` changed.

Fixes objectstack-ai#801


Claude-Session: https://claude.ai/code/session_01VHrPAGEgFDoHjphqYG4BMa

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment