Ginkgo CRM

一款为财富管理销售团队设计的语音优先移动 CRM。通过实时语音采集、自动转录与 AI 结构化总结,取代会后手动整理文档的工作流,并将记录结果直接接入客户关系管理流水线。
Core Flow
System Design
Reliability
Impact
让记录成为销售工作的副产品
高接触行业的销售每天有 30–40% 的时间消耗在会后文档整理上。信息依赖口头交接,客户上下文在 Sales 到 RM 的转移中持续衰减。
核心设计原则是语音优先、渐进披露与绝不丢失数据:用户只需在对话发生时按下录音,系统负责完成转录、总结和结构化。

语音采集 → AI 总结 → CRM 流水线
核心价值闭环从录音开始:本地持久化、后台上传、自动转录、AI 总结,最终写入客户时间线。Sales 与 RM 共享完整对话历史,不再依赖口头简报。

会议文档覆盖率由约 40% 提升至 90%+。
170+ 字段与单一事实来源
将原本混在 Lark 多维表格中的 170 多个字段按基础信息、Sales 流程、RM 流程与公式字段重新分类,建立三表数据模型及字段映射注册表。
数据库成为唯一事实来源,Lark 只做写出终点,从架构层消除双向同步冲突。

移动端录音、离线恢复与部署防线
录音在任何网络请求前先持久化至 IndexedDB;上传失败自动恢复。Flutter 原生壳支持后台录音,并通过超时、重试和错误上报保护 WebView 桥接。
Staging 与 Production 部署增加环境锚点、显式参数和生产二次确认,避免配置串线。

以工程可靠性服务同一个 UX 目标
离线优先、乐观更新与 SSOT 并不是单纯的技术选择,它们共同保证用户无需判断系统是否正常工作。

每位销售代表每天预计节省 25–30 分钟,实时漏斗视图取代每周状态会议。
完整项目记录
以下内容保留自原始 Notion 项目文档,包括研究、决策、验证、反思、指标与技术细节。
01 — 项目概述
产品: Ginkgo CRM(随手记)
角色: UX/产品设计师 & 开发者
时间线: 2025 Q4 - 2026 Q1(持续迭代中)
平台: 移动优先 Web 应用 + 原生 iOS/Android 壳(Flutter)
领域: 财富管理 / 金融服务 CRM
Ginkgo CRM 是一款为财富管理销售团队设计的语音优先移动 CRM。它用实时语音采集、自动转录和 AI 结构化总结,取代了传统的“会后手动打字记笔记”工作流——并将这一切深度集成到客户关系管理流水线中。
核心洞察:高接触行业的销售专业人员,每天有 30-40% 的时间消耗在会后文档整理上。通过在对话发生时即时采集、让 AI 提炼结构,我们将这段时间归还给关系建设本身。


