Dashboard 重新设计 — 时间与内容矩阵视图

Path: apps/web/src/pages/dashboard-v3/ · Created: 2026-05-24

这份文档是什么

这份文档是 Dashboard 单店深挖页 reshape 的 source of truth, 取代现有 mvp-v3 mockup (docs.retaintive.ai/ui-design/ui-prototype/mvp-v3) 里 Dashboard section 的 4 time tab 设计。

实施时按这份文档走, mvp-v3 HTML 不需要改 — 它是过渡 mockup, 这份文档是 final spec。生产实现位于 dashboard-v3/ (新版终态), dashboard/ 是 legacy, v3 完成后被替代。

vs mvp-v3 的变化:

维度mvp-v3 (旧)本文档 (新)
时间选择4 个 time tab (Yesterday / Last Week / This Month / Last Month)统一 time range picker (跟 My Stores 同款, 5 预设 + Custom max 93 天)
Layout 一致性每个 time tab 不同 layout (Yesterday 3 块 / Weekly+ 6 块)同一套 7 块 layout 跨所有 time range, 切 time 只重算数字
Yesterday 缺块没 Staff / Cancel Reasons / Complaint / Impacted Rev7 块全部展示 (数据小就小, "—" 表示无对比)
Weekly+ 缺块没 Task 三联表7 块全部展示

Product Positioning

Dashboard 是 single-store deep dive 页, 是 My Stores fleet view 点店后的下一层。Manager-primary (每天工作面板), Owner 通过 Email Digest cliffhanger 偶尔点入复用同一页 — 没有单独的 Owner Dashboard。

不重发明信息, 不删 mvp-v3 已 design 好的块, 只 unify time × content 让用户切 time range 时认知不断裂。


Page Shell

页面 7 层结构 (从上到下):

  1. Deep-link banner(可选) — 仅当从 My Stores cell click 跳来时显示;详见末尾 "Deep-link from My Stores" 章节
  2. Header — "Dashboard" 标题 + Store switcher dropdown + Snapshot / Export 按钮
  3. Filter row — Time range picker + Voicemail toggle 同行
    • Time range picker:复用 My Stores 同款 component。5 个预设 (Yesterday / Last Week / This Month / Last Month / Custom max 93 天)
    • Voicemail toggle:[✓] Include voicemail 默认 ON,跟 My Stores 同款。Owner 可手动切换 / Deep-link 设置自动 apply
  4. AI Quick Scan — 顶部 1 段 ≤ 80 字 AI summary (按 time scale 重写)
  5. KPI 卡条(② block) — 9 个 KPI 卡跨 time / tab 一致
  6. Tab 切换 — 3 个 tab:
    • Call deep-dive(④ Cancellation Reasons + ⑤ Complaint Reasons)
    • Task deep-dive(⑥ Impacted Revenue + ⑦ Task by Reason — Yesterday only)
    • Staff Performance(③ Staff 一行表 — 独立 tab,加 task 列以反映 staff 跨 call/task 双维度工作)
  7. 当前 tab 的内容(主体)

切 time range 不重置 store / sort / VM toggle / tab。默认时间 = Yesterday (Manager 早 huddle 心智)。Time picker + VM toggle 跨 3 tab 共享。

为什么 Staff 独立 tab(不在 Call deep-dive 下)? Staff 是"人维度"切片,跟 Cancellation Reasons / Complaint Reasons("原因维度"切片)是不同的 lens。Staff 同时做 call + task,放 Call tab 下语义错配。独立 tab 后可加 task 相关列(每个 staff close 了多少 task、close rate、task productivity),反映 staff 真实工作量。


① AI Quick Scan

1 段 ≤ 80 字 plain-text summary, 按当前 time range 重写。Owner 30 秒读完 + Manager 决定要不要深挖。

Sample (illustrative):

Time range示例 narrative
Yesterday"Low call volume (7 vs daily avg 18) — 2 staff out sick. 3 tasks overdue, Lead Outreach + Payment Recovery 优先处理."
Last Week"本周 cancel ↑40% (Schedule conflict 主因, save rate 20%). Billing 投诉 ↑20%. Impacted Revenue $3,362 ↑11%."
This Month"MTD intro booking ↑8%, membership sold flat. Staff Holly 持续领跑, Nadia coaching flags ↑."
Last Month"上月 churn rate 4.2%, save rate 36% — 跟前月持平. Top reason still 'schedule conflict', 建议 script update."

