文件
hyb-oa/docs/integration-boundaries.md
T

16 KiB
原始文件 Blame 文件历史

集成边界冻结(P19 / P19+IM-1 / P19+ERP-3 / R10 / P19+MCP-1 / P19+AI-1 / P20+TRAVEL-1)

快照日期:2026-03-10 当前基线:P19+IM-1、P19+ERP-1、P19+ERP-2、P19+ERP-3、P19+MCP-1、P19+AI-1 与 P20+TRAVEL-1 已完成;当前运行时已落地企微群机器人 + 深链 + Outbox 异步派发的一期协同适配,以及 ERP 主数据 Pull、报销付款凭证切片、采购双阶段 journal / 归档摘要出站、资产台账摘要出站、Postgres MCP 只读工具基线、报销 / 采购 / 资产详情页 AI 只读建议挂件,以及差旅申请主单 / 行程段 / 审批预算锁定 / travel_orders 关联入站的一期差旅基线。 目标:在保持核心域稳定的前提下,冻结 ERP / IM / AI / MCP / TRAVEL 的长期边界,并记录 IM 一期、ERP 三期、AI 一期与差旅一期的已实现范围、禁入规则以及 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 直接修改预算、工作流、资产归属等核心状态。

4.4 P19+AI-1 已实现范围

  • 已新增 GET /api/ai/status 与三条详情建议接口:/api/ai/suggestions/reimbursements/:id、/api/ai/suggestions/purchase-requests/:id、/api/ai/suggestions/assets/:id。
  • 已新增 ai.assist 权限、ai_assist feature flag 与 AI_ASSIST_ENABLED / AI_PROVIDER / AI_BASE_URL / AI_MODEL / AI_TIMEOUT_MS / AI_AUTH_TOKEN 环境变量;默认仍保持关闭。
  • 已固定 AI 运行时只支持同步只读建议层,不新增 Prisma 表、不使用 Outbox、不接入 MCP 运行时,也不持久化 AI 历史结果。
  • 已固定只读白名单快照:报销不暴露发票号码、付款凭证、姓名工号与明细原文;采购不暴露申请人个人信息、附件原名、长文本 reason 与外部 ERP 编号;资产不暴露 assignee 身份信息与外部 ERP 编号。
  • 已在报销详情、采购详情、资产详情挂载 AI 建议卡片;当权限不足、总闸关闭、feature flag 未命中、上游超时或响应非法时,仅在卡片内降级展示,不影响主体页面渲染与业务动作。
  • 已固定审计动作 AI_SUGGESTION_REQUESTED,仅记录 targetType / targetId / provider / model / promptHash / tokenUsage / featureFlag,不记录原始 prompt、脱敏前 payload 或上游全文。

5. 差旅一期边界

5.1 P20+TRAVEL-1 已实现范围

  • 已新增 TravelRequest、TravelRequestSegment 与 travel_orders.travel_request_id,形成“差旅申请主单 + 行程段明细 + 外部订单事实关联”的一期差旅模型。
  • 已固定独立 travel.* 权限命名空间,并将 travel_request 纳入工作流实体映射、待办页、移动审批与通知深链 /travel-requests?id=<id>。
  • 已固定差旅一期持久状态仅 draft / reviewing / approved / rejected;return 与 withdraw 均回到 draft,释放预算并允许修改后重提。
  • 已复用预算三段语义:提交 reserve、审批通过 confirm、驳回 / 退回 / 撤回 release;预算池由 legal_entity_id + cost_center_id + start_date 自动解析。
  • 已固定一期工作流为直属经理单层审批,并把审批通过 / 驳回结果分别映射到 travel_request.approved、travel_request.rejected 通知类型。

5.2 差旅一期明确不做

  • 不创建 travel_request_commitment journal,不写 IntegrationOutbox,不提前进入 erp.travel.export。
  • 不接真实票务 / 酒店 / 商旅供应商 API,不做自动出票、改签、退票。
  • 不做企业卡授权、交易导入、对公支付与清结算,这些能力继续固定在 P20+TRAVEL-2 / P20+TRAVEL-3。
  • travel_order.imported 当前仍只是内部集成事实与入站表更新,不提升为稳定公共事件名。

6. 事件与通知交付规范

6.1 事件最小结构

后续若继续扩展领域事件 / Outbox,建议统一包含:

  • eventName
  • eventId
  • occurredAt
  • actorId
  • entityType
  • entityId
  • payloadVersion
  • payload

6.2 幂等要求

  • 同一 eventId 必须可安全重放。
  • 消费端必须以 eventId 或 entityId + status / version 方式做幂等。
  • 不允许消费端以“收到多次事件”为理由修改核心业务状态。