02 — 问题定义
业务背景
金融服务公司的销售和客户关系管理(RM)团队,正在用一套碎片化的工具组合来管理客户关系:
飞书多维表格:用于客户数据跟踪
手动记笔记:在客户会议之后(常常遗忘或内容不完整)
微信消息:用于 Sales 和 RM 团队之间的内部交接
脑内模型:凭记忆追踪每个客户在销售流水线中的位置
这产生了三个层层递进的问题:
问题一:信息衰减
销售代表与客户进行了一场丰富的 30 分钟对话,然后试图在几小时后重构关键细节。到那时,客户的风险偏好细微差异、时间压力和决策因素早已模糊。笔记大约只能捕捉到 20% 的有效信号。
问题二:交接摩擦
当客户从 Sales 移交到 RM 时,交接本质上就是一次口头简报加上飞书表格里的一行数据。RM 无法访问对话历史、客户情绪,也看不到销售阶段做出建议背后的推理逻辑。
问题三:流水线盲区
管理层无法实时了解流水线健康状况。“客户 X 现在到了哪个阶段?”需要直接问负责的销售代表。业绩预测完全靠猜。
03 — 用户与调研
主要用户画像:Sales 客户经理
背景:金融服务领域的高净值客户开发
日常:每天 3-5 场客户会议(面对面、电话、视频)
痛点:会后文档整理像杂务,经常拖延或跳过
需求:在不打断对话节奏的前提下捕捉会议要点
设备:iPhone(主力),偶尔用桌面端回顾
次要用户画像:关系管理经理(RM)
背景:客户获取后的持续服务
日常:组合回顾、KYC 合规、资产配置讨论
痛点:接手客户时缺乏上下文;对客户需求几乎从零开始了解
需求:丰富的客户历史记录和结构化的 Sales 交接
第三用户画像:团队负责人 / Admin
背景:管理 5-15 人的 Sales/RM 团队
痛点:缺乏团队活动和流水线速度的量化视图
需求:展示活动指标、流水线进展和团队产出的仪表盘
关键调研发现
通过利益相关者访谈和工作流观察,一个发现脱颖而出:
“最好的销售不在会议中记笔记——他们全身心投入与客户的交流。但这意味着最差的文档来自表现最好的人。”
这个悖论成为设计北极星:文档质量不应与会议质量成反比。
04 — 设计原则
基于调研,四条设计原则指导了每一个决策:
零摩擦采集 — 一次点击即可开始录音。无需设置、无需配置、无需在开始前选择“这是哪个客户”。
AI 是编辑,不是作者 — AI 总结应当提炼和结构化实际对话内容,而非生成新内容。用户必须信任输出。
渐进式披露 — 在每个时刻只呈现所需的最少信息。会前快速查看客户姓名的销售代表,与季度回顾中的 RM,需要不同的信息深度。
单一事实来源 — 一个系统拥有数据。同步是单向的(写出到飞书供展示),绝不是双向的(双向会导致竞态条件和数据丢失)。
05 — 信息架构
客户记录模型
客户
身份信息(姓名、公司、行业、评级)
联系方式(电话、微信、邮箱)
业务信息(资产规模、持仓、是否上市)
Sales 流程(7 步流水线,每步有特定字段)
RM 流程(5 步流水线,含 KYC 要求)
随手记时间线(按时间倒序)
单条笔记
文字内容(Markdown)
录音记录(含转录文字)
AI 总结(结构化输出)
归属关系(Sales 跟进人、RM 跟进人、IC 跟进人)
导航结构
首页(随手记列表)
笔记编辑器(语音 + 文字)
Sources Tab(录音 + 转录)
Summary Tab(AI 生成)
客户详情
基本信息(3 层渐进式披露)
流程进度(Sales + RM 流水线)
关联随手记
客户信息表(电子表格视图)
看板 / Dashboard
流水线漏斗
随手记动态
管理后台
用户管理
活跃度分析
审计日志
06 — 核心用户流程
流程一:语音采集 → AI 总结(核心价值闭环)
这是产品的核心——从“我刚开完会”到“我有了结构化笔记”的 60 秒路径。
- 01
点击麦克风
- 02
录制对话
- 03
点击停止
- 04
自动上传至云端
- 05
自动转录(QwenASR)
- 06
点击AI 总结
- 07
选择模式(面客总结 / 内部会议纪要)
- 08
生成结构化输出
- 09
复制 / 保存
此流程中的关键 UX 决策:
一键录音:麦克风按钮始终可从首页访问。无需先创建笔记、选择客户或做任何配置。关联客户可以之后再做。
后台录音支持:用户可以锁屏或切换 App,录音持续进行。一条醒目的黄色横幅提醒:“熄屏/切到后台可继续录音,请勿杀死 App”。
退出安全保护:如果用户在录音时不小心点了“返回”,会弹出原生确认对话框。确认后自动停止录音、自动上传,然后退出——不会丢失数据。
上传韧性:录音会立即持久化到 IndexedDB。如果 App 在上传过程中进入后台(WebView 挂起会中断 XHR),上传队列会在用户返回时通过 visibilitychange 事件自动恢复。
流程二:Sales 流水线推进
- 01
打开客户详情
- 02
查看当前步骤:需求确认
- 03
填写当前步骤的必填字段
- 04
点击下一阶段
- 05
校验通过
- 06
成功
- 07
流程推进至方案评估
- 08
进度条实时更新
- 09
自动同步至飞书
设计决策:
7 步漏斗可视化:每个步骤作为水平进度指示器可见,为客户在旅程中的位置提供空间上下文。
按步骤的字段要求:不是一次展示全部 31 个字段,而是只显示当前步骤相关的必填字段。将认知负荷从“填完这张巨大的表单”降低为“回答这 3 个问题”。
非破坏性回溯编辑:用户可以回到之前的步骤进行编辑,而无需重新验证后续所有步骤。现实中的销售流程并非完全线性。
终态清晰性:第 7 步(关单并移交 RM)显示绿色完成横幅,没有“下一步”按钮——一个有意为之的终点,传达完结感。
流程三:客户交接(Sales → RM)
- 01
Sales 完成第 7 步
- 02
客户出现在 RM 流水线第 1 步
- 03
RM 打开客户详情
- 04
看到:完整的随手记时间线、所有录音对话、AI 总结
- 05
带着完整上下文开始内部 KYC 流程
这个流程不需要专门的 UI——交接通过共享的数据可见性自然发生。RM 继承的是完整的对话历史,而不是一份摘要的摘要。
07 — 关键设计挑战与解决方案
挑战一:移动端录音可靠性
问题:移动端 Web 应用运行在 WebView 容器中,而 WebView 会积极挂起后台进程。用户在录音时锁屏 2 分钟,JavaScript 运行时可能被冻结。返回后,上传卡住、状态过时,录音看似丢失。
解决方案——多层韧性架构:
| 层级 | 机制 | 用途 |
|---|---|---|
| 1 | IndexedDB 持久化 | 录音在页面刷新和 App 重启后依然存活 |
| 2 | 上传队列管理器 | 串行上传 + 重试逻辑,防止并发冲突 |
| 3 | 可见性变化检测 | App 回到前台时:重置处理标志、恢复队列、重新入队卡住的项目 |
| 4 | 原生桥接超时 | Flutter↔WebView 桥接调用 8-10 秒超时,防止无限挂起 |
| 5 | 桥接退避重试 | Flutter 侧回调投递 3 次重试 + 指数退避(200/400/800ms) |
| 6 | 进度反馈 | 多阶段展示:“准备中…“ → ”上传中 45%“ → ”保存到云端中…” → ✓ 完成 |
成效:实施完整韧性栈后,录音上传成功率从约 85% 提升至约 99%+。

