Files
X-Financial/document/development/2026-07-16/feature/financial-connector-reconciliation/CONCEPT.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

227 lines
21 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.
# 财务连接器与支付对账闭环 概念文档
更新时间2026-07-17
## 功能一句话
把经过租户、来源、密钥版本和请求路径共同认证的 production-mode 财务事件契约接入付款、ERP、对账与 Savings 闭环,同时让所有非生产回执严格停留在只读模拟事实层;真实外部现金仍以目标 provider 联调为准。
## 背景与问题
当前报销单可以由财务人员在平台内确认“已付款”,并能联动申请归档和 Savings 实现记录,但这只是内部业务状态,不是银行、支付平台或 ERP 的外部现金事实。若继续把单一状态当成真实回执,会留下重复付款、金额/币种错配、回执伪造、凭证缺失、对账异常未处置和虚假现金节省等风险。
本功能把外部财务系统接入收敛成统一、可审计的连接器契约。首期允许使用 mock adapter 验证协议和流程,但 mock 必须完整模拟签名、幂等、失败、重试、乱序、退款、凭证和对账差异,不以直接写“已付款”代替连接器事实。
## 目标与非目标
### 目标
- 建立租户隔离、来源可验证、追加式的支付/银行/ERP 事件账本。
- 支持支付批次、结算成功、支付失败、退款/冲回、ERP 入账凭证和对账结果。
- 只有单据、金额、币种、外部引用和签名均通过校验时,才推进报销付款状态。
- 把外部事件与 Expense Case、Business Event、Savings Evidence、归档事件用同一 correlation 链关联。
- 对重复、冲突、乱序和不完整事件 fail-closed并提供可人工处理的对账异常。
- 以版本化 activate/disable/rotate 状态机管理连接器密钥,所有配置动作形成不含密钥材料的追加式审计。
### 非目标
- 不自建银行清算、企业支付网络、税务开票网络或 ERP 总账。
- 不保存银行卡号、银行流水原文、完整付款人账号或连接器密钥明文。
- 不允许连接器绕过报销审批、风险门禁、租户权限或财务确认。
- 不把 mock 回执标记为生产级外部现金证据;运行环境和证据等级必须显式区分。
## 用户与场景
- 财务付款员:提交或查看付款批次,处理失败与待匹配回执。
- 财务复核员:复核金额/币种/收款主体和对账异常,确认或拒绝处置。
- 财务负责人/CFO查看已匹配、待对账、失败、退款和未入账金额。
- 平台管理员:配置连接器公钥/密钥版本、来源白名单和健康状态,但不能代替财务确认业务结果。
- 外部连接器:按租户和来源签名推送支付、银行或 ERP 事件,安全重试并读取幂等结果。
## 功能能力
- 连接器注册与密钥版本:来源、环境、允许事件、时钟偏差、启停和轮换状态。
- 统一事件信封tenant、provider、event ID、event type、occurred at、payload hash、correlation、signature version。
- 支付批次与回执:批次创建、提交、受理、成功、失败和部分成功。
- ERP 入账:凭证号、会计期间、入账时间、受控摘要和原始内容哈希。
- 对账:按单据、金额、币种和外部引用自动匹配;差异进入人工处置。
- 冲回:退款、撤销和补付使用新事件,不更新或删除原事件。
- 可观测性:最近成功时间、失败率、重试次数、积压、签名失败和对账差异。
## 方案设计
### 模块职责
- `financial_connector_auth`:验证来源、签名、时间戳、密钥版本和重放窗口。
- `financial_connector_ingestion`:规范化事件、计算指纹、幂等写入、生产/模拟分流和冲突检测。
- `financial_connector_simulation`:只读校验 test/mock/staging 回执,不创建或修改 Claim、对账、ERP、Business Event 或 Savings。
- `financial_connector_mock_adapter`:平台管理员显式触发的非生产场景适配器;用已激活配置的真实签名链确定性生成成功、失败、乱序、重复、冲突、退款和 ERP 回执,但不提供任意 payload 注入能力。
- `financial_connector_observability`:按租户和配置聚合最近成功、失败率、重试、积压、签名失败、冲突和对账异常;只读取最小化事实与追加式运行事件。
- `financial_connector_payment_evidence`:从 Claim 的付款事实中提取统一证据 DTO明确区分 production-mode 外部回执分类、非生产模拟回执和人工付款内部状态;分类本身不证明真实 provider 已接通。
- `financial_connector_config_lifecycle`:执行带 expected version 的激活、停用和原子密钥轮换。
- `payment_reconciliation`:匹配 Claim、金额、币种和状态生成 matched / exception 结果。
- `financial_connector_actions`:在可信匹配后调用现有付款动作;支付失败、退款和 ERP 入账分别旁写事件。
- `financial_connector_projection`:为财务工作台提供脱敏列表、详情、差异和健康度。
- 供应商 adapter 只负责供应商字段映射,不直接修改 Claim、Savings 或预算。
### 数据与契约
首期新增以下 migration-owned 表,均带 `tenant_id`
- `financial_connector_configs`provider、environment、allowed event types、secret/key version、status、last success/error只保存密钥引用或不可逆验证材料。
- `financial_connector_config_events`created、activated、disabled、rotation started/replacement created 的追加式配置审计;保存 actor、request、reason、expected version 和脱敏前后状态,不保存 `secret_ref`
- `financial_connector_events`:方向、事件类型、外部事件 ID、请求指纹、原始内容哈希、发生/接收时间、验证等级、处理状态、关联单据/Case 和错误码UPDATE/DELETE 禁止。
- `payment_reconciliation_cases`Claim、期望/实际金额与币种、匹配状态、差异、处置版本、负责人和最后事件;作为可变投影,历史动作另存事件。
- `payment_reconciliation_events`:创建、自动匹配、人工确认、拒绝、重开、退款和关闭的追加式审计事件,保存请求指纹和首次响应。
- `financial_connector_operational_events``0022`):保存 `replay / auth_failure / payload_conflict` 三类运行事实的 tenant/config/provider/environment、受控原因码、两类 HMAC 指纹、幂等键和发生时间;不保存原始 payload、签名、外部事件 ID、Claim 引用、correlation 或密钥材料。复合租户外键防止跨租户归属PostgreSQL 触发器禁止 UPDATE/DELETE存在运行事实时拒绝有损降级。
关键约束:
- `(tenant_id, provider, external_event_id)` 唯一。
- 配置从 `disabled/version=1` 创建;激活和停用必须命中 expected version轮换原子地产生新 active key version 并把旧版本置为 rotating。
- 同幂等键不同 payload hash 返回冲突,不能覆盖首次事件。
- 同一个运行事实 candidate 的补偿写入按 `(tenant_id, idempotency_key)` 幂等;不同 HTTP 尝试即使请求内容相同,也因可信发生时间不同而分别计数,避免把真实重放次数永久压成一次。
- Claim、Case、配置和对账记录使用复合租户外键。
- 退款/冲回必须引用同租户原结算事件。
- 生产事件必须通过已激活密钥验证test/mock/staging 即使签名和业务字段全部匹配,也只能生成 `projection_scope=simulation_only` 的连接器事实,绝不进入核心财务状态机。
### 接口
- `POST /api/v1/integrations/financial-events`:连接器签名事件入口;返回稳定接收/重放结果。
- `POST /api/v1/financial-connectors/admin/tenants/{tenant}/configs/{id}/activate|disable|rotate`带版本、actor、request ID 和 reason 的配置状态机。
- `POST /api/v1/financial-connectors/admin/tenants/{tenant}/configs/{id}/simulate`平台管理员运行确定性非生产场景production 配置和未激活配置 fail-closed。
- `GET /api/v1/financial-connectors/admin/tenants/{tenant}/config-events`:读取不含密钥材料的配置审计时间线。
- `GET /api/v1/financial-connectors/admin/tenants/{tenant}/observability`:平台管理员读取目标租户脱敏运行指标;从 config/event/reconciliation/operational event 聚合指定窗口真实值。
- `GET /api/v1/financial-connectors/observability`:财务角色读取当前租户脱敏运行指标;返回 `window_started_at / as_of / generated_at / source_revision`,以及 replay、认证失败、签名失败、payload conflict 的真实计数与最近发生时间。`0022` 起四类指标均标记 `available`,没有事实时真实返回零而不是“待采集”占位。
- `GET /api/v1/financial-connectors/payment-evidence/{claim}`:有单据读取权限的当前租户用户读取付款证据等级,不返回原始连接器内容。
- `GET /api/v1/financial-reconciliation/cases`:财务角色分页查看匹配与异常。
- `GET /api/v1/financial-reconciliation/cases/{id}`:查看脱敏证据和追加式时间线。
- `POST /api/v1/financial-reconciliation/cases/{id}/confirm`:独立财务确认差异或人工匹配。
- `POST /api/v1/financial-reconciliation/cases/{id}/reject`:拒绝错误回执并记录原因。
- 连接器配置管理接口仅平台管理员可用,业务确认接口仅财务角色可用,两类权限不互相继承。
### 匹配算法
1. 验证 tenant/provider/key version/timestamp/signature 和事件类型HMAC canonical request 同时绑定固定 HTTP method/path禁止共享密钥跨 provider 或 key version 重放。
2. 以 canonical JSON 生成 payload hash按外部事件 ID 与幂等键检查首次请求。
3. 通过受控引用解析 Claim不允许仅凭模糊姓名或备注自动匹配。
4. 校验 Claim 已完成审批且处于待付款;比较金额、币种、外部业务引用和事件方向。
5. 只有 `production_verified` 且完全一致时才自动 matched非生产来源只生成模拟投影任何生产差异进入 exception 且不改变 Claim。
6. matched 事件在同事务调用付款动作、记录 Business Event并把外部事件哈希作为 Savings 证据。
7. ERP posted 只表示入账不重复触发付款refund/reversal 追加负向业务与 Savings 冲回候选。
### 权限与安全
- 连接器入口不使用普通用户会话,使用租户绑定的签名认证;普通 Bearer token 不能伪装连接器。
- HMAC/签名比较使用常量时间函数,限制时间窗口并记录 nonce/外部事件 ID 防重放。
- 激活和轮换前由服务端解析 `secret_ref` 并校验至少 128-bit HMAC 密钥;数据库和审计 DTO 均不返回引用或明文。
- 日志、响应和 DTO 最多暴露外部引用后八位或不可逆摘要,不返回原始 payload、签名或密钥。
- replay 随成功重放事务提交;认证失败与 payload 冲突先回滚失败业务事务,再独立提交脱敏运行事实,审计写入异常不得覆盖原始 401/409 响应。
- 只有服务端按 tenant/provider/key version 解析出 active 配置,并成功解析该配置的服务端密钥后,才构造可归属的 operational context。缺认证头、请求 tenant 不一致、未知/未激活配置或密钥不可用均不接受客户端自报租户,只写不带租户归属的结构化警告;签名、时间窗和事件白名单失败才可安全归入已解析配置。
- 运行表只保存 `hmac-sha256:` 请求/外部事件指纹和 `sha256:` 幂等键。HMAC 输入可以包含外部 ID 和业务引用但这些原值不会进入表、DTO 或错误日志。
- 不可变连接器事实的 normalized payload 不再保存完整 `claim_reference``0020` 受控迁移会删除历史冗余值,保留内容哈希、受控 Claim ID 与必要尾号。
- 跨租户资源统一按 404 隐藏;配置管理员不能确认对账,付款申请人不能确认自己的异常。
- 连接器故障、未知密钥、签名异常、金额/币种不一致和数据库异常均 fail-closed。
### 状态转换
- 连接器事件:`received → verified → processed`,失败进入 `rejected`;事实本身追加只读。
- 连接器配置:`disabled → active → rotating → disabled`;正常启用走 `disabled → active`,轮换时旧 active 原子进入 rotating、新 key version 以 active 创建。
- 对账记录:`pending → matched | exception → confirmed | rejected`;退款可从 confirmed 进入 `reopened`,重新处置后关闭。
- Claim 仅在可信 `payment_settled + matched` 后从 `pending_payment` 进入 `paid`
- ERP 凭证从 `pending_posting` 进入 `posted | posting_failed`,不反向伪造支付成功。
### 降级策略
- 连接器离线:保留待付款,不自动标记已付;显示积压和最后成功时间。
- 回执乱序:先保存事实,等待前置事件或进入 pending不猜测状态。
- 回执冲突:保留首次事实并返回 409生成对账异常。
- ERP 未接入:付款事实可进入已付,但“已入账/凭证号”保持待采集。
- test/mock/staging返回 `simulation_only`,只保留追加式 connector fact/response projection不创建对账 Case、不修改 Claim/ERP/归档/Savings也不进入生产现金证明。
- 显式 mock adapter 只能选择预定义场景和当前租户 Claim事件 ID、correlation 和受控外部引用由 tenant/config/scenario/request ID 确定性派生。重复执行同一请求只产生稳定重放,不能借模拟接口注入生产配置或任意字段。
- 升级前若已有非生产事件且响应曾关联对账 Case`0020` 将其标记为 `legacy_nonproduction_effect_unknown` 供审计,不伪装成新策略下的无副作用模拟事实,也不在迁移中猜测性冲回历史财务状态。
### 兼容策略
- 保留现有人工“确认已付款”作为低等级内部证据;付款证据 DTO 使用 `internal_manual_payment`,生产连接器使用 `external_cash`,非生产连接器使用 `simulated_connector`/`staging_connector`。UI 必须同时展示来源标签和可信等级,不能只显示“已付款”。
- 新连接器路径复用现有幂等付款动作、Case 时间线和 Savings 实现服务,不复制第二套状态机。
- 现有 `risk_flags_json` 付款摘要继续只读兼容,新连接器事实进入正式事件表。
## 测试方案
- 单元签名、时间窗口、canonical hash、幂等重放、冲突、乱序和字段白名单。
- 权限:跨租户、普通用户伪造、管理员越权、申请人自证和密钥停用。
- PostgreSQL复合外键、唯一键、append-only、并发同事件、不同 payload 冲突和安全降级。
- 集成:申请 → 票据 → 报销 → 预审 → 审批 → 外部付款 → 对账 → ERP 入账 → 归档 → Savings 待确认。
- 反向:支付失败不推进、金额/币种错配不推进、重复回执只写一次、退款追加冲回。
- adapter逐场景验证确定性结果、重复请求、跨租户 Claim 隐藏、production 拒绝,以及 Claim/对账/ERP/Business Event/Savings 零副作用。
- 可观测性:验证租户隔离、财务/管理员权限、窗口边界、签名失败与重放计数,并断言 DTO/日志无原始 payload、签名和密钥。
- 运行事件:验证同 candidate 并发/补偿重试单赢家、不同请求尝试分别计数、冲突回滚后独立持久化、复合租户外键、HMAC 格式检查和数据库 append-only。
- 所有验证只在 `local-x-financial-linux` 容器内执行,每条命令最长 60 秒。
## 算法与公式
本能力不做概率预测,核心是确定性门禁:
```text
canonical_effect_allowed = (
verification_level == production_verified
AND signature_valid
AND tenant_provider_key_path_bound
AND claim_amount_currency_reference_match
)
```
任一条件为假都不得产生核心财务副作用;非生产环境无论其他条件是否为真,`canonical_effect_allowed` 固定为 false。
运行指标使用确定性窗口聚合,不从应用日志估算:
```text
operational_count(type, window) = COUNT(
tenant_id = current_tenant
AND event_type = type
AND window_started_at <= occurred_at <= as_of
)
operational_idempotency_key = SHA256(
source_revision, tenant, config, type, reason,
HMAC(request), HMAC(external_event), occurred_at
)
```
`source_revision=20260716_0022` 表示当前运行指标的数据源与聚合契约版本;它不是 provider 协议版本。发生时间属于本次接收尝试,因此同一 candidate 重试仍稳定,而新尝试会形成新的真实计数。
## 指标与验收
- 100% 外部结算事件具有租户、来源、签名版本、payload hash、外部 ID 和接收时间。
- 重复相同事件稳定重放,冲突 payload 100% 拒绝。
- 任何金额/币种/Claim/审批状态不一致均不会推进已付款。
- 外部支付、ERP 凭证、对账处置、归档和 Savings 证据可由 correlation 链回放。
- 连接器离线或异常时不出现虚假“已付款”“已入账”或现金节省。
- observability 响应 100% 标明窗口起止和 source revision三类运行事实按租户真实计数并提供各类最近发生时间。
## 风险与开放问题
- 首期真实 provider、签名算法、事件字段和 SLA 需要目标客户确认。
- 部分 ERP 只有批次级凭证,需要明确批次到单据的拆分和舍入规则。
- 多币种付款需要锁定汇率来源和会计期间;本功能不自行猜测汇率。
- 退款、补付、员工自担调整是否进入现金节省,仍需客户财务签字口径。
- 对账大额阈值及双人复核需按企业策略配置。
## 本轮实现记录
- 2026-07-16完成现有内部付款、申请归档、Business Event、Savings 实现链路盘点,并冻结统一连接器、安全认证、对账状态和完整 E2E 方案;实现与容器证据保留在同目录 TODO 中继续执行。
- 2026-07-16完成 `0017` 四表迁移、HMAC/密钥版本/时间窗认证、租户隔离、追加式事件、幂等冲突和对账投影;一次性 PostgreSQL 17 迁移循环与 2 项并发探针通过。
- 2026-07-16支付结算只在金额、币种、Claim、审批状态与来源全部匹配时复用正式付款动作ERP、失败、退款/冲回、Savings 失效和财务处置均进入同一 correlation 审计链,连接器服务/HTTP 7 项通过。
- 2026-07-16真实 provider、批次拆分、汇率、会计期间和大额双人复核仍由目标客户确认当前 mock/test 证据始终标记 simulated不冒充生产现金事实。
- 2026-07-16补齐 `0020` 配置版本与追加式审计迁移;新配置只能停用创建,激活前校验服务端密钥,轮换原子切换 key versionHTTP 时间线不暴露 `secret_ref`
- 2026-07-16把 test/mock/staging 六类事件收口到 `simulation_only` 只读投影生产事件继续完成付款、ERP、归档、Savings 和冲回,生产冲回也不能引用模拟原事件。
- 2026-07-16normalized payload 删除完整 `claim_reference`,历史冗余值由 `0020` 受控脱敏HMAC v2 继续以内容哈希和 tenant/provider/key version/path 证明请求边界。
- 2026-07-16容器内连接器/配置/费用价值链组合 16 项、PostgreSQL 并发 3 项、迁移静态 124 项及全新 PostgreSQL 17 完整升降级循环通过;独立 0019→0020 探针确认版本回填、历史脱敏和 legacy 不确定性标记符合契约。
- 2026-07-16新增显式非生产 adapter以 tenant/config/claim/scenario/request ID 派生稳定签名回执,覆盖成功、失败、乱序、重复、冲突、退款和 ERP 场景HTTP 与服务测试确认 simulation-only 且 Claim、对账、Business Event、ERP 与 Savings 零副作用。
- 2026-07-16新增租户级脱敏可观测性 API 与财务看板面板,现有 config/event/reconciliation 表提供最后成功、失败率、积压和对账异常真实值retry/auth_failure 在 `0022` 运行事件落地前明确显示 unavailable不伪造零值。
- 2026-07-16新增付款证据等级 DTO 和 UI 口径,通过 production-mode 签名契约的回执分类为 `external_cash`,人工确认标为低等级 `internal_manual_payment`,模拟/预发布回执明确不进入核心账;当前本地自签测试不作为真实现金或 provider 接通证据。
- 2026-07-17完成 `0022` 追加式运行事实迁移与服务接入,耐久记录 replay、可信归属后的 auth failure 和 payload conflict请求与外部事件只保存 HMAC 指纹,失败事务回滚后独立补偿提交。
- 2026-07-17可观测性改为返回 `20260716_0022` source revision、明确窗口、真实计数和最近时间同一 candidate 补偿重试幂等,不同 HTTP 尝试分别计数。迁移总头继续串到既有 `0023``0022` 不越界创建后继 AI 表。
- 2026-07-17全新一次性 PostgreSQL 17 完整迁移循环 51 项、连接器并发 4 项、后继盲审并发 7 项通过验证租户复合外键、HMAC 格式、运行事实 append-only 和并发单赢家。