Files
X-Financial/document/development/2026-07-16/feature/savings-ledger-and-cfo-value/TODO.md
caoxiaozhu 787bc3a481 feat(platform): close AI expense value loop
Add tenant-safe value, telemetry, connector, commercial, and production-readiness foundations.
2026-07-17 14:14:08 +08:00

142 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 节省事实账本与 CFO 经营价值看板 开发 TODO
更新时间2026-07-17
## 使用规则
- 每条 TODO 必须回链 `CONCEPT.md` 的章节或语义段落。
- 只有代码、接口或容器验证提供真实证据后才能勾选 `[x]`
- 现金节省、工时价值、风险暴露和预计机会始终分开,不以演示数据代替缺失事实。
- 实施顺序为:安全前置 → 账本 → 首条闭环 → 基线/分析 → CFO 前端 → PostgreSQL/E2E → 文档收口。
## 1. 调研与边界
- [x] [CONCEPT: 背景与问题] 盘点财务看板、预算、Claim、Expense Case、Business Event、风险、审批、付款和标准重算事实源。
证据:`finance_dashboard.py``finance_dashboard_snapshot.py``financial_record.py``expense_cases.py``expense_claim_standard_adjustment.py``expense_claim_approval_flow.py` 的只读审计。
- [x] [CONCEPT: 目标与非目标] 确认风险金额、未用预算、预计机会和未确认结果不得进入已确认节省。
证据CONCEPT「目标与非目标」「算法与公式」。
- [x] [CONCEPT: 用户与场景] 选择住宿职级标准重算作为首条纵向闭环,不选择证据不足的重复支付或供应商议价。
证据:现有标准重算和付款业务事件可形成最短可信证据链;`AccountsPayableRecord` 已有租户字段,但仍缺合同价、数量、单位价格和外部付款事实。
- [x] [CONCEPT: 风险与开放问题] 识别旧财务聚合全表读取、快照键缺租户、接口缺角色限制和标准重算信任客户端原金额问题。
证据:`FinanceDashboardMetricMixin._fetch_claims()``_fetch_budget_allocations()``FinanceDashboardSnapshotService._cache_key()``accept_standard_adjustment()`
## 2. 契约与设计
- [x] [CONCEPT: 数据与契约] 定义 baseline、opportunity、realization、evidence 和 append-only event 的职责与关键字段。
证据CONCEPT「数据与契约」。
- [x] [CONCEPT: 算法与规则] 定义 identified → accepted → in_progress → realized → verified → reversed 状态和 rejected/expired 终态。
证据CONCEPT「状态转换」。
- [x] [CONCEPT: 算法与规则] 定义 benefit key、canonical realization、归因比例和追加冲回规则。
证据CONCEPT「收益去重」。
- [x] [CONCEPT: 权限] 定义租户、finance/executive、预算范围、管理员只读、自证禁止和数据范围。
证据CONCEPT「权限」。
- [x] [CONCEPT: 算法与公式] 定义 3 个主 KPI、驱动指标、风险护栏和缺数据边界。
证据CONCEPT「算法与公式」。
## 3. 安全前置
- [x] [CONCEPT: 后端] 让旧财务看板显式接收可信租户与数据范围Claim/预算查询不得全表混算。
证据:`finance_dashboard_access_policy.py``finance_dashboard_scope.py``finance_dashboard_budget.py``finance_dashboard.py`Claim 直接按结构化 `ExpenseClaim.tenant_id` 首层过滤,预算历史兼容仅限 default 租户。
- [x] [CONCEPT: 后端] 给财务快照缓存键和后台任务加入租户/数据范围,禁止跨租户复用。
证据:`finance_dashboard_snapshot.py``finance_dashboard_scheduler.py`;快照键包含 tenant 与 scope fingerprint调度入口必须显式携带租户。
- [x] [CONCEPT: 权限] 给财务与 CFO 分析接口增加后端角色和范围校验,管理员身份不自动获得业务确认权。
证据:`finance_dashboard_access_policy.py``savings_access_policy.py``agent_run_access_policy.py``GET /api/v1/analytics/cfo-value`;容器租户/缓存/角色回归 17 项通过。
- [x] [CONCEPT: 第一条可信机会] 标准重算只使用锁定数据库明细原金额,客户端原金额不能影响结果和节省。
证据:`expense_claim_standard_adjustment.py`;原金额只读锁定 `ExpenseClaimItem.item_amount`,政策结果只由服务端重算,陈旧版本使用内容指纹并降低基线质量等级。
- [x] [CONCEPT: 后端] 将标准重算、审计和账本写入收口到同一事务边界。
证据:`expense_claim_standard_adjustment.py``commit=False` 写审计,同一 API 事务写 Claim、Baseline、Opportunity、Evidence、SavingsEvent 和 BusinessEvent事务失败整体回滚。
## 4. Savings Ledger 后端
- [x] [CONCEPT: 数据与契约] 新增 `profile_baseline_snapshots``savings_opportunities``savings_realizations``savings_evidence_links``savings_events` 模型。
证据:`savings.py`(模型)及 `test_savings_models.py`;五类事实分离保存基线、机会、结果、证据和不可变操作。
- [x] [CONCEPT: 数据与契约] 新增 Alembic 0015、迁移所有权、复合租户外键、唯一键、检查约束、索引和 append-only 触发器。
证据:`20260716_0015_savings_value_ledger.py``migration_preflight.py``schema_ownership.py`;一次性 PostgreSQL 17 空库完整迁移循环通过。
- [x] [CONCEPT: 后端] 实现 discovery、action、realization、query、access policy 和 response builder 独立服务。
证据:`savings_discovery.py``savings_actions.py``savings_realization.py``savings_query.py``savings_access_policy.py``savings_read_projection.py``savings_protocol.py`
- [x] [CONCEPT: 后端] 实现分页、筛选、排序、详情、可用动作、证据和事件 DTO。
证据:`GET /api/v1/savings/opportunities``GET /api/v1/savings/opportunities/{id}``savings.py`schema/API`test_savings_endpoints.py`
- [x] [CONCEPT: 算法与规则] 实现版本锁、请求指纹、不可变响应重放、收益去重和归因比例约束。
证据:`SavingsRequestProtocol`、数据库唯一/检查约束与 `test_savings_concurrency_postgres.py`;同 request 并发仅一次写入,同 benefit 双确认仅一个 canonical winner。
- [x] [CONCEPT: 状态转换] 实现 accept/start/record/verify/reject/expire/reverse 合法与非法转换。
证据:`savings_actions.py``savings_realization.py``test_savings_ledger_services.py`;负向 reversal 只追加,不改写原已确认金额。
- [x] [CONCEPT: 证据与审计] 把 Savings 关键动作写入同 Case 的 `BusinessEvent` 并保留 correlation/causation。
证据:`ExpenseCaseService` 资源链接与 `savings_*` 服务;端到端测试核验 opportunity/payment/action/confirm/reverse 事件同 Case 可回放。
- [x] [CONCEPT: 后端] 新增历史标准重算机会 dry-run/apply 回填脚本;缺 Case/租户/政策证据只输出数据质量报告。
证据:`savings_standard_adjustment_backfill.py``backfill_standard_adjustment_savings.py`;显式租户/目标库、指纹重算、批次锁、稳定键重放,容器直接测试 8 项通过。
## 5. 首条真实纵向闭环
- [x] [CONCEPT: 第一条可信机会] 接受住宿标准重算时冻结服务端原金额、政策输入/版本、目标金额、差额、维度和证据。
证据:`SavingsDiscoveryService`冻结 `ProfileBaselineSnapshot` 与内容指纹,政式发布版本为 complete内容指纹版本显式标记 partial。
- [x] [CONCEPT: 第一条可信机会] 同事务以稳定 opportunity key 创建或重放机会,并进入 in_progress。
证据:稳定键由 tenant + claim + item + policy version + calculation fingerprint 生成;重试返回原机会。
- [x] [CONCEPT: 后端] 付款业务事件后同事务创建 actual realization重复付款事件不重复计入。
证据:`expense_claim_approval_flow.py`调用 `realize_paid_claim()`PostgreSQL 同付款事件并发结果为 `[0, 1]`,仅一条 realization 和一条完成事件。
- [x] [CONCEPT: 财务确认] 实现独立财务 verify/reject未确认实际结果不得进入主 KPI。
证据:所有人工实际结果必须至少一条可追溯证据;独立确认人会固化证据复核人/时间pending 结果在 CFO 口径中为 0。
- [x] [CONCEPT: 冲回能力] 实现补付/申诉/归因修正的负向 reversal原确认不可删除。
证据:原 actual 保留 `finance_confirmed`,新增负向 canonical reversal`as_of` 可回放冲回前结果。
- [x] [CONCEPT: 权限] 验证申请人、机会负责人、结果填报人、纯管理员和跨租户用户不能自证或越权。
证据:`SavingsAccessPolicy`与 PostgreSQL 并发安全测试owner/recorder/admin-only 自证拒绝,独立 finance 可确认,跨租户无副作用。
## 6. 费用基线与经营分析
- [x] [CONCEPT: 基线快照] 按员工、部门、费用类型、城市、项目和流程从租户安全真实数据生成基线窗口、样本量和版本。
证据:`savings_fact_scope.py``savings_baseline_generation.py``savings_insights.py`;金额五维使用已归档明细中位数,流程维度只使用同租户报销提交时间与首个 `payment_completed` 业务事件,冻结 elapsed minutes、窗口、样本量、算法版本、查询指纹、质量、证据和审计事件`source_workflow_cycle_count` 明确披露覆盖,活跃工时保持 unavailable。
- [x] [CONCEPT: 基线快照] 供应商数据缺少租户/合同事实时显示 coverage gap不从应付模拟种子生成可信基线。
证据:基线和洞察 API 均返回 `supplier_dimension_unavailable` / `supplier_price_drift_unavailable`,要求核验供应商、数量和单位价格;不会读取 `AccountsPayableRecord` 模拟事实或创建货币化机会。
- [x] [CONCEPT: 算法与规则] 实现预算预测、描述性异常归因、重复小额浪费、历史偏离和只读政策模拟准备项;证据不足时不自动货币化。
证据:`savings_insight_budget.py` 复用预算配置/核销事实并以 `min(as_of, window_end)` 截止;`savings_insight_analysis.py``savings_insight_attribution.py` 输出历史偏离、部门/费用类型/城市/项目异常集中和版本化政策模拟必需输入。所有缺少正式反事实的候选 `estimated_savings=None``created_opportunity_ids=[]`,稳定重放不写 `SavingsOpportunity`
- [x] [CONCEPT: 后端] 实现 `GET /analytics/cfo-value`,统一时间、维度、币种、状态和 `as_of` 口径。
证据:`cfo_value.py`API/schema`cfo_value_analytics.py`;租户、角色、预算范围、时间和维度过滤均在服务端执行。
- [x] [CONCEPT: 算法与公式] 实现确认现金、工时待采集、安全直通率资格、漏斗、兑现周期、逾期、来源和护栏聚合。
证据:确认现金只求和 finance_confirmed + canonical + cash工时和安全直通率显式返回 collecting漏斗、趋势、驱动、逾期、冲回和数据质量不与主 KPI 混算。
- [x] [CONCEPT: 降级策略] 多币种、工时、外部付款和审计结果缺失时返回明确数据质量状态,不伪造 0。
证据:多币种按原币分组;无人工活跃时间/审计事实时返回 collecting/unavailable 和 coverage gap不使用 mock 回退。
## 7. CFO 前端
- [x] [CONCEPT: 前端] 在分析看板新增 `value` 入口,并把 dashboard 状态同步 URL。
证据:`useTopBarOverviewRange.js``AppShellRouteView.vue``OverviewView.vue``dashboard=value` 与价值筛选/页码写入 query刷新和返回可恢复。
- [x] [CONCEPT: 前端] 新增独立 CFO 组件、composable、API service 和展示模型,不继续扩大 `useOverviewView.js`
证据:`CfoValueDashboard.vue``CfoValueTrendChart.vue``CfoValueOpportunityDrawer.vue``CfoValueActionDialog.vue``useCfoValueDashboard.js``analyticsValue.js``cfoValueDashboardModel.js`;业务组件和状态职责已拆分,核心文件均低于 800 行。
- [x] [CONCEPT: CFO 看板] 实现主 KPI、护栏、价值漏斗、趋势、来源/组织驱动、机会表和数据质量。
证据:`CfoValueDashboard.vue``cfo-value-dashboard.css`;现金、工时和直通率分卡,趋势按币种切换,预计/实际/确认/冲回不混算,缺数据显式展示。
- [x] [CONCEPT: 前端] 实现时间、部门、费用类型、价值类型筛选和项目/供应商/城市/负责人高级筛选。
证据:顶部时间窗口与价值 query 联动,`createEmptyValueFilters``readValueFiltersFromQuery``writeValueFiltersToQuery` 和 API query 白名单覆盖全部筛选字段。
- [x] [CONCEPT: 前端] 实现基线、建议、执行、实际、确认、去重和证据详情。
证据:`CfoValueOpportunityDrawer.vue` 展示冻结基线、机会状态、实际净值、记录人、canonical 去重、财务确认人/时间/说明、证据索引和不可变事件;无可追溯凭证时不开放手工实际结果登记。
- [x] [CONCEPT: 前端] 实现单据、风险、预算、维度下钻与返回状态恢复。
证据:`cfoValueSourceLinks.js` 统一构造来源路由Claim 进入 `app-document-detail`,风险携带最小 focus/观察/决策参数和现有锚点,预算进入 `app-budget` 配置视图并应用部门/费用类型焦点,维度返回 `app-overview?dashboard=value` 相应筛选。`useCfoValueDashboard.js``value_opportunity` 恢复抽屉,并在非法 ID、403/404、跨租户不可见或不符合当前筛选/时间窗口时安全清除;`useAppShell.js` 从单据详情恢复 CFO 查询。限制:预算中心仍是演示配置视图,页面明确金额不是当前机会的真实预算事实;未覆盖费用科目显示未配置而不是零预算。
- [x] [CONCEPT: 降级策略] 区分零、无数据、基线不足、无权限、失败、部分数据和快照过期;删除 CFO 演示回退。
证据:`classifyCfoDashboardState``buildValueKpis` 与页面状态区;接口失败不读取 `data/metrics.js` 或 demo/fallback 数字。
- [x] [CONCEPT: 前端] 完成移动端、键盘、焦点、44px 触控和无障碍状态提示。
证据CFO 样式移动断点、44px 按钮、语义化 `label`/`role=alert`/`aria-live`、抽屉关闭标签及趋势表格降级;生产构建通过。
## 8. 测试与验证
- [x] [CONCEPT: 测试方案] 后端状态、金额、权限、租户、幂等、证据、去重、冲回和看板聚合单测通过。
证据:容器组合回归 84 项通过;本轮 Savings/CFO 基线、洞察、端点、账本、回填与 E2E 组合 `34 passed, 6 skipped`6 项为未配置 PostgreSQL 专用 URL 的预期跳过。
- [x] [CONCEPT: 测试方案] 标准重算客户端金额伪造、政策失败、Case 缺失和事务回滚测试通过。
证据:`test_expense_claim_service.py -k standard_adjustment` 8 项加付款集成 1 项通过HTTP 标准重算 1 项通过。
- [x] [CONCEPT: 测试方案] 前端数据归一化、状态、筛选、URL、证据动作和响应式测试通过。
证据:容器内 `cfo-value-dashboard.test.mjs` 14 项通过,新增机会 URL 恢复/清理、筛选上下文、风险/单据/预算/维度链接和预算非事实口径断言;与 App Shell 返回链、路由加载和筛选样式组合回归 37 项通过;带凭证序列化和无证据入口 fail-closed 均有断言。
- [x] [CONCEPT: 测试方案] 一次性 PostgreSQL 空库迁移、重复升级、约束、append-only、无损降级和并发测试通过。
证据:一次性 PostgreSQL 17 迁移循环通过;`test_savings_concurrency_postgres.py` 6 项通过覆盖重放、canonical 竞态、跨租户、独立确认、付款单事实和 append-only DB 触发器。
- [x] [CONCEPT: 集成] 住宿标准重算 → 机会 → 审批 → 付款 → 实际 → 财务确认 → CFO 看板 E2E 通过。
证据:`test_savings_value_e2e.py` 从服务端政策差额、付款动作、待确认排除、独立财务确认到 CFO 金额对账单项通过。
- [x] [CONCEPT: 集成] 确认后负向冲回和报告 `as_of` 回放 E2E 通过。
证据:`test_savings_value_e2e.py``test_cfo_value_analytics.py`同时验证当前净值归零和冲回前历史金额回放。
- [x] [CONCEPT: 容器验证] 相关 pytest、Ruff、前端测试和生产构建均在 `local-x-financial-linux` 内通过。
证据Savings/CFO 相关切片与端到端均通过fresh PostgreSQL 总探针 `87 passed / 0 skipped / 0 failed`,其中 Savings 并发 6 项Web 全量 `815 passed / 0 failed` 与 Vite build 通过;新增 Python 文件 Ruff 和 `git diff --check` 通过。
## 9. 文档收尾
- [x] [CONCEPT: 指标与验收] 逐项核对 A1-A8并把文件、接口、迁移、测试和运行结果写回证据。
证据A1 纵向闭环由 `test_savings_value_e2e.py`A2-A4/A4.1 由 Savings schema、`cfo_value_analytics.py`、基线/分析测试A5-A6 由 CFO 组件、来源下钻和前端状态测试A7 由 0015 迁移与 PostgreSQL 并发A8 由本节最终容器汇总证明。
- [ ] [CONCEPT: 风险与开放问题] 记录付款证据等级、汇率、双人复核、工时口径和试点目标的最终边界。
证据:
- [x] [CONCEPT: 本轮实现记录] 同步更新上位 `ai-expense-closed-loop-and-value-proof` 文档,不删除历史证据。
证据:上位 TODO 已回填 Savings Ledger、状态机、CFO 看板、下钻、证据详情和 E2E历史证据原样保留。