挑战二:AI 总结的信任问题
问题:用户对 AI 生成的总结持怀疑态度。“我怎么知道它没有编造内容?”
解决方案——通过可追溯性建立透明度:
Sources Tab 始终在总结旁边展示原始转录文字
总结输出被结构化为明确类别(关键要点、客户需求、客户痛点、下一步行动),便于用户快速与记忆进行交叉验证
两种模式选项(面客总结用于对外润色,会议纪要用于内部记录)表明 AI 会适应不同语境,而不仅仅是改写
模型选择对用户可见(Qwen、GPT、Gemini、Claude)——让高级用户掌控总结的“语调”
挑战三:数据架构——SSOT vs. 同步
问题:团队历史上使用飞书多维表格作为事实来源。迁移到数据库后端系统时,产生了构建双向同步的诱惑——而这不可避免地会导致数据冲突、竞态条件和静默覆写。
解决方案——从设计层面强制单向:
这个架构决策被硬编码到代码库本身:
DB → 飞书同步在每次保存时自动发生(异步、非阻塞)
飞书 → DB 同步默认禁用,受环境变量(ALLOW_LARK_SYNC)门控保护,且每次调用都有审计日志
API 端点在门控未打开时直接返回 403
这不仅是一条策略——它在代码中强制执行、在项目宪法中记录、在每次代码评审中被关注
对 UX 的意义:用户永远不会看到冲突数据。App 中的客户记录始终是权威的。飞书成为一面只读镜像,供偏好电子表格视图的利益相关者使用。