视觉: 顶部 1 段 plain text, 无 emoji 无 sentiment 标签, 文字本身已传达情绪 (urgent / stable / strong)。

Calculation (① AI Quick Scan)

非 SQL 算的。callytics-infrastructure cross-call AI Lambda 每天凌晨扫这家店当前 time range 内所有 call analysis, 综合写一句 ≤ 80 字 plain-text summary 存到 store-level summary table。Dashboard 直接读 string 字段 dashboardSummary[period], inline 显示。

V1 不带视觉状态标签。V2 视产品需要再加 sentiment classification。准确性问题 → issue 报到 callytics-infrastructure cross-call AI pipeline。


② KPI 卡条 (8 卡)

8 个数字卡 + trend % vs 上期。所有 time range 都展示同 8 卡 (单日 Impacted Revenue 数字小也显示, 数据真相)。

Cancel Save + Complaint Resolve 两类对称 KPI 卡 — 既然下方 ④/⑤ 有 Cancel Reasons + Complaint Reasons 两 detail block,顶部 KPI 也对应展示两组 close/total 数字,visual + 语义上下对称。Cancel Save % 严格只算 cancellation_risk 类 call(主动 cancel);Complaint Resolve % 算 retention 类 call(投诉/billing/服务争议)— 两类 schema 上 type_category 不同,KPI 上各自独立分母。

Sample (Last Week, illustrative):

CardValueTrend
Total Calls218 (130 in · 88 out)↑12%
Intro Booking Calls9↓25%
Memberships Sold Calls2↓33%
Cancellation Calls14↑40%
Cancel Save %5 / 14 (36%)↓17%
Complaint Calls6↑20%
Complaint Resolve %4 / 6 (67%)↑14%
Impacted Revenue$3,362↑11%

