v0.4 封板(tag
v0.4~v0.4.23)后:报表大整顿 + 摸清第 5 问(跑赢通胀/市场)+ 调优决策 + 配置沉淀管理页 + 股票 cron 估值修复 全部上线。 v0.5 把 v0.4 草草开了个头的「第 5 问」做到严格、做到深:v0.4 的 CPI 对照线是硬编码 2% 的占位实现;v0.5 换成真实拉取、严格推导的 CPI + M2 双基准「财富水位」。本版本主题:
- 📈 财富水位(主线) — 家庭净资产 vs 两条国家级货币基准线:CPI 保命线(还买得起同样的生活吗)+ M2 地位线(社会财富排位是升还是降)· 严格自算自推、不展示拍脑袋数字
- 💵 股票账户现金联动(副线) — 录股票时可选「从账户现金划转买入」· 买入扣现金 / 卖出加回 · 全对称 · 现金可负
- 🎯 FIRE 目标支出自适应(副线) — 财务自由目标的月支出口径可选「自动适配月结支出」· 不再只能填死值 · 周期关闭按近 N 月真实支出滚动重算
配套文档:
- 技术设计:
tech-design/v0.5.md(架构选型 + 决策追溯 · PRD 评审通过后写)- UED 预览:
preview/v0.5/index.html(财富水位页 + 推导面板 + 股票录入改版 · PRD 评审通过后做)- QA 用例:
docs/qa-cases.mdv05-* 段状态(2026-05-29):📝 规划中 · PRD 评审 gate · 未写 tech-design / 未写代码
v0.4 第 5 问(跑赢通胀和市场了吗?)只做了半个:净资产趋势上画了一条硬编码 2% 的 CPI 对照线。问题:
- 2% 是拍的,不是真实 CPI(中国近年 CPI 其实 ~0.2-2%,且年际波动巨大)
- 只有 CPI 一条线 —— 只回答了「能否保命」,没回答「社会排位是否下滑」
- 没有任何推导透明度 —— 用户看不到这个数怎么来的
v0.5 把它做成两条严格推导的水位线:
| 基准线 | 衡量本质 | 回答用户的问题 | 中国当前量级 |
|---|---|---|---|
| CPI 保命线 | 购买力 | 我的钱还买得起同样的生活吗? | 近年 ~2% |
| M2 地位线 | 相对社会财富份额 | 我在社会财富里的排位是升还是降? | 近年 ~8-9% |
核心洞察:两条线差距巨大(近 10 年 M2≈9% / CPI≈2%,每年 7pp 鸿沟)。一个家庭可以「轻松跑赢 CPI(生活质量保住)」却「大幅跑输 M2(社会排位持续下滑)」——只看 CPI 永远发现不了。双线并列才是这一版的灵魂。
用户明确要求:这两个值不能是简单数字,要严格自算自推。落实为:
- 真实拉取,不写死常量(吸取 v0.4 CPI 硬编码 2% 的教训)
- 几何平均而非算术平均(通胀复利,几何才是等效年率)
- 三法并算 + 全部展示:全历史几何均值 / 剔除极端值几何均值(默认对比线) / 近 10 年几何均值
- 推导透明面板:把每个数怎么算的摊给用户看,不藏
- 工程算、LLM 不算(承 [[feedback_llm_no_math]]):所有数字工程算好,AI 只做文字解读
主线 A · 财富水位(FR-70 ~ FR-77)
├─ FR-70 宏观基准数据底座(CPI/M2 表 + 1990-2025 历史 seed + 年度拉取)
├─ FR-71 基准推导引擎(几何 / 剔极端 / 近10年 三法并算 · 纯函数)
├─ FR-72 财富水位三线图(实际净资产 / CPI 保命线 / M2 地位线)
├─ FR-73 真实收益 & 相对社会收益 KPI + 人赚/钱赚分解诊断
├─ FR-74 推导透明面板(把 CPI/M2 怎么算的摊开)
├─ FR-75 /dashboard CPI 线升级(真实 CPI + 加 M2 线)
├─ FR-76 /admin/integrations 加「宏观基准」段(数据源 + 手刷 + 历史表 + 方法选择)
├─ FR-77 /checkup 收益维度喂入双基准 + AI 解读
└─ FR-85 储蓄能力收支趋势图(人赚引擎可视化 · 收入线/支出线/储蓄填充 · 依赖 FR-84)
主线 B · 股票账户现金联动(FR-78 ~ FR-80)
├─ FR-78 买入扣现金(录 AUTO 持仓可选「从账户现金划转」· 强制成本 · FX · 可负)
├─ FR-79 卖出/减仓/归档加回现金(全对称 · 按市价 · FX)
└─ FR-80 账户内买卖在 ledger 显示为「再分配」(净值中性 · 不计入收支)
主线 C · FIRE 目标支出自适应(FR-81 ~ FR-83)
├─ FR-81 FIRE 支出口径开关(固定值 / 自动适配月结支出)+ 窗口 + 平滑方式
├─ FR-82 月结支出自动派生 + 周期关闭触发重算 + 回写存储 + 不足/空期回退
└─ FR-83 下游透明使用 + 移动靶沟通 + AI 偏离预警适配
缺陷修复(FR-84)
└─ FR-84 净流入(人赚的)双源 bug · PMC 优先统一口径 · FR-73 前置依赖| # | 决策点 | 选定 |
|---|---|---|
| D1 | CPI 口径 | 整体 CPI(headline · 含食品) —— 真实反映"吃穿"日常成本 + 有 ~40 年历史(核心 CPI 剔食品 + 仅 2013 起,不适用) |
| D2 | 净资产比较基准 | 总净资产(含工资储蓄)+ 人赚/钱赚分解诊断 |
| D3 | 历史均值默认高亮线 | 剔除极端值的几何均值(三个值都展示,这条做默认对比) |
| D4 | 财富水位入口 | 并入 /reports(报表)tab 作新 section · 不新起 tab(2026-05-29 用户纠正)—— Reports 定位本就是"钱怎么涨/跌的,跑赢通胀和市场没",且已有 人赚/钱赚 KPI + vs基准 pill 可直接复用 |
| D5 | 股票扣款币种 | 账户币种(account.currency)+ 自动 FX 换算 |
| D6 | 股票买卖对称 | 全对称:买入扣现金、卖出/减仓/归档按市价加回 |
| D7 | FIRE 支出口径 | 新增「自动适配月结支出」开关(默认仍 FIXED 保兼容)· 窗口默认 12 期 · 平滑默认 剔极端值 · 触发点 周期关闭 · 派生值回写 monthlyExpense 同字段使下游零改动 |
用户故事:作为家庭成员,我希望系统用的是真实的、可追溯的 CPI / M2 数据,而不是某个写死的猜测值。
需求:
- 新建宏观基准数据存储,按年度记录:整体 CPI、M2 增速、数据来源、抓取时间
- 历史数据 seed:内置 1990-2025 年的年度 CPI / M2 历史值(公开且不变的历史事实,随版本烤入)
- 年度增量拉取:每年自动拉取最新完整年份(如 2026 年拉 2025 全年值)· 接 v0.4.18 已有的定时调度框架
- 数据来源:CPI = 国家统计局 · M2 = 中国人民银行 · 失败回退到 seed/手动录入
验收:
- 历史表有 1990-2025 连续年度数据,无断档
- 任意年份可查到 (CPI, M2, 来源, 抓取时间)
- 拉取失败不影响展示(用已有数据)· 错误有日志
用户故事:我担心单个年份波动太大(比如 1994 年 CPI 高达 24%),希望系统用稳健的方法算长期平均,而不是被极端年份带偏。
需求:对 CPI 和 M2 各算三个值并全部展示:
- 全历史几何均值:
(∏(1+rᵢ))^(1/n) − 1(复利等效年率 · 比算术平均更严谨) - 剔除极端值几何均值(默认对比线 D3):掐掉头尾各 10% 离群年份(如 1994 恶性通胀、1998-2002 通缩年)后再算几何均值
- 近 10 年几何均值:贴当前低通胀 + 高 M2 新常态
验收:
- 三个值同时算出、同时展示
- 几何均值实现正确(可单测:已知序列手算对照)
- 剔除极端值的阈值(头尾 10%)可配置
- 中国 CPI 历史极端年份(1988-89、1993-95、1998-2002)确实被剔除版本排除
用户故事:我想一眼看出我家的净资产,相对"保命线"和"社会地位线",是浮在水面上还是在下沉。
落点:/reports(报表)新增「财富水位」section(D4)· 不新起 tab · 接在现有 XIRR/基准/人赚钱赚 KPI 之后,是它们的自然延伸。
需求:一张时序图,三条线:
- 实际净资产(用户真实曲线 · 实线)
- CPI 保命线 = 期初净资产 × 累计 CPI 因子(虚线)
- M2 地位线 = 期初净资产 × 累计 M2 因子(虚线)
- 数字直接浮在线上 / 数据点上(承 [[feedback_chart_datalabels]] · 不靠 hover)
- 水位隐喻文案:净资产在 CPI 线上方 = 生活质量保住 · 在 M2 线上方 = 社会排位上升 · 卡两线之间 = 活得下去但在掉队
- UI 一律 inline SVG,不用 emoji(承 [[feedback_no_emoji]])
验收:
- 三线正确渲染 · 累计因子 = 区间内逐年 ∏(1+rᵢ)
- 期初锚点 = 用户选定区间起点净资产
- 三种相对位置(全在上 / 卡中间 / 全在下)文案都正确触发
用户故事:我想知道我"实际"赚了多少(剔除通胀后),以及我是靠工资攒的还是靠投资赚的——因为如果全靠工资,一旦收入断了水位会暴跌。
需求:
- 真实收益 KPI = (1+名义增长)/(1+累计CPI) − 1 · 标注"剔除通胀后的真实购买力变化"
- 相对社会收益 KPI = (1+名义增长)/(1+累计M2) − 1 · 标注"相对社会财富份额的变化"
- 人赚/钱赚分解诊断 —— 直接复用 Reports 已有的 KPI(
_region.html当前已渲染「人赚的·净流入 / 钱赚的·投资 PnL / 资产年化 TWR / vs基准 pill」),不新建数据:- 把"跑赢/跑输 M2"归因到已有的「人赚(净流入)」和「钱赚(投资 PnL)」两部分
- 典型诊断文案:"你跑赢了 M2 地位线,但全靠人赚(工资储蓄 +12.3%);钱赚(投资 +1.8%)其实跑输了 CPI。水位靠收入硬撑,一旦收入中断会迅速下沉。"
验收:
- 两个收益率口径与水位图一致
- 分解归因数字与 Reports 现有 净流入/投资PnL KPI 一致(同源 · 不重算)
- 至少 3 种诊断情景(双赢 / 靠人赚撑 / 双输)文案正确
用户故事:作为一个想搞懂的人,我希望看到这些 CPI/M2 平均值到底怎么算出来的,而不是被告知一个数字就完事。
需求:可展开的推导面板,展示:
- CPI:2025 实际值(来源) / 全历史几何均值 / 剔极端值几何均值(标"默认对比") / 近 10 年几何均值
- M2:同上四项
- 当前对比区间的累计因子计算式
- 每个数标注数据来源 + 抓取日期戳(过期数据 UI 淡化,承数据时效纪律)
验收:面板四项齐全 · 数字与图/KPI 一致 · 来源日期戳可见
用户故事:我平时主要看 dashboard,希望那条已有的 CPI 对照线变成真的,并且也能看到 M2 线。
需求:
- 把 v0.4 dashboard 净资产趋势上硬编码 2% 的 CPI 对照线,换成 FR-70 拉取的真实 CPI
- 加一条 M2 线
- 保留"想看详细水位分析"→ 跳
/reports财富水位 section 的入口(dashboard 做速览,Reports 做深看)
验收:dashboard 不再出现硬编码 2% · CPI/M2 两线与 /reports 财富水位 section 一致 · 向后兼容(无历史数据时优雅降级)
用户故事:作为管理者,我想能看到当前用的 CPI/M2 值、手动刷新、并选择用哪种平均方法。
需求:在「数据源接入」页(v0.4.23 改名)新增第④段「宏观基准 CPI/M2」:
- 当前年度 CPI/M2 值 + 来源 + 抓取时间
- 一键手动刷新(承 [[feedback_admin_runtime_config]] · 外部接入配套手动触发)
- 历史数据表(只读 · 分页)
- 默认对比方法选择(剔极端/全历史/近10年 · 默认剔极端)· 存 family_runtime_config · 实时生效
验收:页面 200 · 手刷可用且限频 · 方法切换实时改变 /wealth-level 默认线 · 不重启
用户故事:体检的 AI 诊断应该知道我跑赢/输了通胀和 M2,给出对应建议。
需求:
- 把双基准(真实收益 / 相对社会收益 / 人赚钱赚分解)的算好的数字喂进 checkup 收益维度的 prompt
- AI 输出文字解读(数字工程算好,LLM 不算 · 承 [[feedback_llm_no_math]])
- 典型:"跑赢 CPI 跑输 M2 → 购买力保住但社会相对财富下滑,建议提高权益/不动产配置比例"
验收:prompt 含算好的双基准数字(read 验证)· AI 不做数学 · 误杀/胡话防回归
用户故事:我想看到我家收入和支出随时间的走势对比,一眼看出储蓄能力是在变强还是变弱。
现状:/reports 储蓄能力 section 已有「月度收支双柱图」(PMC 源 · 正确)做逐月对比;缺的是趋势视角。(顺带印证 FR-84:同一页 储蓄区双柱用 PMC 显示正确,净流入 KPI 用 cash_flow 显示 0 —— 同页两个源,正是 bug 现场。)
需求:
- 在储蓄能力 section 现有双柱图旁/下,新增收支趋势图:
- 收入线 + 支出线(按周期时序)
- 两线之间填充 = 储蓄额(income > expense 染 forest 绿 · 负染 rust 红)
- 可选叠加储蓄率走势(次轴或独立 sparkline)
- 数据源 = PMC(
findFamilyAggregateRecent)· 只取真实填报的周期(空期不参与 · 同 FR-84/FR-82 红线) - 数字浮在数据点上(承 [[feedback_chart_datalabels]])· Chart.js + SVG 图标 · 不 emoji
- 定位自洽:框为「储蓄能力走势 / 人赚引擎」(摸清攒钱能力的趋势),不是 v0.4 砍掉的逐笔「流水视角」—— 不回归瀑布/桑基
依赖:FR-84(统一 PMC 净流入口径)· 与 FR-82(FIRE 自动支出读同一月支出)同源
验收:
- 趋势图收入/支出线与储蓄区 KPI、双柱图同源一致(都 PMC)
- 空期被正确排除 · 储蓄填充正负染色正确
- 双柱(对比)与趋势(走势)并存,各司其读
核心认知:「买入股票」在买入当刻是净值中性的 —— 把 X 元现金换成 X 元股票,账户总价值不变;盈亏是之后价格波动才产生。所以这是账户内部两个 holding 之间的再分配,不计入收入/支出 cash_flow(否则会凭空改变净资产)。
用户故事:我录入"买了 100 股 PDD @ $80"时,希望系统自动从账户现金里扣掉买入花的钱,而不是让股票凭空多出来、现金还原封不动。
需求:
/accounts/{id}/holdings/new-auto表单新增开关「从账户现金划转买入」- 勾选 → 买入成本
costBasis变必填(前后端都校验) - 后端创建 AUTO 持仓的同时:
股数 × 成本经 FX 换成账户币种(D5),从账户币种的 CASH 现金行扣减- 账户无该币种现金行 → 新建一条负值现金行
- 现金允许为负(卖空 / 融资 / 保证金 · 不做非负校验)
- 触发
refreshAllForFamily(HOLDING_CHANGE)重算
验收:
- 勾选未填成本 → 报错(前后端)
- 买入后:AUTO 持仓 +、账户币种现金 − (FX 换算正确)
- 买入当刻账户总值中性(市价=成本时)
- 现金可负 · 无该币种现金行时自动建负值行
用户故事:既然买入扣现金,那我减仓或归档持仓时,卖出的钱也应该自动回到账户现金里。
需求(D6 全对称):
- 减仓 / 归档 AUTO 持仓 →
减少股数 × 当前市价经 FX 加回账户币种现金行 - 按市价加回(卖出当刻净值中性 · 浮盈早已体现在卖前价值)
- MANUAL 持仓归档 → 按 manualValue 加回 · CASH 行本身不涉及
- 仅对"曾用现金联动买入"或用户显式勾选的持仓生效(避免误伤纯手工录入的老持仓 · 向后兼容)
验收:
- 减仓/归档后现金按市价加回(FX 正确)
- 部分减仓 vs 全归档都正确
- AUTO / MANUAL 两种持仓加回口径正确
- 老持仓(未联动)归档不动现金(backward compat)
用户故事:我在账本里要能看到"用 ¥X 现金买了 100 股 PDD"这条记录,知道钱去哪了,但它不该被算成一笔支出。
需求:
- 账户内买入/卖出在 ledger 显示一条再分配记录(类似 v0.4.1 估值事件的展示形式 · inline SVG 图标)
- 文案如「买入 100 股 PDD · 现金 −¥56,400」/「卖出 50 股 · 现金 +¥30,000」
- 明确不计入收入/支出统计(净值中性 · 与 cash_flow 区分开)
验收:ledger 显示再分配行 · 不进收支汇总 · 不污染储蓄能力指标 · 图标用 SVG 非 emoji
现状:
/goals的退休/FIRE 目标,月支出(Goal.paramsJson.monthlyExpense)是用户填死的固定值 →annualSpend ×12 → 通胀 PV → / 4% 提取率 → targetValue(缓存在Goal.targetValue)。问题:用户填的支出值往往拍脑袋,且生活水平变化后不更新,FIRE 目标失真。核心设计点:月支出派生值回写进
paramsJson.monthlyExpense同一字段 + targetValue 仍是 Goal 缓存字段 → 所有下游消费方(进度 / 三情景预测 / AI报告 / dashboard 目标条)透明工作、零改动。工作量集中在「开关 UI + 周期关闭重算钩子 + 移动靶沟通」三处。
用户故事:我填的"退休后月支出"其实是猜的。我希望能让系统按我实际每月的月结支出来定 FIRE 目标,而不是一个我拍脑袋的固定数。
需求:
- FIRE 目标设定/编辑表单,月支出口径新增二选一:
- 固定值(现状 · 默认 · 用户手填)
- 自动适配月结支出(按近 N 期真实家庭月支出滚动算)
- 选自动 → 可配
窗口期数(默认 12,平掉季节性)+平滑方式(均值 / 剔极端值 / 中位数 · 默认剔极端,承财富水位同源思路防一次性大额带偏) GoalParams加expense_mode(FIXED / AUTO_MONTHLY · 默认 FIXED 保向后兼容)+expense_window_months+expense_smoothing
验收:
- 开关默认 FIXED · 老目标不受影响(向后兼容)
- 选 AUTO 时窗口/平滑可配 · 选 FIXED 时退回手填
- 切 AUTO→FIXED 时,以最近一次派生值作为新的手填种子(不丢)
用户故事:我每个月记完账,FIRE 目标应该自动跟着我的真实支出走,不用我手动改。
需求:
- 数据源:
PeriodMemberCashflowMapper.findFamilyAggregateRecent(家庭月支出 = SUM 成员 total_expense_input) - 触发时机:周期关闭时(承现有指标重算钩子)对 AUTO 模式 FIRE 目标重算月支出基准 → 重算
targetValue→ 落库;另加目标页访问时的惰性兜底 - 存储:派生月支出回写
paramsJson.monthlyExpense+ 记computed_at(供 UI 显示"基于近12月 · 更新于 YYYY-MM") - 正确性红线:
- 跳过未填报的空期(
findFamilyAggregateRecent用 IFNULL 0,空期会错误拉低均值 → 必须只统计真实填了支出的周期) - 数据不足(< 窗口期数):回退可用期数均值;一期都没有 → 回退用户填的种子值 + 提示"数据不足,暂用手填值"
- 跳过未填报的空期(
验收:
- 周期关闭后 AUTO 模式目标的 monthlyExpense + targetValue 自动更新
- 空期被正确排除(构造含空期数据验证均值不被拉低)
- 数据不足时优雅回退 + 提示
- 派生值在今天币值口径,通胀 PV 层(
×(1+通胀)^years)仍叠加在上面
用户故事:目标会随我的支出变动,我希望界面讲清楚"为什么我的目标数变了",而不是莫名其妙进度倒退。
需求:
- 进度 / 三情景预测 / dashboard 目标条 透明读派生后的 targetValue(因回写同字段,无需逐个改)
- 移动靶沟通:AUTO 模式目标卡显示"目标随实际支出动态调整 · 当前基于近 N 月均值 ¥X · 更新于 YYYY-MM"
- AI 偏离预警(90天节流)适配:targetValue 因支出上升而上调时,预警文案区分"目标因近期支出上升而上调、达成日推迟",而非误判为用户退步
验收:
- AUTO 模式下进度/预测/目标条数字与新 targetValue 一致
- 移动靶说明文案正确(含基准值 + 更新时间)
- AI 预警在 target 上移时文案正确(不误判退步)· 数字工程算好 LLM 不算
现象(prod 报告):reports「人赚的·净流入」显示 0,但用户明明收入 > 支出。
根因:净流入来自 principalVsReturnDecomposition → periodIncome/periodExpense → AccountPeriodFact.incomeBase/expenseBase,只读账户级 cash_flow。但用户工资填在 period_member_cashflow(PMC · /entry 成员月度收支两框),不是逐笔 account cash_flow → incomeBase ≈ 0 → 净流入 = 0。
- v0.4.3 B2 已为「月均支出」确立 "PMC 优先 · cash_flow 回退"(
averageExpense),但净流入分解漏改,仍只读 cash_flow。 - 连带 bug:钱赚的(PnL = ΔNW − 净流入)被高估 —— 把工资攒的钱误算成投资赚的。
- 不是
for i=1跳第 0 期所致(那是 PnL 恒等式锚定需要,人赚+钱赚=ΔNW 要求净流入与 ΔNW 同窗口)。
影响面(3 处同源):
principalVsReturnDecomposition(reports 净流入 KPI + 本金vs收益分解图)netInflowForPeriod(v0.4.2 · dashboard 人赚/钱赚)/checkup收益质量卡(若复用上述)
修复:
- 统一净流入口径 = PMC 优先 · 逐期回退 cash_flow(承 v0.4.3 B2 同纪律)· 每期:有 PMC 用 PMC 的 (income − expense),该期 PMC 空则回退该期 account cash_flow
- 同步改 reports 分解 + dashboard
netInflowForPeriod+ checkup,三处口径一致 - 必须守 人赚的 + 钱赚的 = ΔNetWorth 恒等式(改完构造数据验证两者加和)
- FR-73 前置依赖:此源不修,财富水位的人赚/钱赚分解诊断就建在错数据上
验收:
- 构造"只填 PMC、无 account cash_flow"数据 → 净流入正确(非 0)· 旧"只填 cash_flow"数据仍正确(回退路径)
- 人赚 + 钱赚 = ΔNetWorth(单测断言)
- reports / dashboard / checkup 三处净流入数字一致
- 向后兼容:两种历史数据(纯 PMC / 纯 cash_flow / 混合)都正确
附:实现时顺带排除次因 —— 若个别账户 incomeBase 因缺 FX 汇率为 null 被静默吞掉,也要补 fallback(实现期 read 一次 prod 数据形态确认主因 = PMC 双源,非 FX null)。
- ✗ 个股逐笔买卖流水 / 持仓成本 FIFO/LIFO 核算(到"账户月末快照"为止,不到逐笔)
- ✗ 实时盯盘 / 分钟级行情
- ✗ CPI/M2 之外的指数(沪深300、房价指数等留待后续评估)
- ✗ 公积金/房贷利率工具(B 系列)、CRS/个税(O/P)、双角色记账(A)—— 推 v0.6+
- ✗ 券商 API 直连下单 · 银行账单 OCR
mvn test全绿(在 v0.4 的 190 基础上 + 新增 FR-70~80 单测)qa-run.shv05-* 段全绿qa-e2e.sh端到端(含财富水位真值校验 + 股票现金联动真值校验 + FIRE 自动支出派生真值校验)- beta(
http://43.106.119.1/)部署 + 用户浏览器验收 - 向后兼容:宏观表 ADD TABLE · 股票联动仅对显式勾选持仓生效 · 0 破坏现有数据
- 第 1 轮 · app 横评:扫国内外理财/记账 app 功能 → 偏表层,被用户批"没考虑国情"
- 第 2 轮 · 国情对齐:转去知乎/雪球/律所专栏挖真实痛点 → 锁定国情独有空白(公积金/CRS/双角色)
- 第 3 轮 · 底层逻辑:用户批"LPR 时效性 + 底层逻辑没拎清" → 学到要先拎因果链、核数据时效
- 收敛:用户最终把 v0.5 收窄为单一主题「财富水位 · 资产 vs CPI/M2」—— 比铺开的 Tier 清单聚焦得多
- CPI 答"绝对购买力/生活质量",M2 答"相对社会财富份额/阶层地位"——两个根本不同的问题
- 中国 M2(~9%)远高于 CPI(~2%),"跑赢 CPI 只是保命,跑赢 M2 才是真增值"是中文理财语境的共识
- 双线差距能让"看着在涨、其实在掉队"这件隐形的事变得可见
- D1 选 headline CPI 而非核心 CPI:核心 CPI 剔食品(不含"吃")+ 仅 2013 起无长历史
- D3 默认剔极端值几何均值:中国 CPI 史有 1994=24.1% 这类极端年,简单平均会严重失真
- D2 总净资产 + 人赚/钱赚分解:既答"家庭是否跑赢",又诊断"靠收入还是靠投资"(可持续性)
- D5/D6 股票联动选完整模型(本位币 FX + 全对称):用户主动选了更完整而非最小实现
- 宏观数据拉取:NBS/PBOC 官方接口 vs 第三方聚合 vs seed+增量(倾向 seed+增量,历史不变只拉新年)
- 几何均值/剔极端值的数值实现 + 边界(通缩负值年的处理)
- 股票"账户币种"=
account.currency的确认 + 无该币种现金行时建负值行的细节 - 财富水位区间选择器(YTD / 近1年 / 近3年 / 自起始)与累计因子对齐
用户诉求:我们早先给计算型 KPI 加了 ⓘ 小叹号,但它只讲「口径公式」(如「流动资产 ÷ 月均支出」)。用户希望点开后看到真实的计算数值(如「流动资产 ¥18.5万 ÷ 月均支出 ¥1.8万 = 3.2 月」),让非技术家庭成员能验证、能信任每个数字怎么来的。
- 全站梳理出 28 个计算型 KPI(净资产 / 总资产 / 总负债 / 紧急储备 / 本月资产收益 / 流动资产 / 本年累计损益 / 人赚净流入 / 钱赚 PnL / 月均收入 / 月均支出 / 储蓄率 / 月储蓄能力 / 已填月份 / vs 基准 / 家庭 XIRR / 资产年化 TWR),分布在 dashboard / reports / reports 储蓄区 / checkup 四个页面。
- 每个 ⓘ 面板在原口径文字下方,多加一条真实实算行(虚线分隔 + 等宽字体):把当前账期/区间的真实中间数值代入公式展示。
- 币种一致:dashboard、reports KPI 区按当前展示币种(viewCurrency);checkup 与 reports 储蓄区按家庭本位币(模板原本就如此)。数值与页面上 KPI 同源同币种,绝不出现「面板里一个数、KPI 卡上另一个数」。
- 诚实口径:XIRR / TWR 是迭代/几何解,无法写成单条四则算式 → 只展示真实输入端点 + 解得值(如「期初净资产 −¥B → 期末 +¥E · N 期求解年化 = x%」),不编造算术步骤。
- 纯定义指标(账户级 XIRR 为何为 0% 的成因说明、基准列定义)无可代入数值 → 保留口径文字,不强加数字。
- 不改任何指标的计算口径(只把已算出的中间量暴露出来展示;计算逻辑零改动)。
- 不在前端做算术(沿用 [[feedback_thymeleaf_diagnosis]]:数值一律服务端算好成串再传模板,避免 SpEL 沙箱问题)。
用户在目标详情「AI 综合月报」发现三个问题:
月报里出现「建议成员A与成员B共同核查」—— 给 LLM 的真名脱敏代号(成员A/成员B)未在展示前还原回真名(v0.3 起 latent)。修:校验仍在代号原文上做(防真名误判泄露),通过后 reverseMapping(raw, 代号→真名) 还原,与资产体检 AI 诊断完全同口径。
确认:月报本就持久化在 goal_ai_report(UNIQUE(goal_id,period_id,report_type) upsert),详情页加载直接复用已存月报(= 缓存命中,不重算)。补齐 UI:有月报时显「本期复用 · 渲染于…」+「重新生成」按钮(对齐 checkup ↻ 强制刷新语义),原先仅"尚未生成"态才有触发入口。缓存是周期级(下个周期关闭或手动重新生成才更新),非时间 TTL —— 月报本就按账期定义,符合语义。
仪表盘目标进度条带每个目标卡右侧加一个小入口(inline-SVG · book-open + AI 字样),直达 /goals/{id}#ai-report 本期月报锚点,用户从仪表盘可一键进入当期 AI 总结。
- 不改月报生成时机(仍:周期关闭自动 + 手动触发)· 不引入时间 TTL(周期级缓存即可)。
报表页四个核心 banner —— ① 家庭 XIRR(含收入)② 资产年化 TWR(剔收入)③ 人赚的·净流入 ④ 钱赚的·投资 PnL —— 当前共用一个数据切片,锚定期取"当前 OPEN(进行中)账期"(ReportsController.anchorPeriod 自 v0.5.1 起 findCurrentOpen() 优先)。
这违背了产品最初的分工:报表 = 已关账账期的稳定快照 · 仪表盘 = 实时(此分工在 v0.1 存在,后被 2026-05-10「dashboard 改实时」与 v0.5.1「绕开 2032 测试期」两次改动抹平,reports 与 dashboard 现都锚 OPEN 期)。
由此产生用户实感的怪象——#3 人赚常年显示 0。根因三件事叠加(FactViewServiceImpl.principalVsReturnDecomposition):
- 锚定在 OPEN 期,而月中该期通常还没填,作为窗口终点贡献 ≈0;
- 逐期分解永远把窗口最老一期当基准、排除其净流入;
- 家庭账期少时(如仅"上月已关账 + 本月 OPEN 空"两期),唯一填了数的已关账月恰好成了被排除的基准,真正计入的只剩那个空 OPEN 期 → #3 = 0。
用户"月末几分钟填一次"的使用节奏下,只要账期不够多,#3 就长期为 0,且 XIRR/TWR 还会用"月中半填的净值"做终点,失真。
- 报表四指标的数据切片终点改为"最近一个已关账(
status=CLOSED)且period_start ≤ 今天的账期";dashboard不动,保持实时(锚最新一期、含 OPEN)。两个 tab 分工重新清晰。 - 终点永远是填满的已关账月:XIRR/TWR 不再用月中半填净值;#3/#4 不再被空 OPEN 期拖成 0。
- 用户月末填完并关账后,报表立即纳入该月(符合"关账即入快照"心智);未关账前,报表稳定停留在上一已关账月。
period_start ≤ 今天的约束顺带干净地解决了当初 v0.5.1 要绕的"测试/误建未来账期(如 2032)被findLatest锚到"的问题——不必再靠 OPEN 期兜底。
- 逐期差额/回报本就需要 ≥2 个已关账账期才能计算(要有上一期做起点)。当不足时:
- 仅 0 个已关账期(全新家庭):报表顶部显引导「尚无已关账账期 · 完成本月填报并关账后,这里出现收益快照」,四 banner 显「—」。
- 仅 1 个已关账期:四 banner 显「—」+ 小字「需 ≥2 个已关账账期」,不再显误导性的 0。
- 其余报表区块(账户级收益表、风险分布、储蓄能力、财富水位)按各自既有口径照常显示,不受影响。
- #3「人赚的·净流入」ⓘ 口径补一句:这是所选区间内逐期(收入−支出)累计(与下方"本金 vs 投资损益"分解柱状图同口径、且满足"人赚+钱赚 = 区间净资产变化"恒等式),非单月。
光靠角落小字不足以让用户意识到"报表只含已关账账期"。在报表页头醒目透出,呼应晚清账册 / 朱印美学:
- 朱印红「已关账」印章:标题(
数 · 字 · 所至)右侧盖一枚朱印风格徽记(朱红--rust系 · 印章感边框 · 可微旋转/做旧),作为本页身份标识常驻,一眼区分于 dashboard。 - 说明行(替换原 anchor 提示):
本页为已关账账期的稳定快照 · 数据截至
2026 年 5 月。进行中的本月请看 仪表盘 →(链接/dashboard)仪表盘为链接,引导想看实时的用户去 dashboard,强化两 tab 分工。
- 与空态联动(承 FR-95):有已关账锚定期 → 显印章 + "数据截至 X";0 个已关账期 → 不显印章,改显 FR-95 的引导空态卡(避免盖一个"截至无"的空印章)。
- 排版示意(用户已选定):
月 · 度 · 大 · 账 数 · 字 · 所至 ┌────────┐ │ 已关账 │ ← 朱印红印章 └────────┘ 本页为已关账账期的稳定快照 · 数据截至 2026 年 5 月 进行中的本月请看 仪表盘 → - 全站 emoji 红线照旧:印章用 SVG/CSS 实现,不用 emoji([[feedback_no_emoji]])。
- #3/#4 保持"窗口累计"口径(不改成"最近关账月单月净流入")。理由:① 与下方分解柱状图一致;② 维持"人赚 + 钱赚 = 区间 ΔNetWorth"恒等式;③ 与同panel的 XIRR/TWR(本就是区间/年化)口径协调。改单月会破坏这三点。
- 窗口仍由现有 range 选择器(1M/3M/6M/YTD/1Y/ALL)控制,只是窗口终点从 OPEN 期改为最近已关账期。
- 不改 dashboard(继续实时锚最新一期)。
- 不改任何指标的数学口径(XIRR/TWR/人赚/钱赚算法不动),只改"锚定到哪个账期"。
- 不引入"报表含进行中账期"开关(会再次模糊 reports/dashboard 分工 · 明确不做)。
- 0 schema 改动(仅新增一个只读查询 + controller 锚定逻辑)。
- prod 真实数据:报表锚定到最近已关账月,四指标非 0(在有 ≥2 已关账期时);关账新月后报表立即纳入。
- 2 个已关账期家庭:#3 = 第 2 个已关账月净流入(非 0);1 个 → 显空态而非 0。
- 存在未来账期(2032 测试期)时不被锚定。
- dashboard 行为不变(仍含 OPEN 实时)。
- 报表页头显朱印红「已关账」印章 + "数据截至
<最近关账月>" + 指向仪表盘的链接;0 已关账期时显引导空态而非空印章。印章为 SVG/CSS(无 emoji)。
报表页很长(收益概览 / 本金vs投资 / 财富水位 / 负债风险 / 账户级收益 / 资产配置 / 储蓄能力)。v0.5.1 加过一个右下角低调小 FAB 目录,但易被忽略、无"读到哪一节"高亮,远不到长文档应有的导航体验。调研业界(飞书 / Notion / MDN / NN/g / Wikipedia 2025 移动实验)后升级。
- PC(≥lg):报表右侧常驻 sticky 目录栏,树状大纲(竖向引导线 + 横向树枝 · 支持多层嵌套),scrollspy 高亮当前所在节(滚动联动 ·
aria-current作样式钩子 · 当前节朱铜高亮、父级淡显)· 点击平滑跳转。 - 手机(<lg):右栏收起,左上角出现「目录」唤醒钮 → 底部 sheet 滑出(拖拽手柄 + 关闭 × + Esc/返回键 · 触控行 ≥44px · 点击跳转后自动收起,不丢阅读位)。
- 章节锚点:
#reports-region(收益概览)/#sec-decompose/#sec-risk/#allocation-diff(条件)/#sec-accounts/#sec-wealth/#sec-savings,均设scroll-margin-top处理 sticky-nav 偏移。 - 嵌套就绪:当前各节为平铺;CSS/结构按树设计,未来任意加子节(缩进 + 引导线 + 树枝)自动体现层级。
- dashboard 不加目录(它短)· 不做纯 CSS scrollspy(浏览器支持不足,用 JS)· 不自动展开全部章节(Wikipedia 2025 实验证明反降留存)· 0 后端 / 0 schema(纯前端)。
v0.5.6 报表长文目录验证 OK。推广到其它长 tab 页,并把目录沉淀为可复用件,避免每页重写。
- 共用件:
fragments/_toc.html(rail(items)/mobile(items)两片段)+static/js/toc.js(页面无关 scrollspy + 底部 sheet · 自动接[data-toc-nav])+style.css布局类.toc-cols/.toc-cols-main(泛化自.reports-cols)。页面只需:<main th:with="tocItems=${...}">包.toc-cols(内容列 +rail)+mobile+ 引toc.js。 - 接入页:
- dashboard:概览 / 净资产趋势 / 按成员分布 / 按账户分布 / 账户列表
- checkup:概览 / 资产配置 / 风险敞口 / 流动性 / 收益质量 / 智能建议 / AI 综合诊断 / 单账户体检
- reports:改用共用件(行为不变)
- 不做目录的页(明确非目标):填报(/entry · 任务表单)/ 账户(/accounts · 列表)/ 目标列表(/goals · 卡片列表)/ 管理(/admin · 管理页)—— 非长文阅读,不需目录。
- 迭代纪律:任何改动某 tab 页 section 结构,须同步该页目录锚点/条目(memory
feedback_toc_sync)。
- 不动任何指标/数据/后端;0 schema;纯前端。
- 条件 section(advice 互斥两态)用「同 id」保锚点恒在;allocation-diff 缺失时容忍 dead-anchor(无害 no-op)。
- dashboard/checkup/reports 三页均有目录(PC 左侧常驻 + scrollspy · 手机左上钮→sheet)· 锚点全部可解析 · HTMX 换 region 后 scrollspy 仍准。