挑战四:170+字段Lark数据同步到数据库(AI-First Problem Solving)
接手项目时,所有客户数据都存在一张 Lark 多维表格里——170 多个字段,Sales流程、RM 流程、KYC清单、基础信息全部混在一起,没有分组,没有文档,字段命名风格也不统一。要把这些数据迁移到自己的数据库,第一步不是写代码,而是搞清楚每个字段是什么。我先让 AI 调用 Lark Bitable API 拉取全量字段元数据,拿到每个字段的名称、类型(文本、单选、多选、日期、人员、公式等)和选项值,输出成一份完整的字段清单。然后在本地写了一个测试前端页面,把这 170个字段按原始顺序渲染出来,逐个对照 Lark 表格确认每个字段的实际用途和归属。
确认完之后开始分组。我按业务逻辑把字段分成五类:
基础信息(姓名、电话、公司等约 35 个)
Sales 流程字段(约 40 个)
RM 流程字段(约 80 个,光 KYC清单就占了一大半)
随手记相关(排除)
公式字段(只读)
分类逻辑写成了classifyField函数,根据字段名前缀和流程步骤定义自动判断归属,不需要手动维护一张 170行的映射表。数据库设计上采用了三表模型:app_customers 存基础信息(19个高频字段提升为直接列,其余存 JSON),customer_sales_flow 和customer_rm_flow 分别存两条业务流程的状态和字段快照。同时建了lark_field_mappings 注册表,记录每个 Lark 字段对应到哪张表、哪个列、什么类型、是否可编辑——后续前端渲染表单时直接读这张表,不需要硬编码字段列表。
整个过程走了 30 多个数据库迁移文件,从最初的全量 JSON导入,到拆表、加列、定义流程步骤、配置必填规则,逐步收敛。最终确立了一条铁律:数据库是唯一事实来源,Lark 只做写出终点,彻底断掉了 Lark→DB的反向同步,避免双向写入导致的数据冲突。

挑战五:多环境部署
Staging 和 Production 两套环境,配置不同的数据库、API Key、Lark应用——但代码是同一份。
最初的做法是 SSH 到服务器手动改 .env,每次新增变量要登录两台机器分别改,极
易遗漏。有一次加了推送配置变量,部署后线上毫无反应——排查半天发现docker-compose.yml 用的是显式环境变量列表,新变量没加进去,容器根本读不到。
但真正让我出冷汗的是另一次:我在 prod 服务器上执行了 ./deploy.sh --envstaging。切错了终端窗口,staging 的数据库配置直接覆盖到了生产环境,用户打开App 看到的是测试数据,操作也写进了 staging 库。回滚和数据清洗花了一整晚。
这次事故后,我在部署脚本里加了三层防护:一是强制显式声明环境,不传 --env直接报错;二是服务器身份锚点,每台机器放一个 /etc/ginkgo-deploy-env文件声明自己是 staging 还是 prod,参数不匹配直接拒绝执行;三是 prod部署二次确认,打印数据库地址,要求手动输入 prod 才能继续。

