216 行
12 KiB
Markdown
216 行
12 KiB
Markdown
# 集成边界冻结(P19 / P19+IM-1 / P19+ERP-3 / R10)
|
||
|
||
**快照日期**:2026-03-09
|
||
**当前基线**:`P19+IM-1`、`P19+ERP-1`、`P19+ERP-2` 与 `P19+ERP-3` 已完成;当前运行时已落地企微群机器人 + 深链 + Outbox 异步派发的一期协同适配,以及 ERP 主数据 Pull、报销付款凭证切片、采购双阶段 journal / 归档摘要出站、资产台账摘要出站。
|
||
**目标**:在保持核心域稳定的前提下,冻结 ERP / IM / AI / MCP 的长期边界,并记录 IM 一期与 ERP 三期的已实现范围、禁入规则以及 R10 之后的固定主线顺序。
|
||
|
||
## 1. 总体原则
|
||
|
||
### 1.1 只通过边界集成
|
||
- 外部系统只允许通过两种方式接入:
|
||
- 领域事件 / Outbox 异步投递
|
||
- 显式 API 适配层
|
||
- 禁止外部系统直写核心业务表。
|
||
- 禁止为了对接外部系统,在核心事务表中提前加入 ERP 私有字段、IM 私有字段或 AI 中间状态字段。
|
||
|
||
### 1.2 核心域优先
|
||
- `purchase_request`、`asset_card`、`inventory_check` 等领域模型继续由业务服务自身维护。
|
||
- 集成层只能消费既有领域事实,不能反向篡改领域判定逻辑。
|
||
- 若未来需要双向同步,必须先定义系统主责方(source of truth),再设计幂等回写接口。
|
||
|
||
### 1.3 回滚优先
|
||
- 所有集成必须支持“关闭适配器后核心域仍可独立运行”。
|
||
- 外部调用失败只能影响外围联动,不得阻断核心单据保存、审批和查询。
|
||
- 对外推送必须具备可重试、可补偿、可审计能力。
|
||
|
||
## 2. ERP / 财务适配边界
|
||
|
||
### 2.1 允许进入适配层的对象
|
||
- 主数据:`LegalEntity`、`CostCenter`、`Supplier`
|
||
- 采购:`purchase_request` 审批结果、预算占用确认结果、PO / 合同归档摘要
|
||
- 资产:`asset_card` 基础卡片信息、财务维度变更摘要、盘点完成摘要
|
||
|
||
### 2.2 推荐适配方式
|
||
- **主数据同步**:
|
||
- 由 `hyb-oa` 输出标准化读模型或事件
|
||
- ERP 适配器负责字段映射与批量 / 增量同步
|
||
- **财务凭证 / 单据接口**:
|
||
- 先生成中间格式(JSON / CSV / 显式 API payload)
|
||
- 再由独立适配器调用外部 ERP
|
||
- **失败处理**:
|
||
- 在适配层重试
|
||
- 失败记录在适配层日志 / Outbox 中,不回写核心事务状态为“失败”
|
||
|
||
### 2.3 明确禁止事项
|
||
- 禁止在 `PurchaseRequest`、`AssetCard`、`BudgetPool` 等核心表中直接加入 ERP 专有主键、分录号、凭证表字段。
|
||
- 禁止应用直接连写 ERP 主表。
|
||
- 禁止把 ERP 状态机复制到 `hyb-oa` 核心路由中。
|
||
|
||
### 2.4 建议后续专项
|
||
- `P19+ERP-1`:主数据同步协议
|
||
- `P19+ERP-2`:采购双阶段 journal 与归档摘要出站
|
||
- `P19+ERP-3`:资产台账摘要导出协议(已完成一期)
|
||
|
||
### 2.5 P19+ERP-1 已实现范围
|
||
- 已新增 `IntegrationBinding` 与 `IntegrationSyncState` 两张集成层私有表,用于维护 ERP 映射与同步状态,不向核心事务表注入 ERP 私有字段。
|
||
- 已实现 `LegalEntity`、`CostCenter`、`Supplier` 的 ERP 全量 Pull,同步方式固定为 `manual + cron`;其中 `ERP_MASTER_DATA_SYNC_CRON` 为空时不自动调度。
|
||
- 已实现 `reimbursement.paid` 的标准化凭证切片导出,运行时通过 `erp.journal.export` 写入 `IntegrationOutbox` 并由 dispatcher 异步派发。
|
||
- 已兼容保留历史 `erp.reimbursement.paid` 派发路径;成功导出后统一回写 `integration_bindings(provider=erp, entity_type=reimbursement_journal)`。
|
||
- 已明确 `ERP_SYNC_ENABLED` 与 `erp_sync` feature flag 共同构成 ERP 管理端总闸,任一关闭都必须阻断主数据同步与手动导出。
|
||
|
||
### 2.6 P19+ERP-2 已实现范围
|
||
- 已冻结采购双阶段财务语义:`purchase_request.approved` 自动生成 `purchase_request_commitment` journal,`purchase_order.archived` 首次归档自动生成 `purchase_order_accrual` journal。
|
||
- 已新增 `erp.procurement.export` 用于 `purchase_order_archive` 摘要出站;commitment / accrual 仍统一复用 `erp.journal.export`,避免额外拆分出站总线。
|
||
- 已为 `purchase_order_archive` 建立“同一条 outbox 覆盖同步”语义:当 `poNo` / `contractNo` / `archivedFiles` 变化时,仅重置 summary 对应 outbox 并覆盖 payload,不重复创建 accrual journal。
|
||
- 已在 `integration_bindings` 中落地采购映射:`purchase_request_commitment_journal`、`purchase_order_accrual_journal`、`purchase_order_po`、`purchase_order_contract`;成功派发后回写 ERP 外部编号与最近同步时间。
|
||
- 已明确 `IntegrationSyncState` 继续只表示资源级主数据同步状态,不承载采购单据级轨道;采购详情轨道只允许由 `IntegrationOutbox + IntegrationBinding + 当前单据事实` 推导。
|
||
- 已将采购 ERP 轨道挂件固定在采购详情 / 归档区:所有可读用户仅查看阶段状态,`integration.manage` 才能查看 ERP 外部编号并执行手动补发 / 重试。
|
||
|
||
### 2.7 P19+ERP-3 已实现范围
|
||
- 已新增 `erp.asset.export` 单一资产 ERP 事件,固定用于 `asset_card` 的 ledger summary export,不进入 `erp.journal.export`,也不向核心资产表注入 ERP 私有字段。
|
||
- 已冻结资产一期触发边界:仅 `POST /api/assets` 建卡成功,以及 `PATCH /api/assets/:id` 导致 `legalEntityId / costCenterId / status(retired|archived)` 发生变化时自动出站。
|
||
- 已明确 `POST /api/assets/:id/assign`、`POST /api/assets/:id/return`、`POST /api/assets/:id/transfer` 与仅 `name / location / serialNo / activatedAt` 变化不触发 ERP,同步边界仅覆盖财务台账摘要。
|
||
- 已为单资产固定 `asset_card:{assetId}:ledger_summary` dedupe key,并采用“同一条 outbox 覆盖同步”语义:payload 无变化时返回历史记录,payload 有变化或失败 / 死信时仅重置同一条记录。
|
||
- 已在 `integration_bindings` 中固定资产映射 `asset_erp_card`;成功派发后回写 ERP 资产外部编号与最近同步时间。
|
||
- 已将资产 ERP 轨道挂件固定在资产详情侧边栏:所有可读用户查看同步状态,`integration.manage` 才能查看 ERP 外部编号并执行补发 / 重试;`IntegrationSyncState` 继续不承载资产单据级轨道。
|
||
|
||
## 3. IM / 协同适配边界
|
||
|
||
### 3.1 一期已实现能力(P19+IM-1)
|
||
- 已复用 `IntegrationOutbox` 与派发作业,实现 `notification.im` 异步派发。
|
||
- 已新增 `NotificationChannel` 的创建 / 更新 / 列表 / 测试接口与后台页面。
|
||
- 已接入企微群机器人两种模式:
|
||
- `mock`
|
||
- `wecom_webhook`
|
||
- 已支持三维路由过滤:
|
||
- `roleCodes`
|
||
- `domainScopes`
|
||
- `allowedTypes`
|
||
- 已支持 `APP_ORIGIN + targetPath` 生成深链;缺少 `APP_ORIGIN` 时允许发送但不阻断业务。
|
||
- 站内通知、邮件、IM 三通道并存;业务事务内只负责写通知与 Outbox,真正派发在作业中完成。
|
||
|
||
### 3.2 一期明确覆盖范围
|
||
- 待办类:`workflow.task_assigned`
|
||
- 报销结果:`reimbursement.approved / rejected / returned / paid`
|
||
- 请假结果:`leave.approved / rejected`
|
||
- 采购结果:`purchase_request.approved / rejected`
|
||
- 资产流转:`asset.assigned / returned / transferred`
|
||
- 盘点结果:`inventory_check.completed`
|
||
|
||
### 3.3 一期明确不做
|
||
- 飞书、钉钉真实适配器
|
||
- 员工 IM OpenID / UserID / UnionID 主数据
|
||
- 点对点个人消息
|
||
- IM 卡片回调审批
|
||
- 新的 Outbox 表或消息总线
|
||
- 默认全员广播频道
|
||
|
||
### 3.4 运行时回滚策略
|
||
- 设置 `IM_NOTIFIER_ENABLED=false`
|
||
- 在管理页中禁用全部通知渠道
|
||
- 保留 `integration_outbox` 历史记录,不回删
|
||
- 即使 IM 全部关闭,站内通知与邮件仍继续工作
|
||
|
||
### 3.5 后续专项建议
|
||
- `P19+IM-2`:飞书 / 钉钉适配器
|
||
- `P19+IM-3`:个人直达与 IM 身份映射
|
||
- `P19+IM-4`:消息卡片交互与回调审批(仍必须回到 OA 鉴权)
|
||
|
||
## 4. AI 增强边界
|
||
|
||
### 4.1 允许能力
|
||
- 审批摘要生成
|
||
- 采购 / 资产异常提示
|
||
- 主数据重名与重复建议
|
||
- 文档 / 制度 / 流程问答检索
|
||
|
||
### 4.2 强制约束
|
||
- AI 只做建议,不直接写库。
|
||
- AI 输出必须允许人工复核和拒绝。
|
||
- 任何模型调用都不得绕过现有权限校验。
|
||
- 若未来接入外部大模型,必须先明确脱敏策略与日志留存边界。
|
||
|
||
### 4.3 禁止事项
|
||
- 禁止 AI 自动创建、审批、归档业务单据。
|
||
- 禁止 AI 直接修改预算、工作流、资产归属等核心状态。
|
||
|
||
## 5. 事件与通知交付规范
|
||
|
||
### 5.1 事件最小结构
|
||
后续若继续扩展领域事件 / Outbox,建议统一包含:
|
||
- `eventName`
|
||
- `eventId`
|
||
- `occurredAt`
|
||
- `actorId`
|
||
- `entityType`
|
||
- `entityId`
|
||
- `payloadVersion`
|
||
- `payload`
|
||
|
||
### 5.2 幂等要求
|
||
- 同一 `eventId` 必须可安全重放。
|
||
- 消费端必须以 `eventId` 或 `entityId + status / version` 方式做幂等。
|
||
- 不允许消费端以“收到多次事件”为理由修改核心业务状态。
|
||
|
||
### 5.3 当前 IM 一期实现说明
|
||
- 运行时仍以通知类型驱动 IM 入队,而不是直接暴露新的领域事件名。
|
||
- `notification.im` 的 `dedupeKey` 固定为:
|
||
- `${notificationType}:${targetType}:${targetId || targetPath}:${channelId}`
|
||
- IM 失败仅影响 Outbox 状态,不回滚业务事务。
|
||
|
||
## 6. MCP 基线
|
||
|
||
### 6.1 当前结论
|
||
- `P19+IM-1` 阶段 **不启用 MCP**。
|
||
- 当前仓库中 **仍不创建** `docs/mcp-tools.md`,因为尚未进入真实 MCP 使用场景。
|
||
|
||
### 6.2 首次启用前置条件
|
||
若未来需要启用 MCP,固定顺序如下:
|
||
1. 明确真实用途(数据库只读排障、GitHub PR / Issue / CI 协作等)
|
||
2. 新增 `docs/mcp-tools.md`
|
||
3. 使用 `mcp-tools-catalog` 生成工具目录
|
||
4. 在执行合同中记录启用原因、风险与禁用边界
|
||
|
||
### 6.3 允许的 MCP 范围
|
||
- `postgres MCP`:只读排障、迁移核对、账本核对
|
||
- `github MCP`:PR / Issue / CI 协作
|
||
|
||
### 6.4 禁止事项
|
||
- 禁止在没有 `docs/mcp-tools.md` 的前提下默认启用 MCP。
|
||
- 禁止用 MCP 绕过仓库内已存在的本地验证命令。
|
||
- 禁止将 MCP 用作写生产数据的通道。
|
||
|
||
## 7. 当前阶段明确不做
|
||
- 不新增新的集成总线表结构
|
||
- 不接入 ERP 真实写回逻辑
|
||
- 不接入飞书 / 钉钉真实生产推送
|
||
- 不新增 AI 写库动作
|
||
- 不引入绕过工作流与权限体系的外部回调路径
|
||
|
||
## 8. R10 后续路线冻结
|
||
|
||
### 8.1 固定主线顺序
|
||
- `R10` 之后的固定主线顺序为:`P19+MCP-1 -> P19+AI-1 -> P20+TRAVEL-1 -> P20+TRAVEL-2 -> P20+TRAVEL-3 -> P21+PWA-1 -> P21+PWA-2`。
|
||
- 后续阶段继续遵循“先治理,再工具,再建议,再业务,再移动”的总顺序,不并行开启两个重业务 phase。
|
||
- 每个 phase 固定遵循:`执行合同 CSV -> 方案批准 -> 开发 -> 测试 -> 文档矩阵收口 -> 合并 main`。
|
||
|
||
### 8.2 MCP / AI 前置关系
|
||
- `P19+MCP-1` 是首次真实启用 MCP 的唯一前置 phase;在其完成前,`docs/mcp-tools.md` 仍不得作为已存在事实源引用。
|
||
- `P19+AI-1` 固定在 `P19+MCP-1` 之后启动,继续遵守“AI 只做建议,不直接写库”的硬边界。
|
||
- AI 一期只覆盖采购、报销、资产详情的只读建议工作台,不开放自由聊天、自动审批或 agent 自治。
|
||
|
||
### 8.3 差旅统付主线
|
||
- `P20+TRAVEL-1` 固定负责差旅申请、行程段与 `travel_orders` 入站整合,作为对公统付的前置主数据与流程基线。
|
||
- `P20+TRAVEL-2` 固定采用企业卡 / 虚拟卡授权与交易导入路线,优先复用 `docs/adr/adr-enterprise-card-control.md` 的既有结论。
|
||
- `P20+TRAVEL-3` 固定负责核销闭环与 ERP / AP 摘要桥接;个人垫资报销继续与对公统付并存,不互相替代。
|
||
|
||
### 8.4 PWA 兑现顺序
|
||
- `P21+PWA-1` 固定先做移动资产扫码与盘点增强,优先兑现一线资产作业的生产价值。
|
||
- `P21+PWA-2` 固定后做离线动作队列与企微深链增强,继续复用现有 `APP_ORIGIN + targetPath` 深链规范。
|
||
- PWA 路线继续限定在浏览器 / PWA 栈内,不引入原生 App、小程序或双栈移动壳。
|
||
|
||
### 8.5 后置 backlog
|
||
- `P19+IM-2 / IM-3 / IM-4`、`P22+VEH-1`、`P22+ASSET-FIN-1` 明确列为后置 backlog,本轮不进入主线。
|
||
- 这些方向只保留“触发条件 / 进入时机”的规划地位,不提前写入已完成矩阵或事实源校验器。
|
||
- 若后续优先级发生变化,必须通过新的路线合同显式改序,不直接口头跳 phase。
|