视觉: trend ↑N% 绿色 (#16A34A) = 对店有利方向, ↓N% 红色 (#dc2626) = 不利方向, 灰色 (#CBCED4) = 无对比数据。Membership Cancellation Calls 列 是好事 (cancel 减少) → 绿色, 颜色按"对店家有利"判定方向而非数字大小。沿用 mvp-v3 + My Stores 同款 component。

Calculation Recipes (② KPI 卡条)

源表 calls + tasks (Neon) · Schema @retaintive/common/db/schema/{calls,tasks}.ts · Enum 常量 apps/api/src/constants/call-analysis.ts

所有公式默认前缀 WHERE store_id = ? AND start_time IN period, 下表只列额外条件。Trend % = (current - previous) / previous × 100, previous 自动按 time range 算同长度上期。

公式 (在 base WHERE 上追加)含义 / 备注
Total CallsCOUNT(*) from calls所有 call_state 都算, 含 voicemail / no_answer
· Inbound subtextAND direction = 'Inbound'RingCentral enum 首字母大写
· Outbound subtextAND direction = 'Outbound'Inbound + Outbound = Total
Intro Booking CallsAND primary_subcategory = 'intro_booking'新客 first-time, free / $12 区间
Memberships Sold CallsAND primary_subcategory IN ('membership_purchase_related', 'reactivation_purchase') AND primary_outcome_result = 'success'2 值口径同 My Stores Tab 1 (Pending Discussion Decision 1 待决)
Membership Cancellation CallsAND primary_subcategory = 'membership_cancel'完全终止, membership_freeze 不算。↓ 为好事 (绿色)
Cancel Save %saved / Cancellation Calls;saved = AND primary_subcategory = 'membership_cancel' AND primary_outcome_result = 'retained'retained 是 cancel 专用 outcome。显示 s / t (%) 格式
Complaint CallsAND primary_subcategory IN ('member_support', 'billing_issue', 'cancellation_fee_dispute', 'complaint_feedback')投诉(精确 subcategory list 待 Decision 2 — 见 my-stores spec Pending Discussion)
Complaint Resolve %resolved / Complaint Calls;resolved = Complaint Calls + AND primary_outcome_result = 'resolved'投诉处理成功保留客户。显示 r / t (%) 格式
Impacted RevenueSUM(coefficient(close_result)) from tasks WHERE status='closed' AND closed_at IN period系数表 SoT 同 My Stores Tab 2 · Impacted Revenue V1 系数表

Sanity checks:

  • Inbound + Outbound = Total Calls
  • Cancel Save saved ≤ Cancellation Calls(saved 数 ≤ total)
  • Complaint Resolve resolved ≤ Complaint Calls
  • Cancellation Calls 与 Complaint Calls 来自不同 subcategory(membership_cancel vs member_support/billing_issue/etc.),互不重叠
  • 单日 Impacted Revenue 可能 = $0, 不是 bug

Backend 改动 — voicemail toggle 替代 filter 删除 (与 My Stores spec 一致): apps/api/src/routes/v3/dashboard-multi-store.ts line 181 + 206 现有 call_state IS DISTINCT FROM 'voicemail' filter 不删,改成参数化:

  • API 接 ?includeVoicemail=true|false (默认 true)
  • true → 移除 filter (含 VM)
  • false → 保留 filter (排除 VM)

Dashboard UI 顶部 voicemail toggle 跟 My Stores 同款,默认 ON。Owner 切换时重查。Deep-link 从 My Stores 跳来时,VM 设置经 query param 带过来(详见末尾 "Deep-link from My Stores")。


③ Staff Performance 表 (独立 tab)

按 SA 一行表格,反映 staff 跨 call + task 双维度工作。独立 tab(不在 Call deep-dive 下) — staff 是"人维度"切片,跟 Cancellation/Complaint Reasons("原因维度"切片)分开。

Sample (Last Week, illustrative):

StaffCallsIn / OutIntro BookingSoldCancel SaveComplaint ResolveTasks ClosedTask ProductivityCoaching FlagsCall Productivity %
Nadia K. (Front Desk)5821 / 371463 / 52 / 33180%18%40% (vs avg +3)
Ryan W. (Front Desk)4218 / 24941 / 21 / 21965%28%33% (vs avg −4)
Kyle L. (Front Desk)196 / 13421 / 11 / 11070%8%37% (vs avg ±0)
Team Avg 37%

视觉: Productivity vs avg +N 绿色, −N 红色, ±0 灰色。Coaching Flags % > 25% 黄色背景警示 (阈值由 product confirm)。

Calculation Recipes (③ Staff Performance)

源表 calls (聚合 by staff_name) + tasks (assigned_to field) · 跟 ② 同 base WHERE 加 AND staff_name = ?

公式含义
StaffDISTINCT staff_name + role从 calls 表 staff_name 字段去重
CallsCOUNT(*) FROM calls WHERE staff_name = ?该 SA 接的所有 call
In / Outsplit by direction该 SA 接听 / 主动外呼
Intro Booking CallsAND primary_subcategory = 'intro_booking'该 SA 接的 intro call
Memberships Sold CallsAND primary_subcategory IN ('membership_purchase_related', 'reactivation_purchase') AND primary_outcome_result = 'success'该 SA 推成的
Cancel Save(saved/total) from primary_subcategory = 'membership_cancel'该 SA cancel 救回 / 接到的 cancel total。严格不混 complaint
Complaint Resolve(resolved/total) from primary_subcategory IN ('member_support', 'billing_issue', 'cancellation_fee_dispute', 'complaint_feedback')该 SA 处理投诉 (Decision 2 待定 subcategory 范围)
Tasks ClosedCOUNT(*) FROM tasks WHERE closed_by_staff_name = ? AND status = 'closed' AND closed_at IN period该 SA 本期关闭的 task 数
Task Productivity(positive close_results) / (tasks_closed) per staffpositive = converted / booked / cancel_saved / win_back / renewed / upgraded / issue_resolved / referral_obtained。同 my-stores Tab 2 productivity 公式
Coaching Flagsflagged_calls / total_calls × 100flagged = AI 标记 coaching-worthy (script: skip voicemail / <60s / wrong number)
Call Productivity %(Intro Booking Calls + Memberships Sold Calls + Cancel Save saved + Complaint Resolve resolved) / Total Calls × 100Owner 唯一会盯的 staff call 指标(同 my-stores Tab 1 Team Productivity 公式)

Team Avg Productivity = SUM(numerator) / SUM(Total Calls) × 100 (不是 staff 平均的平均)

Sanity checks:

  • In + Out = Calls (per staff)
  • Productivity % ≤ 100%
  • vs avg 偏差 = staff_productivity - team_avg

④ Cancellation Call Reasons

Cancel call 按 reason 拆分 + 各 reason 的 Save Rate。顶部 1 行 AI summary 指明 "哪个 reason 在 bleeding"。

Sample (Last Week, illustrative):

顶部 banner: "Where we're bleeding: Schedule conflict is the #1 cancel reason (5 calls) and we save only 20% — fix the scheduling-objection script."

Cancellation ReasonCancel CallsSavedSave Rate
● Schedule conflict5120%
● Price3267%
● Moved away20— uncontrollable
● Unhappy with staff / service2150%
● Injury / health11100%
● Unclear / multi-reason10
Total14536%

视觉: Save Rate < 30% 红色 (#DC2626), 30-60% 黄色 (#CA8A04), > 60% 绿色 (#16A34A)。"Moved away" 标 — uncontrollable 灰色 (不计入 save rate 评估)。

Calculation Recipes (④ Cancellation Call Reasons)

源表 calls WHERE primary_subcategory = 'membership_cancel' · Reason 来自 AI prompt 的 cancellation_reason 字段 (callytics-infrastructure standard-v1.0.0.txt)

公式含义
Cancellation ReasonDISTINCT cancellation_reasonAI 分类 6 reason (Schedule conflict / Price / Moved away / Unhappy / Injury / Unclear)
Cancel CallsCOUNT(*) WHERE cancellation_reason = ?该 reason 的 cancel call 数
SavedCOUNT(*) WHERE cancellation_reason = ? AND primary_outcome_result = 'retained'救回的
Save RateSaved / Cancel Calls × 100"Moved away" Save Rate 显示 因 uncontrollable
AI bannerLLM 生成 1 句指出 #1 reason + save rate, 给 actionable advice

Sanity check: 各 reason Cancel Calls SUM = ② KPI 卡 Membership Cancellation Calls


⑤ Complaint Call Reasons

跟 ④ 同结构, complaint 按 reason 拆 + Resolve Rate。

Sample (Last Week, illustrative):

顶部 banner: "Where trust is slipping: Billing disputes are the #1 complaint (2 calls) and we resolve only 50% — tighten the billing-explanation script."

Complaint ReasonComplaint CallsResolvedResolve Rate
● Billing / overcharge dispute2150%
● Equipment broken / unavailable11100%
● Staff behavior / rudeness11100%
● Class / booking availability11100%
● Unclear / multi-reason100%
Total6467%

视觉: 同 ④ 颜色规则 (Resolve Rate < 50% 红, 50-80% 黄, > 80% 绿)。

Calculation Recipes (⑤ Complaint Call Reasons)

源表 calls WHERE primary_subcategory IN ('service_complaint', 'billing_complaint') · complaint_reason 字段同 AI prompt 分类。

公式结构同 ④, 替换:

  • cancellation_reasoncomplaint_reason
  • primary_outcome_result = 'retained'primary_outcome_result = 'resolved'
  • SavedResolved
  • Save RateResolve Rate

Sanity check: 各 reason Complaint Calls SUM = ② KPI 卡 Complaint Calls


⑥ Impacted Revenue Breakdown

9 类 MRR + 1 类 One-time, 每类 revenue + task count + trend %。Owner 验证 Retaintive ROI 核心视图。

Sample (Last Week, illustrative):

Recurring Revenue (MRR)

CategoryRevenueTasksDescription
● Conversion MRR$1,268 ↑14%11Revenue from new member conversions
● Upgrade MRR$400 ↓6%4Revenue from membership upgrades
● Complaint Retention MRR$379 ↑9%5Protected revenue (complaints resolved, 90d retained × 0.60)
● Payment Recovery MRR$318 ↑22%3Recovered failed payments (× 0.75)
● Cancel Save MRR$423 ↑5%7Revenue saved from prevented churn
● Freeze Recovery MRR$207 ↓12%2Revenue from reactivated frozen members (× 0.70)
● Win-back MRR$67 ↑3%2Revenue from re-enrolled former members
● Promotion MRR$120 ↑18%1Revenue from promotion memberships

One-Time Revenue

CategoryRevenueTasksDescription
● Event Revenue$180 ↑7%6Challenge & event registration fees

| Total | $3,362 ↑11% | 41 | — |

Calculation Recipes (⑥ Impacted Revenue Breakdown)

源表 tasks WHERE status = 'closed' AND closed_at IN period · 按 close_result 分类 + 应用 V1 系数表

Category来源 close_result系数公式含义
Conversion MRRconvertedcount × $450新签 paying member
Upgrade MRRupgradedcount × $200升级 tier
Complaint Retention MRRissue_resolved (V2 算系数)count × $X (V1 = $0)V1 暂不入账, V2 重评
Payment Recovery MRR(待 schema 补 close_result)count × $? × 0.75失败付款回收
Cancel Save MRRcancel_savedcount × $450Cancel 救回
Freeze Recovery MRR(待 schema 补 close_result)count × $? × 0.70冻结复活
Win-back MRRwin_backcount × $300Former member 回归
Promotion MRR(V2)Promotion membership 系数待定
Event Revenue(V2)Challenge/event 报名费, 非 task 来源, V2 接入

V1 现实: 只有 Conversion / Upgrade / Cancel Save / Win-back 有现成 close_result enum 算得出。Complaint Retention / Payment Recovery / Freeze Recovery / Promotion / Event 是 mvp-v3 mockup 已 design 但 schema 未支持的, 见 Pending Team Discussion · Decision 2。

Sanity check: SUM(all categories) = Total = ② KPI 卡 Impacted Revenue


⑦ Task by Reason — Created / Closed / Overdue

3 列并排表格, 每列按 11 reason 拆 task 数。Manager huddle 看"今天打谁电话"+ Owner 看"团队 follow-through 怎样"。所有 time range 都展示。

Sample (Yesterday, illustrative):

ReasonTasks Created (6)Tasks Closed (4)Tasks Overdue (3)
Lead Outreach211
Lead Follow-up111
Booked Not Converted110
Upgrade000
Complaint Retention100
Payment Recovery001
Cancellation Risk110
Freeze Recovery000
Win-back000
Event Promotion000
Special Promotion000

视觉: 数字 = 0 的 reason 标灰色 (#9CA3AF)。bar 长度按各列 max 缩放。Created 蓝 / Closed 绿 / Overdue 红 — 颜色 = 状态情绪。

Calculation Recipes (⑦ Task by Reason)

源表 tasks · 按 type_category 分组 (11 reason mapping 见下)

公式 (base WHERE store_id = ?)含义
Tasks Createdcreated_at IN period GROUP BY type_category本期新建 task
Tasks Closedstatus = 'closed' AND closed_at IN period GROUP BY type_category本期关闭
Tasks Overduestatus = 'pending' AND due_at < NOW() GROUP BY type_category (不限 period, 看当前积压)当前逾期 (snapshot, 非 period 内)

Reason mapping (mvp-v3 mockup 11 reason vs @retaintive/common schema 9 enum):

Mockup labelSchema type_category状态
Lead Outreachlead_outreach✅ 对应
Lead Follow-uplead_follow_up✅ 对应
Booked Not Convertedbooked_not_converted✅ 对应
Upgradeupgrade✅ 对应
Cancellation Riskcancellation_risk✅ 对应
Win-backwin_back✅ 对应
Complaint Retentionretention✅ 对应 (改 label)
Payment Recovery❌ schema 缺, 见 Decision 2
Freeze Recovery❌ schema 缺
Event Promotion❌ schema 缺
Special Promotion❌ schema 缺

Sanity checks:

  • Tasks Created SUM = 顶部 Created total (例 = 6)
  • Tasks Closed SUM = 顶部 Closed total (例 = 4)
  • Overdue 是 snapshot, 不受 period 影响

Interaction Rules

行为跳转 / 结果
切 time range当前 tab 重算, layout 不变, 不重置 store / sort / VM / tab
切 store (顶部 switcher)全 tab 重算, time / VM / tab 保留
切 VM toggle当前 tab 重算 (Call Volume 受影响最直接)
切 tab (Call / Task / Staff)tab 内容重渲染, time / VM 保留
点 staff name (③)/staff-timeline/:staffName?period=...
点 cancel/complaint reason 行 (④⑤)/calls?subcategory=...&reason=...&period=...&voicemail=...
点 revenue category 行 (⑥)/task?type_category=...&status=closed
点 task reason 行 (⑦)/task?type_category=...&status=created/closed/overdue
Hover ⓘ显示 formula tooltip
AI Quick Scan (①)inline 显示, 不 expand
Grab Snap截图当前 tab (跟 mvp-v3 现有按钮一致)

Dashboard reshape 作为 My Stores cell click 的跳转目标,需要接受 my-stores 传过来的 4 个 query param。

支持的 query param:

ParamValues含义
storestore name 或 store_id自动 set 顶部 store switcher
metriccalls | intro | membership | cancel | complaint | productivity | tasks | revenueOwner 在 my-stores 点的具体 cell
periodtoday | 7d | 14d | 28d | this-week | last-week | this-month | last-month | ISO date range与 my-stores time picker 一致
voicemailinclude (default) | exclude与 my-stores VM toggle 一致

Frontend 行为:

  1. 接到 deep-link 时,4 个 param 自动 apply 到对应 UI 控件
  2. metric 决定 default tab + 是否高亮:
    • metric=calls / intro / membership / productivity → default Call tab,顶部 KPI 卡条对应那张高亮(紫色边框 + ⤴ pill)
    • metric=cancel → default Call tab,scroll to ④ Cancellation Reasons block + KPI Cancel Save % 卡高亮
    • metric=complaint → default Call tab,scroll to ⑤ Complaint Reasons block + KPI Complaint Resolve % 卡高亮
    • metric=tasks / revenue → default Task tab,对应 block + KPI 卡高亮
  3. 顶部紫色 banner 显示 "⤴ From › My Stores › <Store><Metric>" + 一键 ‹ Back to My Stores 按钮
  4. ✕ Clear focus 按钮 — 清掉 banner + 高亮,但保留 time / VM / tab 选择

V1 visual scope:V1 只对 3 个 metric 高亮 detail block(cancel → ④;complaint → ⑤;revenue → ⑥)。其他 5 个 metric 跳进来只显示顶部 banner + 对应 KPI 卡高亮,不 scroll(因为 dashboard reshape V1 没有对应的 detail block)。V2 补全 detail block 后再扩展。

Backend 行为:Dashboard 已经支持 store + period + voicemail param,无需新加 backend 字段。metric 是纯 frontend 路由信号,不影响 SQL。


Backend Implications

复用 apps/api/src/routes/v3/dashboard-multi-store.ts 改 single-store route (或新建 dashboard-single-store.ts), 扩展:

  • Period enumyesterday / last-week / this-month / last-month + startDate / endDate ISO query params (custom 日历)
  • Response shape:
    • aiSummary: string (① 来自 cross-call AI Lambda)
    • kpis: { totalCalls, inbound, outbound, introBooking, membershipsSold, cancellation, cancelSaved, complaintCalls, complaintRetention, impactedRevenue, ...trends } (②)
    • staffPerformance: Array<{ staffName, calls, in, out, introBooking, sold, cancelSaved, tasks, coachingFlags, productivity, vsAvg }> (③) + teamAvgProductivity
    • cancellationReasons: Array<{ reason, count, saved, saveRate }> (④)
    • complaintReasons: Array<{ reason, count, resolved, resolveRate }> (⑤)
    • impactedRevenueBreakdown: { recurring: [...], oneTime: [...], total } (⑥)
    • taskByReason: Array<{ reason, created, closed, overdue }> (⑦)
  • 删 voicemail filter (见 ② Backend 改动)
  • Previous-period 同长度自动算 (用于 trend %)

Store 列表沿用现有 useStores composable + getAuthorizedStore 权限检查。多租户隔离: store_id


Files to Change

文件改动
apps/web/src/pages/dashboard-v3/index.vue7 块 layout + 统一 time picker
apps/web/src/pages/dashboard-v3/components/7 个新 component (AIQuickScan / KPICardRow / StaffPerformanceTable / CancellationReasons / ComplaintReasons / ImpactedRevenueBreakdown / TaskByReason)
apps/web/src/composables/queries/useDashboardSingleStore.ts新建 — TanStack Query hook 调单店 dashboard route
apps/web/src/components/date-range/DateRangeDropdown.vue复用 (跟 My Stores 同款)
apps/api/src/routes/v3/dashboard-single-store.ts新建或扩展现有 multi-store route — 7 块数据聚合 + period enum + voicemail filter 删
apps/api/docs/api-technical-reference.md + apps/api/docs/frontend-api-guide.md文档同步 (pre-commit hook 强制)
CHANGELOG.md (root + apps/web + apps/api)各加 entry

Pending Team Discussion

V1 按下面"当前选择"实施, 不 block 开发。Team review 后如改方向, 同步更新对应 section。

Decision 1 — KPI 卡 ② 用哪 8 个

选项8 卡组合Lens利弊
mvp-v3 Weekly+ (当前选择)Total / Intro / Sold / Cancel / Cancel Saved / Complaint / Complaint Retention / Impacted Revenue"完整 funnel 看完"mvp-v3 已 design, manager 心智已建立
Owner Will 5 问Intro / Sold / Cancel / Cancel Saved / Outbound Call / Impacted Revenue / Total + ?Will 锁定 "Owner 每天 5 问" (role-deep-dive §1)Owner-first, 但 Manager 复用时缺 Complaint 维度
Manager + Owner 并集mvp-v3 8 卡 + Outbound Calls (从 subtext 提到卡级) = 9 卡"Owner 看 Outbound 主动出击, Manager 看 Complaint"9 卡视觉拥挤, 1 行排不下

背景 — mvp-v3 mockup 选 8 卡, role-deep-dive Owner 5 问偏向不同集合, Manager M1 还要 Complaint Retention。这是产品 lens 决策, 不是技术决策。

决策人: (待填) · 决议日期: (待填)

Decision 2 — Impacted Revenue ⑥ 9 类系数缺 5 个

mvp-v3 mockup 展示 9 类 MRR (Conversion / Upgrade / Complaint Retention / Payment Recovery / Cancel Save / Freeze Recovery / Win-back / Promotion / Event), @retaintive/common v0.54 close_result 18 值只能算出 4 类 (Conversion / Upgrade / Cancel Save / Win-back)。

选项做法利弊
A. V1 只展示 4 类 (当前选择)缺的 5 类不渲染, 占位 "—"数据真实, mvp-v3 mockup 跟生产差距明示
B. mockup 全展示, 缺的标 $09 类全显, V1 系数表 5 类 = $0视觉跟 mockup 一致, 但 owner 误以为系统在算
C. 扩 schema 加缺的 close_resultv1.x 加 payment_recovered / freeze_recovered / promotion_signed / event_registered长期对, 但 block dashboard 上线

决策人: (待填) · 决议日期: (待填)

Decision 3 — Task by Reason ⑦ 11 vs 9 schema mismatch

mvp-v3 mockup 11 reason (含 Payment Recovery / Freeze Recovery / Event Promotion / Special Promotion), schema 只 9 enum。

选项做法利弊
A. V1 只展示 schema 9 个 (当前选择)mockup 多的 4 个不渲染跟 ⑥ Decision 2A 一致, 数据真实
B. mockup 11 个全显, 缺的标 0UI 跟 mockup pixel-perfect误导 owner "系统在追踪"

决策人: (待填) · 决议日期: (待填)


Schema Source-of-Truth Chain

位置
L1 Drizzle schema@retaintive/common/src/db/schema/{calls,tasks}.ts (web ^0.54.0, API ^1.0.0 — 2026-05-24 bump)
L2 Enum constants见下方 sub-list
L3 Design SoTdocs/product-design/future-plans/role-deep-dive-v2.html (Manager M1-M7 已锁定 dashboard 设计)
L4 AI prompt SoTcallytics-infrastructure/lambda/ai-analysis-processor/prompts/standard-v1.0.0.txt (cancellation/complaint reason 分类)
L5 Neon test live datarestless-boat-70724564 (org org-long-math-59935021), npx neonctl connection-string 拿 conn
L6 Existing routeapps/api/src/routes/v3/dashboard-multi-store.ts (Tab 1 SQL 已写, line 165-208)

L2 详情:

  • apps/api/src/constants/call-analysis.ts — call enums (CallCategory / CallSubcategory / OutcomeResult / CallState / CallDirection)
  • @retaintive/common/db/schema/tasks.tsTASK_TYPE_CATEGORY (9 值) + TASK_CLOSE_RESULT (18 值, v0.54 起加 'booked' + 'cancelled')
  • @retaintive/common/db/schema/task-ui.tsCLOSE_RESULT_OPTIONS (Impacted Revenue 系数表 SoT)