08 — 设计系统:视觉语言
视觉语言在专业克制与温暖亲和之间取得平衡——适合金融服务工具的日常使用场景。
色彩体系
| 令牌 | 色值 | 用途 |
|---|---|---|
| 主色 | #2e64a3 | 品牌强调色、交互元素 |
| 高亮 | #ffc612 | 活跃 Tab 指示器、强调 |
| 主文字 | #0b1f3a | 标题、正文 |
| 次文字 | #5d6776 | 标签、元数据 |
| 弱文字 | #95a0b1 | 占位符、禁用状态 |
| 边框 | #d3d9e4 | 分割线、卡片边缘 |
| 背景 | #f8f9fb | 页面背景 |
字体排版
字体栈:‘Barlow’, ‘Segoe UI’, sans-serif
正文:15px / 400 字重 / 1.6 行高
按钮:12px 大写、600 字重、0.08em 字间距
标题:从 18px(h3)到 24px(h1)递进
间距与圆角
间距体系:8 · 12 · 16 · 20 · 24 · 32px
圆角:10px(小/按钮)· 14px(卡片)· 18px(弹窗)
阴影:分层高度系统——静止时微妙,悬停/激活时明显
交互模式
卡片:悬停时显现微妙的高度变化(0 18px 36px rgba(18,31,52,0.16))
按钮:大写微标签 + 充裕的内边距——感觉精心设计,而非局促
弹窗:居中 + 背景模糊,统一 18px 圆角
Tab:静止时低调(#999 文字),激活状态使用金色下划线 + 深色文字
09 — 权限与角色设计
| 能力 | 所有用户 | BA(中台/商分) | Admin |
|---|---|---|---|
| 查看客户列表 | ✓ | ✓ | ✓ |
| 编辑客户字段 | ✓ | ✓ | ✓ |
| 编辑流程进度 | ✓ | ✓ | ✓ |
| 创建随手记 + 录音 | ✓ | ✓ | ✓ |
| 查看看板 | — | ✓ | ✓ |
| 删除客户 | — | — | ✓ |
| 用户管理 | — | — | ✓ |
| 活跃度分析 | — | — | ✓ |
设计理由:权限模型有意保持扁平。在一个 5-15 人的小型销售团队中,对字段编辑设门槛只会增加摩擦,却不会带来有意义的风险降低。唯一受保护的操作是不可逆的操作(删除)和系统配置(用户角色)。
10 — 技术层面的 UX 决策
离线优先架构
每一段录音在发起任何网络请求之前就被持久化到 IndexedDB。这意味着:
网络故障永远不会导致数据丢失
用户在电梯信号盲区或地下室会议室可以自由录音
上传在网络恢复时自动进行
乐观 UI 更新
当用户保存字段编辑时:
UI 立即更新(乐观更新)
DB 写入同步完成
飞书同步异步进行(非阻塞)
用户永远不需要等待飞书。如果飞书同步失败,系统会静默重试——而由于 DB 是 SSOT,不会有数据丢失。
原生 App 壳(Flutter)
App 通过 App Store 和 Google Play 分发,是 React Web 应用外套一层原生 Flutter 壳。这带来了:
后台录音(iOS UIBackgroundModes:audio,Android 前台服务 + WakeLock)
原生文件系统访问,用于录音存储
App Store 上架,便于企业分发
推送通知(规划中)
代价是桥接复杂度——每一次原生↔Web 交互都跨越一个可能静默失败的消息传递边界。前述的超时 + 重试 + 错误上报系统就是应对方案。
11 — 指标与成效
活动指标(在 Admin 仪表盘中跟踪)
录音频次:每用户每日/每周录音数
随手记创建率:有/无录音的随手记创建数
AI 总结采纳率:生成总结的随手记占比
流水线推进速度:每个流水线步骤的平均停留天数
上传成功率:无需手动重试即完成上传的录音占比
业务影响
文档覆盖率:从约 40% 的会议被记录提升至 90%+(语音采集消除了摩擦壁垒)
交接质量:RM 收到的是完整对话历史,而非口头简报
流水线可见性:实时漏斗视图取代了每周状态会议
时间节省:估计每位销售代表每天在文档上节省 25-30 分钟
12 — 迭代历程(节选)
| 日期 | 变更 | 触发原因 |
|---|---|---|
| 3月10日 | 录音退出安全保护——返回键自动停止录音并上传 | 用户因误触导航离开而丢失录音 |
| 3月10日 | iOS 桥接超时保护(10秒)+ 重试(3次指数退避) | iOS 用户在停止录音时遭遇白屏冻结 |
| 3月11日 | App 回到前台后上传队列恢复 | 录音卡在“准备中…”,因 App 进入过后台 |
| 3月11日 | CSS sticky Tab 替代 JS 滚动检测 | Tab 栏与头部之间在移动端出现视觉缝隙 |
| 3月11日 | 退出笔记时停止音频播放 | 离开笔记后音频继续播放 |
| 3月11日 | 飞书机器人推送通知 + 多收件人选择 | 团队负责人希望自动生成活动报告 |
| 3月12日 | 删除操作同步至飞书 | 已删除的笔记在飞书表中残留为幽灵条目 |
每次迭代都遵循紧凑的闭环:用户反馈摩擦 → 调查根因 → 最小范围修复 → 当天上线。
13 — 反思与收获
有效的做法
语音优先的框架改变了行为:将产品定位为“录制你的会议”而非“写 CRM 笔记”,从根本上改变了采纳率。抗拒记笔记的用户接受了录音,因为录音不与会议中的注意力竞争。
SSOT 纪律避免了数据混乱:严格的单向同步策略(仅 DB → 飞书)消除了一整类 bug。在类似产品中常见的“同步冲突”问题在这里根本不存在。
渐进式披露优雅地扩展:从 6 个可见字段开始,按需扩展到 170+,意味着同一个界面同时服务了“会前快速查看”和“深度审计”两种用例,无需切换模式。
Vibe Coding Basics
任务拆解与 Prompt 策略:从“模糊需求“到”精准执行”
极致的任务拆解是提效的关键:将大需求拆解为微小的、可验证的步骤,确保每一步修改正确后再进行下一步。这种方法比直接抛出复杂需求能带来 1000% 的效率提升,并显著降低 AI 出错的概率。
利用 AI 的“行业常识“进行决策引导:在不确定具体实现路径时,询问 AI ”业内普遍解决方案是什么“ 是一个极佳的切入点。有时直接让 AI ”根据行业内 UX 规范生成界面”,效果往往比直接指定像素位置更好。
明确意图边界,防止代码污染:在要求 AI 修改样式时,必须清晰声明“这只是一个只移动位置的修改”,以防止 AI 在调整 UI 的同时错误地重构或破坏背后的功能逻辑。
调试与破局:解开“AI 死循环”的工程手段
诊断脚本是解开死循环的钥匙:当 AI 进入 debug 死循环(反复改不对同一个 feature)时,不要盲目重复描述。有效的对策是让 AI 写一个诊断报告脚本,在控制台打印详细的错误内容,再将真实报错反馈给 AI。
建立多维度的报错机制:在开发初期就让 AI 增加详细的报错提示功能(如 Lark OAuth 报错原因弹窗),这能帮助你在环境配置出错时(如 Client ID 未设置)迅速定位问题,而不是在逻辑代码中盲目排查。
警惕 AI 的环境配置盲区:AI 常会在环境配置上犯低级错误,例如将环境变量硬编码为 localhost,导致移动端或线上环境无法访问。这要求开发者必须对网络请求路径和环境变量有清晰的审核意识。
工程防线:在 AI 时代保护数据与代码安全
Git 是唯一的安全网,严禁依赖 AI 回退:AI 自带的“Rewind”功能并不可靠,存在无法完全恢复到保存点的风险。Git Commit 版本控制是修复顽固 Bug、确保代码安全的唯一物理屏障。
严格管控数据库高危操作:坚持“操作数据表不让代码自动执行”的原则。数据库的初始化和表结构变更应由人工手动操作,防止 AI 在重构过程中导致数据意外丢失。
清晰的数据流向管理:开发者必须清楚地告知并确认 AI 对动态资源(如用户上传的音频、图片存入 S3)与静态资源(如 Logo 存入 Git 仓库)的存储逻辑,防止存储混乱。
架构认知:从设计文档到技术落地的闭环
提供规范文件以维持一致性:在开发前为 AI 提供清晰的设计规范(.md 文件),是保障 AI 生成代码具备设计一致性的重要前提。
技术选型的务实判断:通过实践发现,在垂直功能领域(如语音转文字 STT),SDK 的稳定性与成功率往往优于 API。
解决“离线可靠性“的防御性设计:针对移动端易断网、进程易挂起的特性,建立”本地存储暂存 + 自动补传”的机制比单纯依赖前端缓存更科学。
如果重来我会做得不同的
从总结开始,而非录音:当前流程是 录音 → 转录 → 总结。回头看,总结应该是一等公民,录音和转录作为其下方的支撑证据。用户的心智模型应该是“AI 写了我的会议笔记”,而非“我有一段录音可以处理”。
显式设计交接时刻:Sales → RM 的转交目前通过共享数据可见性隐式发生。一个专门的“交接”页面配合结构化简报格式,能让这个时刻感觉是经过深思熟虑的,而非隐含的。
更早投入空状态设计:首次使用的用户看到的是空列表和空白仪表盘。通过示例数据或引导式首次录音流程来减少价值实现时间。
14 — 工具与方法
| 类别 | 工具 |
|---|---|
| 设计 | 组件驱动开发、移动优先响应式设计 |
| 前端 | React 18、Vite、Lucide React、CSS-in-JS(内联样式) |
| 后端 | Node.js、Express、MySQL、AWS S3 |
| AI/ML | QwenASR(转录)、Qwen3-Max(总结)、OpenRouter(多模型) |
| 集成 | Lark Open API(字段同步、机器人消息) |
| 移动端 | Flutter(iOS/Android 原生壳 + WebView 桥接) |
| 部署 | Docker、docker-compose、VPS 托管 |
15 — 总结
Ginkgo CRM 证明了:最高杠杆的 UX 干预,往往不是视觉重设计——而是消除阻止有价值行为发生的摩擦。
通过让会议文档记录变得像按下一个按钮一样简单,让 AI 处理结构化,产品将文档整理从一件与销售业绩竞争的苦差事,变成了销售业绩的副产品。
技术挑战(WebView 桥接可靠性、离线持久化、上传韧性、SSOT 数据架构)是实质性的,但它们全都服务于一个 UX 目标:用户永远不应丢失数据,也永远不应需要思考系统是否在正常工作。