6.3 当前 IM 一期实现说明

  • 运行时仍以通知类型驱动 IM 入队,而不是直接暴露新的领域事件名。
  • notification.im 的 dedupeKey 固定为:
    • ${notificationType}:${targetType}:${targetId || targetPath}:${channelId}
  • IM 失败仅影响 Outbox 状态,不回滚业务事务。

7. MCP 基线

7.1 P19+MCP-1 已实现范围

  • 已新增 docs/mcp-tools.md,作为项目级 MCP 工具目录与使用边界事实源。
  • 已新增 .mcp.json.example,仅提供 postgres 只读示例配置,不提交任何真实密钥、PAT 或数据库连接串。
  • 已新增 scripts/validate-mcp-tools.py,用于校验工具目录、示例配置与 AGENTS.md 引用关系。
  • 已明确当前 shell 中 codex mcp list --json 不可作为唯一事实源,因此工具目录固定以官方 package 文档、执行合同与仓库校验脚本共同收口。

7.2 当前允许的 MCP 范围

  • postgres MCP:当前唯一允许启用的 MCP server,用于只读排障、迁移核对、账本核对。
  • postgres:query:固定用于只读 SQL 查询;所有查询必须处于 READ ONLY 事务语义下。
  • schema resources:允许读取表结构、字段类型与 schema 元数据,不得反向修改业务数据。

7.3 Deferred candidate

  • github MCP:当前仅记录为 deferred candidate,不纳入 enabled servers。
  • 原因:官方 GitHub MCP server 当前暴露读写混合工具集,不满足 Read-only Tools Baseline。
  • 若未来需要启用,必须通过新的路线合同显式解锁,并单独治理最小权限 PAT、读写边界与回滚策略。

7.4 禁止事项

  • 禁止提交真实 .mcp.json、真实数据库连接串、PAT、API Token 或其他密钥。
  • 禁止在没有 docs/mcp-tools.md 的前提下默认启用 MCP。
  • 禁止用 MCP 绕过仓库内已存在的本地验证命令。
  • 禁止将 MCP 用作写生产数据或修改业务状态的通道。

8. 当前阶段明确不做

  • 不新增新的集成总线表结构
  • 不接入 ERP 真实写回逻辑
  • 不接入飞书 / 钉钉真实生产推送
  • 不新增 AI 写库动作
  • 不引入绕过工作流与权限体系的外部回调路径

9. R10 后续路线冻结

9.1 固定主线顺序

  • P20+TRAVEL-1 已完成后,当前固定后续主线顺序为:P20+TRAVEL-2 -> P20+TRAVEL-3 -> P21+PWA-1 -> P21+PWA-2。
  • 历史主线顺序仍保持: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。

9.2 MCP / AI 前置关系

  • P19+MCP-1 已完成,并已把 docs/mcp-tools.md、.mcp.json.example 与 MCP 校验脚本固化为仓库治理基线。
  • 当前唯一允许启用的 MCP server 为 postgres;github 继续保持 deferred,不进入 enabled servers。
  • P19+AI-1 已在 P19+MCP-1 之后完成落地,并继续遵守“AI 只做建议,不直接写库”的硬边界。
  • 当前 AI 一期已覆盖采购、报销、资产详情的只读建议工作台;自由聊天、自动审批与 agent 自治仍明确不做。

9.3 差旅统付主线

  • P20+TRAVEL-1 已完成差旅申请、行程段、审批预算与 travel_orders 入站整合,作为对公统付的前置流程基线。
  • P20+TRAVEL-2 固定采用企业卡 / 虚拟卡授权与交易导入路线,优先复用 docs/adr/adr-enterprise-card-control.md 的既有结论。
  • P20+TRAVEL-3 固定负责核销闭环与 ERP / AP 摘要桥接;个人垫资报销继续与对公统付并存,不互相替代。

9.4 PWA 兑现顺序

  • P21+PWA-1 固定先做移动资产扫码与盘点增强,优先兑现一线资产作业的生产价值。
  • P21+PWA-2 固定后做离线动作队列与企微深链增强,继续复用现有 APP_ORIGIN + targetPath 深链规范。
  • PWA 路线继续限定在浏览器 / PWA 栈内,不引入原生 App、小程序或双栈移动壳。

9.5 后置 backlog

  • P19+IM-2 / IM-3 / IM-4、P22+VEH-1、P22+ASSET-FIN-1 明确列为后置 backlog,本轮不进入主线。
  • 这些方向只保留“触发条件 / 进入时机”的规划地位,不提前写入已完成矩阵或事实源校验器。
  • 若后续优先级发生变化,必须通过新的路线合同显式改序,不直接口头跳 phase。