WHMSLIVE 部署验证企微HR主数据镜像
这个提交包含在:
@@ -16,7 +16,7 @@ Read only what is relevant:
|
||||
- For UI/page work, PC/mobile/WeCom experience, approval UX, or domestic OA benchmarking, read `docs/产品设计规则.md` and `references/visual-qa.md`. DG8 makes Feishu workbench/approval the single main UI/layout reference, with Hyinda branding and project rules taking priority. DG9 adds the A/B/C page layering and shared workbench/mobile samples; choose the DG9 sample before designing or coding a page. Other products are only function/process/control references. Mobile page work must treat `docs/产品设计规则.md` as the source of truth for the unified mobile shell, icon grid, card lists, deep Push pages, sticky actions, safe-area, and cross-viewport matrix. 移动页必须先对齐该设计事实源,再进入实现或验证。
|
||||
- For approval workflow, roles, self-approval, notification, deeplink, reminder, or escalation work, read `docs/需求-统一审批中心规约.md`.
|
||||
- For HR lifecycle, employee onboarding/offboarding, Enterprise WeChat directory sync, or account disablement work, read `docs/需求-企业微信基础设施规约.md`, `docs/管理员手册.md`, and the latest HCLT/HRWD Issue CSV evidence first.
|
||||
- For Enterprise WeChat-first HR/attendance runtime migration, read `docs/企微优先开发路线图.md` before planning or coding. WDRG makes the roadmap authoritative for stage order; WCPC has rerun the capability POC with an existing active test account and reached `GO_TO_HR_MASTER_SYNC`; WHMS has locally implemented `wecom_hr_master_sync_v1` but it is not deployed and production batch apply is not approved. Do not start `wecom_attendance_approval_mirror_v1`, `oa_hr_emergency_mode_v1`, `wecom_recovery_writeback_v1`, or `wecom_ruleops_v1` until WHMS is deployed/verified and the next stage has its own Issue CSV.
|
||||
- For Enterprise WeChat-first HR/attendance runtime migration, read `docs/企微优先开发路线图.md` before planning or coding. WDRG makes the roadmap authoritative for stage order; WCPC has rerun the capability POC with an existing active test account and reached `GO_TO_HR_MASTER_SYNC`; WHMS/WHMSLIVE has implemented, deployed, and publicly verified `wecom_hr_master_sync_v1`, with the production flag restored to `force_off` and production real-employee batch apply not approved. Do not start `wecom_attendance_approval_mirror_v1`, `oa_hr_emergency_mode_v1`, `wecom_recovery_writeback_v1`, or `wecom_ruleops_v1` without the next stage's own Issue CSV.
|
||||
- For reimbursement, invoice, OCR, duplicate invoice, or attachment work, read `docs/报销发票附件规则.md` and `references/reimbursement.md`.
|
||||
- For local/WeCom/public trial-run, OCR runtime, Caddy, or DB drift work, read `docs/试运行与自动化验证手册.md` and `references/trialrun.md`.
|
||||
- For how this skill should evolve, read `docs/Agent开发交付实践.md`.
|
||||
@@ -105,7 +105,7 @@ Final responses should include:
|
||||
- R6 scope defaults to reimbursement, leave, procurement, approval, Enterprise WeChat entry/notification, finance payment/export.
|
||||
- Do not expand to budget, ERP, AI, full travel, or complex BPM during R6; record those as follow-up Issues.
|
||||
- Enterprise WeChat personal app message is the formal approval notification channel after R5; mock and group bots are not acceptance evidence for R6 business notification.
|
||||
- After WHMS, ERP is not a future OA integration target. HR/attendance employee daily approvals (leave, missed punch, outing, overtime) should reuse mature Enterprise WeChat capabilities first, while OA provides domain-based mirror, manual takeover, recovery writeback, finance closeout, and audit. Reimbursement, payment batches, AP, accounting handoff, procurement, expenses, contracts, projects, sensitive attachments, invoices, bank receipts, and accounting handoff materials remain OA-primary unless a later Issue changes that domain explicitly. OA-primary approvals may send Enterprise WeChat personal-app notifications, but messages must contain only dehydrated title/type/no/status/deeplink; do not upload procurement forms, contract bodies, quotes, supplier files, invoices, bank receipts, or accounting materials to WeCom native approvals or WeCom attachments. Before runtime migration, read `docs/企微优先开发路线图.md`, run or check `WECOM-CAPABILITY-POC-V1`/WCPC, and classify each capability as `CAN_REUSE_NOW`, `NEEDS_CONFIG`, `NEEDS_API_POC`, `KEEP_OA_PRIMARY`, or `NOT_SUPPORTED_BY_API`; missing Secret, callback, template, trusted IP, visible scope, or API permission must be recorded as `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`, not PASS. Current WCPC status: existing active test account `SMOKE002/测试员工` (reported only as `oa_smoke***`) reran successfully with report `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json`, `status=PASS`, `conclusion=GO_TO_HR_MASTER_SYNC`, and `blockingCapabilities=[]`. Current WHMS status: `wecom_hr_master_sync_v1` is locally implemented with feature flag default `force_off`, HR/contact read service, dry-run/apply, sync run/item records, People management card, and QA-only runner `scripts/qa/check-wecom-hr-master-sync.mjs`; it is not deployed and production real-employee batch apply is not approved. WHMS rules: missing OA-required fields are skipped as `missing_required_field`, inactive WeCom status becomes `needs_offboarding_confirmation`, and OA accounts are not auto-disabled. Approval template ID, approval `sp_no`, callback config, attendance/approval mirror, emergency mode, recovery writeback, RuleOps, and HR write APIs remain later-stage gaps. Do not skip stage order: `WECOM-CAPABILITY-POC-V1`/WCPC -> `wecom_hr_master_sync_v1` deployment/verification -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`. UI and API work must distinguish `OA 主办`, `企微镜像`, and `OA 应急接管`. OA-driven Enterprise WeChat directory create/update/disable is live verified; for later HR/WeCom directory issues, first check configuration, permission, department, and data-specific causes before treating the capability as unfinished. After WCFB, Enterprise WeChat check-in sync uses an authorized custom app Secret: `WECOM_CHECKIN_SECRET` is an explicit override for a dedicated check-in app, and when it is empty OA can reuse the authorized workbench app `WECOM_AGENT_SECRET`.
|
||||
- After WHMSLIVE, ERP is not a future OA integration target. HR/attendance employee daily approvals (leave, missed punch, outing, overtime) should reuse mature Enterprise WeChat capabilities first, while OA provides domain-based mirror, manual takeover, recovery writeback, finance closeout, and audit. Reimbursement, payment batches, AP, accounting handoff, procurement, expenses, contracts, projects, sensitive attachments, invoices, bank receipts, and accounting handoff materials remain OA-primary unless a later Issue changes that domain explicitly. OA-primary approvals may send Enterprise WeChat personal-app notifications, but messages must contain only dehydrated title/type/no/status/deeplink; do not upload procurement forms, contract bodies, quotes, supplier files, invoices, bank receipts, or accounting materials to WeCom native approvals or WeCom attachments. Before runtime migration, read `docs/企微优先开发路线图.md`, run or check `WECOM-CAPABILITY-POC-V1`/WCPC, and classify each capability as `CAN_REUSE_NOW`, `NEEDS_CONFIG`, `NEEDS_API_POC`, `KEEP_OA_PRIMARY`, or `NOT_SUPPORTED_BY_API`; missing Secret, callback, template, trusted IP, visible scope, or API permission must be recorded as `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`, not PASS. Current WCPC status: existing active test account `SMOKE002/测试员工` (reported only as `oa_smoke***`) reran successfully with report `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json`, `status=PASS`, `conclusion=GO_TO_HR_MASTER_SYNC`, and `blockingCapabilities=[]`. Current WHMSLIVE status: `wecom_hr_master_sync_v1` is implemented and deployed with feature flag default/final `force_off`, HR/contact read service, dry-run/apply, sync run/item records, People management card, and QA-only runner `scripts/qa/check-wecom-hr-master-sync.mjs`; public verification applied migration `20260518184319_wecom_hr_master_sync_v1`, temporarily forced the flag on, ran dry-run and explicit apply for `SMOKE002` (`oa_smoke***`), verified ordinary employee API denial with 403, then restored `force_off`. The SMOKE002 apply did not write OA master data because WeCom lacks phone/email/department and was correctly skipped as `missing_required_field`; production real-employee batch apply is not approved. WHMS rules: missing OA-required fields are skipped as `missing_required_field`, inactive WeCom status becomes `needs_offboarding_confirmation`, and OA accounts are not auto-disabled. Approval template ID, approval `sp_no`, callback config, attendance/approval mirror, emergency mode, recovery writeback, RuleOps, and HR write APIs remain later-stage gaps. Do not skip stage order: `WECOM-CAPABILITY-POC-V1`/WCPC -> `wecom_hr_master_sync_v1`/WHMSLIVE -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`. UI and API work must distinguish `OA 主办`, `企微镜像`, and `OA 应急接管`. OA-driven Enterprise WeChat directory create/update/disable is live verified; for later HR/WeCom directory issues, first check configuration, permission, department, and data-specific causes before treating the capability as unfinished. After WCFB, Enterprise WeChat check-in sync uses an authorized custom app Secret: `WECOM_CHECKIN_SECRET` is an explicit override for a dedicated check-in app, and when it is empty OA can reuse the authorized workbench app `WECOM_AGENT_SECRET`.
|
||||
- Approval-chain correctness can be proven by PC or automation, while Enterprise WeChat validates entry, binding,免登录, notification, deeplink, and mobile layout.
|
||||
- If real-device mobile validation is paused after automation passes, record the gate as `PAUSED`; do not close RS6/UI6/R6 mobile blockers until representative real-device confirmation is recorded.
|
||||
- Role-specific pages should use one shared OA/mobile framework and tailor summaries, entries, actions, and sensitive fields by role. Do not create unrelated UI systems for employee, approver, finance, admin, or CEO views.
|
||||
|
||||
@@ -72,6 +72,9 @@ WECOM_CHECKIN_SECRET=
|
||||
WECOM_CONTACT_SYNC_ENABLED=false
|
||||
WECOM_CONTACT_SECRET=
|
||||
WECOM_CONTACT_DEFAULT_DEPARTMENT_ID=
|
||||
WECOM_HR_MASTER_SYNC_ENABLED=false
|
||||
# 企业微信 HR 主数据镜像 Secret:人事助手专用 Secret 优先;留空时仅可复用已验证授权应用的 WECOM_AGENT_SECRET
|
||||
WECOM_HR_ASSISTANT_SECRET=
|
||||
IM_NOTIFIER_ENABLED=true
|
||||
|
||||
# ===== 数据库(Compose 内部连接) =====
|
||||
|
||||
+2
-2
@@ -46,7 +46,7 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开
|
||||
- 2026-05-18 WDRG 已完成“企微优先后续开发路线图”门禁:新增 `docs/企微优先开发路线图.md`,固定“路线图门禁 + 单功能 Issue CSV”的工程节奏。后续顺序为 `WECOM-CAPABILITY-POC-V1` -> `wecom_hr_master_sync_v1` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`;阶段未退出前禁止跳阶段。本轮只更新路线图、交付规约、事实源、手册、项目 skill 和 Issue CSV,不改业务代码、不部署、不调用公网写接口。
|
||||
- 2026-05-18 WCP1 已完成企业微信能力 POC:新增 QA-only 只读 runner `scripts/qa/check-wecom-capability-poc.mjs`,本地不开启 live read 时可解释为 `PAUSE_FOR_API_POC`,本地开启 live read 但无真实 env 时可解释为 `PAUSE_FOR_CONFIG`;部署服务器容器内 live 只读探测报告为远端 `/tmp/wecom-capability-poc-wcp1/summary.json`,历史结论为 `PAUSE_FOR_CONFIG`。该报告继续作为初始配置缺口证据保留,当前 HR 主数据镜像准入以 WCPC 复跑结论为准。
|
||||
- 2026-05-18 WCPC 已完成 WCP1 配置收口复跑:先完成未补配置前远端基线复跑,报告目录 `/tmp/wecom-capability-poc-wcpc-baseline`,结论为 `PAUSE_FOR_CONFIG`;随后按用户要求自动查找并使用既有在职低风险测试号 `SMOKE002/测试员工`(报告只记录 `oa_smoke***`)复跑,只读报告 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json` 返回 `PASS / GO_TO_HR_MASTER_SYNC`,`nextStageAllowed=true`,`blockingCapabilities=[]`,状态计数为 `CAN_REUSE_NOW=15`、`NEEDS_CONFIG=3`、`NEEDS_API_POC=1`、`KEEP_OA_PRIMARY=1`。本轮不部署、不改业务代码、不持久写服务器 `.env`;下一步允许规划 `wecom_hr_master_sync_v1`,审批模板/实例、回调配置和 HR 写接口仍留后续合同。
|
||||
- 2026-05-18 WHMS 已完成企微 HR 主数据镜像本地实现:新增 `wecom_hr_master_sync_v1` 默认 `force_off`,实现企业微信通讯录/人事助手读取、dry-run/apply、同步批次/逐员工记录、管理员 API、People 管理卡片和 QA-only runner;缺字段跳过、不在职只标记 `needs_offboarding_confirmation`,不自动禁用 OA 账号。本轮未部署公网,未执行生产真实员工批量 apply,不代表考勤/审批镜像、应急接管、恢复回写或 RuleOps 已完成。
|
||||
- 2026-05-18 WHMS 已完成企微 HR 主数据镜像本地实现、部署和受控公网验证:新增 `wecom_hr_master_sync_v1` 默认 `force_off`,实现企业微信通讯录/人事助手读取、dry-run/apply、同步批次/逐员工记录、管理员 API、People 管理卡片和 QA-only runner。WHMSLIVE 部署到 `https://oa.hyinda.com` 并应用 migration `20260518184319_wecom_hr_master_sync_v1`;公网临时 `force_on` 后对 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)执行 dry-run 和显式 userids apply,企微读取链路通过,因企微侧缺手机号、邮箱和部门按 `missing_required_field` 跳过,未写 OA 主数据;普通员工访问同步 API 返回 403;最终 `wecom_hr_master_sync_v1=force_off`。未执行生产真实员工批量 apply,不代表考勤/审批镜像、应急接管、恢复回写或 RuleOps 已完成。
|
||||
|
||||
## 关键证据索引
|
||||
|
||||
@@ -135,7 +135,7 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开
|
||||
| WDRG 企微优先开发路线图门禁 | 通过,无运行时变更 | Issue `issues/2026-05-18_12-44-10-wecom-development-roadmap-gate.csv`;新增 `docs/企微优先开发路线图.md`,并回写交付规约、产品口径、PRD、管理员手册、员工快速上手、文档索引、事实源矩阵和项目 skill。结论 `DONE_ROADMAP_READY`;其下一步 `WECOM-CAPABILITY-POC-V1` 已由 WCP1/WCPC 执行并收口,不代表运行时迁移已完成。 |
|
||||
| WCP1 企业微信能力 POC | 完成只读 POC,历史结论 `PAUSE_FOR_CONFIG` | Issue `issues/2026-05-18_13-30-07-wecom-capability-poc-v1.csv`;新增 `scripts/qa/check-wecom-capability-poc.mjs`。本地脚本门禁通过,远端容器内 live 只读报告为 `/tmp/wecom-capability-poc-wcp1/summary.json`:`CAN_REUSE_NOW=9`、`NEEDS_CONFIG=8`、`NEEDS_API_POC=1`、`KEEP_OA_PRIMARY=1`。阻断为 `contact.member_read=wecom_errcode_48009`、`hr.staff_read=wecom_errcode_60021`、打卡同步未开启、缺审批模板/实例、假期权限 `wecom_errcode_301062` 和回调配置;该历史阻断已由 WCPC 复跑收口。 |
|
||||
| WCPC 企业微信能力 POC 配置收口 | 通过,结论 `GO_TO_HR_MASTER_SYNC` | Issue `issues/2026-05-18_15-01-23-wecom-capability-poc-config-closeout-v1.csv`;未补配置前远端基线复跑报告 `/tmp/wecom-capability-poc-wcpc-baseline` 为 `PASS / PAUSE_FOR_CONFIG`;随后使用既有在职测试号 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)完成只读复跑,报告 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json`,`nextStageAllowed=true`,`blockingCapabilities=[]`,`CAN_REUSE_NOW=15`、`NEEDS_CONFIG=3`、`NEEDS_API_POC=1`、`KEEP_OA_PRIMARY=1`。该准入已由 WHMS 承接;审批模板/实例、回调配置和 HR 写接口仍留后续合同。 |
|
||||
| WHMS 企微 HR 主数据镜像 | 本地已实现,待部署验证 | Issue `issues/2026-05-18_18-43-19-wecom-hr-master-sync-v1.csv`;新增 `wecom_hr_master_sync_v1`、同步批次/逐员工记录、企微通讯录/人事助手读取服务、管理员 API、People 管理卡片和 `scripts/qa/check-wecom-hr-master-sync.mjs`。默认 `force_off`,未部署公网,未执行生产真实员工批量 apply;考勤/审批镜像、审批回调、应急接管、恢复回写和 RuleOps 仍未完成。 |
|
||||
| WHMS 企微 HR 主数据镜像 | 已部署并完成受控公网验证 | Issue `issues/2026-05-18_18-43-19-wecom-hr-master-sync-v1.csv`、`issues/2026-05-18_19-28-25-whms-deploy-live-verify-v1.csv`;已部署 `wecom_hr_master_sync_v1`、同步批次/逐员工记录、企微通讯录/人事助手读取服务、管理员 API、People 管理卡片和 `scripts/qa/check-wecom-hr-master-sync.mjs`。公网 dry-run/apply 对 `SMOKE002` 返回 `missing_required_field` skip,未写 OA 主数据;权限负例 403;最终 `force_off`,未执行生产真实员工批量 apply。 |
|
||||
|
||||
## R7EP / OPS8 / QAF8 / UX8 / P2T 预检推进
|
||||
|
||||
|
||||
+3
-2
@@ -20,7 +20,7 @@
|
||||
- 企业微信打卡用于原始采集,保留其定位、人脸、Wi-Fi、规则与设备能力。
|
||||
- OA 后续同步企业微信打卡规则、排班、记录、日报、月报和 HR/考勤审批镜像,形成正式考勤口径。
|
||||
- 请假、补卡、外出、加班等考勤修正正常在企业微信完成;OA 只在应急模式下接管,并在企微恢复后 dry-run 和自动回写。
|
||||
- `wecom_hr_master_sync_v1` 已本地实现但尚未部署公网;后续考勤/审批镜像、应急接管、恢复回写或 RuleOps 仍必须另建 `wecom_attendance_approval_mirror_v1`(承接旧口径 `wecom_native_approval_mirror_v1`)、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1` 或 `wecom_ruleops_v1` 合同。
|
||||
- `wecom_hr_master_sync_v1` 已本地实现并部署公网完成受控验证;最终保持 `force_off`,后续考勤/审批镜像、应急接管、恢复回写或 RuleOps 仍必须另建 `wecom_attendance_approval_mirror_v1`(承接旧口径 `wecom_native_approval_mirror_v1`)、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1` 或 `wecom_ruleops_v1` 合同。
|
||||
|
||||
### P0-3 按域镜像定义
|
||||
- 企微主办域镜像到 OA:通讯录/人事助手、打卡、请假、补卡、外出、加班、假期余额和 HR/考勤规则。
|
||||
@@ -53,10 +53,11 @@
|
||||
- WCPC 已由 WHMS 承接;审批模板 ID、审批单号 `sp_no`、真实回调配置和 HR 写接口仍需后续独立合同处理,不得直接跳到考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。
|
||||
|
||||
### P0-8 WHMS 企微 HR 主数据镜像口径
|
||||
- WHMS 已本地实现 `wecom_hr_master_sync_v1`,默认 `force_off`,尚未部署公网,未执行生产真实员工批量 apply。
|
||||
- WHMS 已本地实现并部署验证 `wecom_hr_master_sync_v1`,默认和最终均为 `force_off`,未执行生产真实员工批量 apply。
|
||||
- 企微/人事助手作为 HR 主数据源;OA 同步员工档案、部门、主管、职位、手机号、邮箱、默认角色、企业微信绑定和审计。
|
||||
- dry-run 只生成差异和同步记录,不写员工主数据;apply 需要管理员确认,生产真实员工批量 apply 需单独批准。
|
||||
- 缺姓名、手机号、邮箱或部门时记录 `missing_required_field` 并跳过,不生成占位数据;企微不在职状态记录 `needs_offboarding_confirmation`,不自动禁用 OA 账号。
|
||||
- WHMSLIVE 公网验证中,`SMOKE002/测试员工`(脱敏 `oa_smoke***`)因企微侧缺手机号、邮箱和部门按 `missing_required_field` 跳过,证明缺字段不会写入占位数据;普通员工访问同步 API 已验证为 403。
|
||||
- 已有 OA 员工只更新安全主数据字段,不覆盖银行账户、身份证、工资、合同附件或历史审批。
|
||||
- WHMS 不代表考勤/审批镜像、审批回调、OA 应急接管、恢复回写或 RuleOps 已完成;下一阶段仍需另建 `wecom_attendance_approval_mirror_v1`。
|
||||
|
||||
|
||||
+12
-10
@@ -2,10 +2,10 @@
|
||||
|
||||
**文档状态**:当前开发路线图事实源。
|
||||
**分类**:开发治理 / 路线图。
|
||||
**适用时间**:WDRG / WCP1 / WHMS 之后。
|
||||
**关联 Issue**:`WDRG,WCP1,WHMS`。
|
||||
**适用时间**:WDRG / WCP1 / WHMSLIVE 之后。
|
||||
**关联 Issue**:`WDRG,WCP1,WHMS,WHMSLIVE`。
|
||||
**最近审计**:2026-05-18。
|
||||
**不得误读**:本文只控制后续开发节奏、阶段顺序和门禁。WHMS 后只代表企微 HR 主数据镜像已本地实现,尚未部署;不代表企微考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps 已完成运行时实现。
|
||||
**不得误读**:本文只控制后续开发节奏、阶段顺序和门禁。WHMSLIVE 后只代表企微 HR 主数据镜像已部署并受控验证;不代表企微考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps 已完成运行时实现。
|
||||
|
||||
## 1. 路线图原则
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
| `WDRG` | 已完成 | 固定开发路线图和节奏;其下一步 `WECOM-CAPABILITY-POC-V1` 已由 WCP1/WCPC 执行并收口。 |
|
||||
| `WCP1` | 已完成 | 已完成只读 POC runner 和远端只读探测,历史结论为 `PAUSE_FOR_CONFIG`;后续由 WCPC 复跑收口。 |
|
||||
| `WCPC` | 已完成 | 已使用既有在职低风险测试号 `SMOKE002/测试员工`(报告只记录 `oa_smoke***`)完成远端只读复跑,结论 `GO_TO_HR_MASTER_SYNC`;该准入已由 WHMS 承接,不得直接跳到考勤/审批镜像、应急、回写或 RuleOps。 |
|
||||
| `WHMS` | 本地已实现,待部署/公网验证 | 已新增 `wecom_hr_master_sync_v1`、企微/人事助手主数据读取服务、dry-run/apply、同步批次/逐员工记录、People 管理入口和 QA-only runner;默认 `force_off`,未部署,未执行生产真实员工批量 apply。 |
|
||||
| `WHMSLIVE` | 已部署并受控公网验证 | 已部署 `wecom_hr_master_sync_v1`,应用 migration,公网对 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)执行 dry-run 和显式 userids apply;因企微侧缺手机号、邮箱和部门按 `missing_required_field` 跳过,未写 OA 主数据;普通员工权限负例 403;最终 `force_off`,未执行生产真实员工批量 apply。 |
|
||||
|
||||
## 3. 阶段路线
|
||||
|
||||
| 顺序 | 阶段 | 目标 | 进入条件 | 退出条件 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | `WECOM-CAPABILITY-POC-V1` | 只读或低风险探测企微 API 能力,输出能力矩阵。 | WDRG 完成;企微后台权限、Secret、可信 IP、模板和可见范围按现状记录。 | 人事助手、通讯录、打卡、审批、假期余额、回调和权限配置均有 `CAN_REUSE_NOW`、`NEEDS_CONFIG`、`NEEDS_API_POC`、`KEEP_OA_PRIMARY` 或 `NOT_SUPPORTED_BY_API` 结论。 |
|
||||
| 2 | `wecom_hr_master_sync_v1` | 企微/人事助手员工、部门、主管、职位、联系方式和在职状态镜像到 OA。 | POC 证明人事助手/通讯录读取和回调能力可用,或明确缺口处理方式。 | 本地实现通过门禁后进入待部署/公网验证;OA 可自动创建/更新员工档案、账号、角色、企微绑定和审计;缺配置时记录 `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`。 |
|
||||
| 2 | `wecom_hr_master_sync_v1` | 企微/人事助手员工、部门、主管、职位、联系方式和在职状态镜像到 OA。 | POC 证明人事助手/通讯录读取和回调能力可用,或明确缺口处理方式。 | WHMSLIVE 后已完成本地门禁、部署和受控公网验证;OA 可自动创建/更新员工档案、账号、角色、企微绑定和审计;最终 `force_off`,真实员工批量 apply 仍需单独批准;缺配置时记录 `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`。 |
|
||||
| 3 | `wecom_attendance_approval_mirror_v1` | 企微打卡、请假、补卡、外出、加班、假期余额和审批历史镜像到 OA。 | WHMS 部署并完成受控 dry-run/apply 验证;审批模板、打卡规则和回调能力已完成 POC 或有可解释替代方案。 | OA 可查询企微 HR/考勤镜像、附件摘要、审批历史、考勤解释和审计;不把 OA 主办高敏审批迁到企微。 |
|
||||
| 4 | `oa_hr_emergency_mode_v1` | 企业微信不可用时,由管理员人工开启 OA HR/考勤应急接管。 | 企微镜像数据可支撑对账;OA 应急入口、权限和审计方案明确。 | 管理员可填写原因、范围、预计结束时间和责任人后开启/关闭;应急单据带 `EMERGENCY` 标记。 |
|
||||
| 5 | `wecom_recovery_writeback_v1` | 企微恢复后,OA 应急数据先 dry-run,再回写企微。 | 应急接管模式完成;企微写回接口、冲突规则和回滚策略已单独批准。 | 系统生成成功、失败、跳过和冲突清单;无冲突项可自动回写,冲突进入人工确认。 |
|
||||
@@ -112,13 +112,13 @@ POC 默认只读或低风险探测。任何生产写操作、企微规则写入
|
||||
- `callback.config=NEEDS_CONFIG`:本轮只读报告未证明真实回调配置存在。
|
||||
- `hr.staff_update_classification=NEEDS_API_POC`:人事助手资料更新属于写接口,需单独批准后再做低风险 POC。
|
||||
|
||||
WCPC 已允许进入 `wecom_hr_master_sync_v1`。WHMS 已承接该阶段并完成本地实现,考勤/审批镜像仍需先补审批模板、审批单、回调配置并另建 `wecom_attendance_approval_mirror_v1` 合同,不得把 WCPC 或 WHMS 误读为考勤/审批运行时迁移已完成。
|
||||
WCPC 已允许进入 `wecom_hr_master_sync_v1`。WHMS 已承接该阶段,完成本地实现、部署和受控公网验证;考勤/审批镜像仍需先补审批模板、审批单、回调配置并另建 `wecom_attendance_approval_mirror_v1` 合同,不得把 WCPC 或 WHMS 误读为考勤/审批运行时迁移已完成。
|
||||
|
||||
## 9. WHMS HR 主数据镜像状态
|
||||
|
||||
2026-05-18 已建立 `WECOM-HR-MASTER-SYNC-V1` 合同,范围限定为企业微信通讯录/人事助手只读主数据同步到 OA。该阶段不做考勤/审批镜像、审批回调、恢复回写、RuleOps、HR 写企微接口、采购/合同/财务迁移。
|
||||
|
||||
本地实现内容:
|
||||
已实现内容:
|
||||
|
||||
- 新增 feature flag `wecom_hr_master_sync_v1`,默认 `force_off`;新增配置 `WECOM_HR_MASTER_SYNC_ENABLED`、`WECOM_HR_ASSISTANT_SECRET`,允许已验证工作台应用 Secret 作为只读 fallback 并记录 token source。
|
||||
- 新增管理 API:`POST /api/employees/wecom-hr-master-sync/runs`、`GET /api/employees/wecom-hr-master-sync/runs`、`GET /api/employees/wecom-hr-master-sync/runs/:id`。
|
||||
@@ -135,6 +135,8 @@ WCPC 已允许进入 `wecom_hr_master_sync_v1`。WHMS 已承接该阶段并完
|
||||
|
||||
当前状态:
|
||||
|
||||
- 本地代码、文档和 QA runner 已实现,仍需通过本轮门禁后提交。
|
||||
- 尚未部署到公网,未执行生产真实员工批量 `apply`。
|
||||
- 下一阶段仍是 `wecom_attendance_approval_mirror_v1`,但必须在 WHMS 部署和受控验证后另建合同,不能直接跳到应急接管、恢复回写或 RuleOps。
|
||||
- 已通过 `WHMSLIVE` 部署到 `https://oa.hyinda.com`,远端已应用 migration `20260518184319_wecom_hr_master_sync_v1`。
|
||||
- 公网验证窗口中临时将 `wecom_hr_master_sync_v1` 设为 `force_on`,对既有低风险测试号 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)执行 dry-run 和显式 userids apply;企微读取链路通过,因企微侧缺手机号、邮箱和部门,按规则记录 `missing_required_field` 并跳过,未写入 OA 主数据。
|
||||
- 已验证普通员工访问同步 API 返回 403;验证结束后 `wecom_hr_master_sync_v1` 已恢复为 `force_off`。
|
||||
- 未执行生产真实员工批量 `apply`;后续若要正式批量同步真实员工,必须另行批准并先处理企微必填字段质量。
|
||||
- 下一阶段允许规划 `wecom_attendance_approval_mirror_v1`,但必须另建合同,不能直接跳到应急接管、恢复回写或 RuleOps。
|
||||
|
||||
+12
-11
@@ -67,7 +67,8 @@
|
||||
| `WDRG` | `issues/2026-05-18_12-44-10-wecom-development-roadmap-gate.csv` | `EVIDENCE` | 企微优先开发路线图门禁已收口:固定路线图门禁、单功能 Issue CSV 节奏、阶段顺序、并行规则和下一轮 POC 合同口径 |
|
||||
| `WCP1` | `issues/2026-05-18_13-30-07-wecom-capability-poc-v1.csv` | `EVIDENCE` | 企业微信能力 POC 已完成,历史结论 `PAUSE_FOR_CONFIG`;初始配置缺口已由 WCPC 复跑收口 |
|
||||
| `WCPC` | `issues/2026-05-18_15-01-23-wecom-capability-poc-config-closeout-v1.csv` | `EVIDENCE` | WCP1 配置收口已用既有在职测试号复跑通过,结论 `GO_TO_HR_MASTER_SYNC`,已由 WHMS 承接 |
|
||||
| `WHMS` | `issues/2026-05-18_18-43-19-wecom-hr-master-sync-v1.csv` | `CURRENT` | 企微 HR 主数据镜像已本地实现:`wecom_hr_master_sync_v1`、同步批次/逐员工记录、dry-run/apply、管理员 API、People 管理入口和 QA-only runner;默认 `force_off`,未部署公网,未执行生产真实员工批量 apply |
|
||||
| `WHMS` | `issues/2026-05-18_18-43-19-wecom-hr-master-sync-v1.csv` | `CURRENT` | 企微 HR 主数据镜像已实现:`wecom_hr_master_sync_v1`、同步批次/逐员工记录、dry-run/apply、管理员 API、People 管理入口和 QA-only runner;默认 `force_off`,不代表考勤/审批镜像已完成 |
|
||||
| `WHMSLIVE` | `issues/2026-05-18_19-28-25-whms-deploy-live-verify-v1.csv` | `EVIDENCE` | WHMS 已部署并完成受控公网验证:migration 已应用,`SMOKE002` dry-run/apply 管道通过但因缺手机号、邮箱和部门按 `missing_required_field` 跳过,普通员工权限负例 403,最终 `wecom_hr_master_sync_v1=force_off`,未执行生产真实员工批量 apply |
|
||||
|
||||
旧 Issue CSV 保留为历史审计证据:不删除、不批量回写、不移动到 `docs/archive/` 或其他归档目录。新连续合同如替代旧合同,只在新合同 `Notes` 或文档索引中说明 supersedes。
|
||||
|
||||
@@ -75,23 +76,23 @@
|
||||
|
||||
| Doc_ID | Path | Category | Authority | Status | Owner | Related_Issues | Evidence | Supersedes | Last_Audited | Audit_Method | Risk | Notes |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| `IDX` | `docs/文档索引.md` | 入口索引 | 最高文档入口 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1,SYSTEM-COMPLETE-GATE,LAUNCH-OPS-V1,REQ-COMPLETE-AUDIT,ATTV1,LAUNCH-AUTO-OPS-V1,AUTO-REMAINING-CLOSEOUT,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WDRG,WCP1,WCPC,WHMS` | `rg` | none | 2026-05-18 | `node scripts/qa/audit-docs.mjs --check-registry` | medium | 判断当前该读什么 |
|
||||
| `REG` | `docs/文档事实源状态矩阵.md` | 文档台账 | 文档分类和状态事实源 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1,SYSTEM-COMPLETE-GATE,LAUNCH-OPS-V1,REQ-COMPLETE-AUDIT,ATTV1,LAUNCH-AUTO-OPS-V1,AUTO-REMAINING-CLOSEOUT,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WDRG,WCP1,WCPC,WHMS` | `audit-docs` | none | 2026-05-18 | `audit-docs --check-registry` | medium | 判断文档权威性 |
|
||||
| `PRD-MVP` | `docs/海音达OA-MVP需求规格说明书.md` | 需求事实源 | PRD 主事实源 | `CURRENT` | product | `REQ8,P2T,GOV8,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WDRG,WCP1,WCPC,WHMS` | Issue CSV | `docs/requirements-specification.md` | 2026-05-18 | `rg` | high | WHMS 后定义 HR 主数据镜像本地实现、待部署和下一阶段边界;ERP 未来不接入 OA |
|
||||
| `PRODUCT-SCOPE` | `docs/产品口径.md` | 需求事实源 | 产品边界事实源 | `CURRENT` | product | `REQ8,P2T,WFDG,WDRG,WCP1,WCPC,WHMS` | `rg` | none | 2026-05-18 | `rg` | high | 记录已拍板产品边界、企微/OA 设计门禁、开发路线图、WCPC 准入结论和 WHMS 本地实现状态 |
|
||||
| `IDX` | `docs/文档索引.md` | 入口索引 | 最高文档入口 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1,SYSTEM-COMPLETE-GATE,LAUNCH-OPS-V1,REQ-COMPLETE-AUDIT,ATTV1,LAUNCH-AUTO-OPS-V1,AUTO-REMAINING-CLOSEOUT,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE` | `rg` | none | 2026-05-18 | `node scripts/qa/audit-docs.mjs --check-registry` | medium | 判断当前该读什么 |
|
||||
| `REG` | `docs/文档事实源状态矩阵.md` | 文档台账 | 文档分类和状态事实源 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1,SYSTEM-COMPLETE-GATE,LAUNCH-OPS-V1,REQ-COMPLETE-AUDIT,ATTV1,LAUNCH-AUTO-OPS-V1,AUTO-REMAINING-CLOSEOUT,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE` | `audit-docs` | none | 2026-05-18 | `audit-docs --check-registry` | medium | 判断文档权威性 |
|
||||
| `PRD-MVP` | `docs/海音达OA-MVP需求规格说明书.md` | 需求事实源 | PRD 主事实源 | `CURRENT` | product | `REQ8,P2T,GOV8,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE` | Issue CSV | `docs/requirements-specification.md` | 2026-05-18 | `rg` | high | WHMS 后定义 HR 主数据镜像已部署验证和下一阶段边界;ERP 未来不接入 OA |
|
||||
| `PRODUCT-SCOPE` | `docs/产品口径.md` | 需求事实源 | 产品边界事实源 | `CURRENT` | product | `REQ8,P2T,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE` | `rg` | none | 2026-05-18 | `rg` | high | 记录已拍板产品边界、企微/OA 设计门禁、开发路线图、WCPC 准入结论和 WHMS 部署验证状态 |
|
||||
| `DESIGN-UI` | `docs/产品设计规则.md` | 设计事实源 | PC/移动/企业微信设计事实源 | `CURRENT` | design/frontend | `MIA7,MIF7,GOV8,DG8,DG9,WFDG` | Playwright/视觉审查/DG8/DG9/WFDG | none | 2026-05-18 | `rg` | high | 页面改动必须读取;DG8 后飞书为主 UI/布局参考;DG9 后按页面分层和样板选型;WFDG 后区分 OA 主办、企微镜像和 OA 应急接管 |
|
||||
| `ROADMAP-WECOM` | `docs/企微优先开发路线图.md` | 开发治理 | 企微优先开发路线图事实源 | `CURRENT` | product/dev | `WDRG,WCP1,WCPC,WHMS` | Issue CSV | none | 2026-05-18 | `rg` | high | WHMS 后记录企微 HR/考勤路线阶段顺序、HR 主数据镜像本地实现和下一阶段准入边界 |
|
||||
| `ROADMAP-WECOM` | `docs/企微优先开发路线图.md` | 开发治理 | 企微优先开发路线图事实源 | `CURRENT` | product/dev | `WDRG,WCP1,WCPC,WHMS,WHMSLIVE` | Issue CSV | none | 2026-05-18 | `rg` | high | WHMS 后记录企微 HR/考勤路线阶段顺序、HR 主数据镜像部署验证和下一阶段准入边界 |
|
||||
| `DELIVERY` | `docs/开发交付与变更管理规约.md` | 开发治理 | 开发交付事实源 | `CURRENT` | dev/qa | `GOV8,WDRG` | `rg` | none | 2026-05-18 | `rg` | high | Issue、review、commit、交付规则;WDRG 后采用路线图门禁 + 单功能 Issue CSV |
|
||||
| `QA-GATE` | `docs/测试规约与回归门禁.md` | 测试验收 | 测试和回归门禁事实源 | `CURRENT` | qa | `QAF8,GOV8` | 回归脚本/Playwright | none | 2026-05-13 | `rg` | high | 测试计划和 DONE 门禁 |
|
||||
| `AGENT-PRACTICE` | `docs/Agent开发交付实践.md` | Agent 治理 | Agent 协作事实源 | `CURRENT` | dev | `GOV8,DG8` | Skill 校验 | none | 2026-05-13 | `rg` | medium | Agent 协作开发实践和设计主参考层级 |
|
||||
| `AGENTS` | `AGENTS.md` | 执行硬约束 | 项目硬规则 | `CURRENT` | lead | `GOV8` | 人工核对 | none | 2026-05-13 | `rg` | high | 不可违反约束 |
|
||||
| `SKILL-HYB` | `.agents/skills/hyb-oa-delivery/SKILL.md` | Skill | 项目交付 Skill | `CURRENT` | dev | `GOV8,DG8,WFDG,WDRG,WCP1,WCPC,WHMS` | quick_validate | none | 2026-05-18 | `quick_validate.py` | medium | 每轮交付操作入口;企微/OA 后续先读路线图和 WHMS 状态,不得跳过部署/验证直接做考勤审批镜像 |
|
||||
| `SKILL-HYB` | `.agents/skills/hyb-oa-delivery/SKILL.md` | Skill | 项目交付 Skill | `CURRENT` | dev | `GOV8,DG8,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE` | quick_validate | none | 2026-05-18 | `quick_validate.py` | medium | 每轮交付操作入口;企微/OA 后续先读路线图和 WHMSLIVE 状态,不得跳过单功能合同直接做考勤审批镜像 |
|
||||
| `REQ-WF` | `docs/需求-统一审批中心规约.md` | 需求事实源 | 审批模块规约 | `CURRENT` | product/backend | `AP6,WF8,WFOC,DBWFOC,WFDG` | workflow 回归 | none | 2026-05-18 | `rg` | high | OA 主办审批、企微镜像和 OA 应急接管边界 |
|
||||
| `REQ-OCR` | `docs/需求-报销发票OCR规约.md` | 需求事实源 | OCR 模块规约 | `CURRENT` | product/backend | `RI6,OCR8,BIZ8` | OCR 回归 | none | 2026-05-13 | `rg` | high | OCR 和发票边界 |
|
||||
| `RULE-REIMB` | `docs/报销发票附件规则.md` | 需求事实源 | 报销发票附件规则 | `CURRENT` | product/finance | `RI6,BIZ8` | 报销回归 | none | 2026-05-13 | `rg` | high | 报销、发票、附件细则 |
|
||||
| `REQ-WECOM` | `docs/需求-企业微信基础设施规约.md` | 需求事实源 | 企业微信边界规约 | `CURRENT` | product/backend | `R7E,ORG8,WF8,ATTV1,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WCP1,WCPC,WHMS` | live smoke/真机反馈/Issue CSV | none | 2026-05-18 | `rg` | high | 企微优先承担 HR/考勤员工日常审批和人事/打卡能力;WHMS 记录 HR 主数据镜像本地实现;采购、合同、项目、报销和财务继续 OA 主办 |
|
||||
| `REQ-WECOM` | `docs/需求-企业微信基础设施规约.md` | 需求事实源 | 企业微信边界规约 | `CURRENT` | product/backend | `R7E,ORG8,WF8,ATTV1,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WCP1,WCPC,WHMS,WHMSLIVE` | live smoke/真机反馈/Issue CSV | none | 2026-05-18 | `rg` | high | 企微优先承担 HR/考勤员工日常审批和人事/打卡能力;WHMS 记录 HR 主数据镜像部署验证;采购、合同、项目、报销和财务继续 OA 主办 |
|
||||
| `RUNBOOK-TRIAL` | `docs/试运行与自动化验证手册.md` | 操作手册 | 试运行验证手册 | `CURRENT` | qa/ops | `R7E,QAOPS8` | live readiness | none | 2026-05-13 | `rg` | medium | 本地、公网、企业微信和真实 OCR 验证 |
|
||||
| `MANUAL-ADMIN` | `docs/管理员手册.md` | 操作手册 | 管理员手册 | `CURRENT` | ops/admin | `ORG8,R7E,WFOC,DBWFOC,WFDG,WCPC,WHMS` | 人工验收 | none | 2026-05-18 | `rg` | medium | 管理员上线、企微优先边界、OA 主办数据边界、HR 主数据镜像、OA 应急接管、恢复回写和 POC 前置 |
|
||||
| `MANUAL-ADMIN` | `docs/管理员手册.md` | 操作手册 | 管理员手册 | `CURRENT` | ops/admin | `ORG8,R7E,WFOC,DBWFOC,WFDG,WCPC,WHMS,WHMSLIVE` | 人工验收 | none | 2026-05-18 | `rg` | medium | 管理员上线、企微优先边界、OA 主办数据边界、HR 主数据镜像、OA 应急接管、恢复回写和 POC 前置 |
|
||||
| `MANUAL-EMPLOYEE` | `docs/员工快速上手.md` | 操作手册 | 员工手册 | `CURRENT` | product | `R7E,WFOC,DBWFOC,WFDG` | 人工验收 | none | 2026-05-18 | `rg` | low | 员工侧使用说明,HR/考勤优先企业微信,采购/合同/财务仍在 OA;区分企微镜像和 OA 应急接管 |
|
||||
| `R7-DRAFT` | `docs/trialrun/R7扩大试运行草案.md` | 草案 | R7 准备材料 | `DRAFT` | product/qa | `R7E` | R7EP 报告 | none | 2026-05-13 | `rg` | medium | 不代表当前 R7E 执行状态 |
|
||||
| `OPS-RUNBOOK` | `docs/trialrun/OPS7运维交接Runbook.md` | 运维草案 | OPS 准备材料 | `DRAFT` | ops | `OPS8,QAOPS8` | 只读检查 | none | 2026-05-13 | `rg` | medium | 不代表恢复演练已执行 |
|
||||
@@ -108,7 +109,7 @@
|
||||
| `docs/文档事实源状态矩阵.md` | 当前事实源 | 文档分类和恢复规则 |
|
||||
| `docs/海音达OA-MVP需求规格说明书.md` | 当前事实源 | PRD 主事实源 |
|
||||
| `docs/产品设计规则.md` | 当前事实源 | PC、移动、企业微信设计规则;DG8 主 UI/布局参考层级 |
|
||||
| `docs/企微优先开发路线图.md` | 当前事实源 | WDRG/WCP1/WCPC/WHMS 后企微优先 HR/考勤改造阶段顺序、准入/退出门禁、禁止跳阶段和当前 HR 主数据镜像本地实现状态 |
|
||||
| `docs/企微优先开发路线图.md` | 当前事实源 | WDRG/WCP1/WCPC/WHMS/WHMSLIVE 后企微优先 HR/考勤改造阶段顺序、准入/退出门禁、禁止跳阶段和当前 HR 主数据镜像部署验证状态 |
|
||||
| `docs/产品口径.md` | 当前事实源 | 产品边界和业务规则 |
|
||||
| `docs/需求-统一审批中心规约.md` | 当前事实源 | 审批、催办、超时、效率摘要 |
|
||||
| `docs/报销发票附件规则.md` | 当前事实源 | 报销、发票、附件细则 |
|
||||
@@ -183,4 +184,4 @@
|
||||
|
||||
- `ME6-3` 代表性企业微信真机门禁已关闭。
|
||||
- MIF7-1..7 与 MIF7T 已完成本地整改、公网部署、公网匿名复检和带凭据 live smoke/OCR 复检。
|
||||
- R7E 真实扩大试运行阶段验收、P2 排序、R7E 收口、QAOPS8 上线硬化阶段收口、QAOPS9 上线硬化连续合同、PRELAUNCH 正式启用前公网预回归、CASHIER-VOUCHER-V1 财务闭环与银行回单附件、LAUNCH-DEPLOY-FINANCE 部署复检、FIN-PROD-ENABLE 正式常开、ACCOUNTING-HANDOFF-V1 代账交接 SOP、SYSTEM-COMPLETE-GATE 系统完成门禁、LAUNCH-OPS-V1 首周运营保障、REQ-COMPLETE-AUDIT 需求完成度复核、ATTV1 考勤统一入口、AUTO-REMAINING-CLOSEOUT 剩余自动化收口、HRWD-CONTACT-LIVE-TEST 公网企微通讯录真实写入闭环、WFOC 需求重构、DBWFOC 数据边界修正、WFDG 设计门禁、WDRG 路线图门禁和 WCPC 配置复跑均已完成,当前 P0/P1 阻断为 0;P2D 已完成决策分流,P2-ORG 只读巡检已完成且无需写修复合同。LAUNCH-AUTO-OPS-V1 发现的公网 `payment_batch_v1=force_off` 漂移已由 AUTOREM 恢复为 `force_on`,正式自动巡检结论为 `GO_TO_OPERATE`;`erp_sync=force_off`,ERP 未来不接入 OA,正式支付接口、图片 OCR 和银行流水导入继续不进入当前路线。WCP1 已完成企业微信能力 QA-only 只读 POC,历史结论为 `PAUSE_FOR_CONFIG`;WCPC 使用既有在职测试号 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)完成远端只读复跑,报告 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json`,结论 `GO_TO_HR_MASTER_SYNC`,`nextStageAllowed=true`,`blockingCapabilities=[]`。WHMS 已本地实现 `wecom_hr_master_sync_v1`、同步批次/逐员工记录、dry-run/apply、管理员 API、People 管理入口和 QA-only runner;默认 `force_off`,尚未部署公网,未执行生产真实员工批量 apply。HR/考勤员工日常审批优先复用企业微信,OA 目标是按域镜像、人工接管、恢复回写和 RuleOps;采购、费用、合同、项目、报销、付款、AP、代账交接、审计和高敏附件继续 OA 主办。考勤/审批镜像、审批回调、OA 应急接管、恢复回写和 RuleOps 尚未实现;审批模板 ID、审批单号 `sp_no`、真实回调配置和 HR 写接口仍需后续独立合同处理。后续仍须按 [企微优先开发路线图](./企微优先开发路线图.md) 在 WHMS 部署和受控验证后另拆 `wecom_attendance_approval_mirror_v1`、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1`、`wecom_ruleops_v1`;阶段未退出前不得跳阶段。HRWD 已完成 OA 驱动企业微信通讯录同步,并通过 `HRWDTEST-20260517214548` 真实公网 create/update/disable 验证;测试成员按审计要求保留离职/禁用状态。
|
||||
- R7E 真实扩大试运行阶段验收、P2 排序、R7E 收口、QAOPS8 上线硬化阶段收口、QAOPS9 上线硬化连续合同、PRELAUNCH 正式启用前公网预回归、CASHIER-VOUCHER-V1 财务闭环与银行回单附件、LAUNCH-DEPLOY-FINANCE 部署复检、FIN-PROD-ENABLE 正式常开、ACCOUNTING-HANDOFF-V1 代账交接 SOP、SYSTEM-COMPLETE-GATE 系统完成门禁、LAUNCH-OPS-V1 首周运营保障、REQ-COMPLETE-AUDIT 需求完成度复核、ATTV1 考勤统一入口、AUTO-REMAINING-CLOSEOUT 剩余自动化收口、HRWD-CONTACT-LIVE-TEST 公网企微通讯录真实写入闭环、WFOC 需求重构、DBWFOC 数据边界修正、WFDG 设计门禁、WDRG 路线图门禁和 WCPC 配置复跑均已完成,当前 P0/P1 阻断为 0;P2D 已完成决策分流,P2-ORG 只读巡检已完成且无需写修复合同。LAUNCH-AUTO-OPS-V1 发现的公网 `payment_batch_v1=force_off` 漂移已由 AUTOREM 恢复为 `force_on`,正式自动巡检结论为 `GO_TO_OPERATE`;`erp_sync=force_off`,ERP 未来不接入 OA,正式支付接口、图片 OCR 和银行流水导入继续不进入当前路线。WCP1 已完成企业微信能力 QA-only 只读 POC,历史结论为 `PAUSE_FOR_CONFIG`;WCPC 使用既有在职测试号 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)完成远端只读复跑,报告 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json`,结论 `GO_TO_HR_MASTER_SYNC`,`nextStageAllowed=true`,`blockingCapabilities=[]`。WHMS 已实现并部署验证 `wecom_hr_master_sync_v1`、同步批次/逐员工记录、dry-run/apply、管理员 API、People 管理入口和 QA-only runner;默认和最终均为 `force_off`,公网 `SMOKE002` 因缺手机号、邮箱和部门按 `missing_required_field` 跳过,未执行生产真实员工批量 apply。HR/考勤员工日常审批优先复用企业微信,OA 目标是按域镜像、人工接管、恢复回写和 RuleOps;采购、费用、合同、项目、报销、付款、AP、代账交接、审计和高敏附件继续 OA 主办。考勤/审批镜像、审批回调、OA 应急接管、恢复回写和 RuleOps 尚未实现;审批模板 ID、审批单号 `sp_no`、真实回调配置和 HR 写接口仍需后续独立合同处理。后续仍须按 [企微优先开发路线图](./企微优先开发路线图.md) 在 WHMSLIVE 之后另拆 `wecom_attendance_approval_mirror_v1`、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1`、`wecom_ruleops_v1`;阶段未退出前不得跳阶段。HRWD 已完成 OA 驱动企业微信通讯录同步,并通过 `HRWDTEST-20260517214548` 真实公网 create/update/disable 验证;测试成员按审计要求保留离职/禁用状态。
|
||||
|
||||
+6
-5
@@ -20,7 +20,7 @@
|
||||
|
||||
## 最近事实源链
|
||||
|
||||
R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> MIF7/MIF7T(公网部署与带凭据公网复检已收口) -> DG8 -> DG9 -> R7E -> FBA -> QAOPS9/P2D -> P2-ORG -> P2-FIN-DECISION -> P2-FIN-V1 -> P2-OCR-SAMPLE -> P2Q -> P2AUTO -> P2AF -> P2-FIN-LIVE-DECISION -> P2-FIN-LIVE -> PRELAUNCH -> CASHIER-VOUCHER-V1 -> LAUNCH-DEPLOY-FINANCE -> FIN-PROD-ENABLE -> ACCOUNTING-HANDOFF-V1 -> SYSTEM-COMPLETE-GATE -> LAUNCH-OPS-V1 -> REQ-COMPLETE-AUDIT -> ATTV1 -> LAUNCH-AUTO-OPS-V1 -> AUTO-REMAINING-CLOSEOUT -> HR-WECOM-DIRECTORY-V1 -> HRWD-CONTACT-LIVE-TEST -> WCFB -> WFOC -> DBWFOC -> WFDG -> WDRG -> WCP1 -> WCPC -> WHMS。
|
||||
R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> MIF7/MIF7T(公网部署与带凭据公网复检已收口) -> DG8 -> DG9 -> R7E -> FBA -> QAOPS9/P2D -> P2-ORG -> P2-FIN-DECISION -> P2-FIN-V1 -> P2-OCR-SAMPLE -> P2Q -> P2AUTO -> P2AF -> P2-FIN-LIVE-DECISION -> P2-FIN-LIVE -> PRELAUNCH -> CASHIER-VOUCHER-V1 -> LAUNCH-DEPLOY-FINANCE -> FIN-PROD-ENABLE -> ACCOUNTING-HANDOFF-V1 -> SYSTEM-COMPLETE-GATE -> LAUNCH-OPS-V1 -> REQ-COMPLETE-AUDIT -> ATTV1 -> LAUNCH-AUTO-OPS-V1 -> AUTO-REMAINING-CLOSEOUT -> HR-WECOM-DIRECTORY-V1 -> HRWD-CONTACT-LIVE-TEST -> WCFB -> WFOC -> DBWFOC -> WFDG -> WDRG -> WCP1 -> WCPC -> WHMS -> WHMSLIVE。
|
||||
|
||||
- R6、PC6、PA6、FL6、AP6、RI6、LP6 已完成并部署。
|
||||
- ME6 自动化、公网视觉矩阵和 `ME6-3` 代表性企业微信真机门禁已完成。
|
||||
@@ -58,10 +58,10 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M
|
||||
- WFOC 是企微优先 + OA 无痛接管需求重构合同:用户已确认优先复用企业微信成熟能力,OA 做镜像、人工接管、恢复回写、财务闭环和审计中台;其“HR/考勤/行政审批”和“完整镜像”宽口径已由 DBWFOC 修正为 HR/考勤员工日常审批和按域镜像。本轮只冻结需求和事实源,不改业务代码、不部署、不切换公网配置;后续实现需拆 `wecom_hr_master_sync_v1`、`wecom_native_approval_mirror_v1`、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1`、`wecom_ruleops_v1`。
|
||||
- DBWFOC 是 WFOC 后的数据边界修正合同:将“企微优先”收窄为 HR/考勤员工日常审批优先,采购、费用、合同、项目、报销、付款、AP、代账交接、审计和高敏附件继续 OA 主办;企业微信成熟功能可作为流程/字段/交互/规则参考,OA 主办审批只向企业微信发送脱敏提醒和 OA deeplink,不上传高敏附件到企微原生审批。
|
||||
- WFDG 是 DBWFOC 后的设计规约门禁合同:固定后续开发前必须先判定主办方、主事实源、操作端、镜像方向、附件归属和审计责任;PC/移动页面需区分 `OA 主办`、`企微镜像` 和 `OA 应急接管`;下一轮进入 `WECOM-CAPABILITY-POC-V1`,输出 `CAN_REUSE_NOW`、`NEEDS_CONFIG`、`NEEDS_API_POC`、`KEEP_OA_PRIMARY`、`NOT_SUPPORTED_BY_API` 能力矩阵。本轮不改业务代码、不部署、不调用生产写接口。
|
||||
- WDRG 是 WFDG 后的开发路线图门禁合同:新增 [企微优先开发路线图](./企微优先开发路线图.md),固定“路线图门禁 + 单功能 Issue CSV”的开发节奏和阶段顺序;其下一步 `WECOM-CAPABILITY-POC-V1` 已由 WCP1/WCPC 执行并收口,HR 主数据镜像已由 WHMS 本地实现,不得跳过阶段直接开发考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。本轮不改业务代码、不部署、不调用公网写接口。
|
||||
- WDRG 是 WFDG 后的开发路线图门禁合同:新增 [企微优先开发路线图](./企微优先开发路线图.md),固定“路线图门禁 + 单功能 Issue CSV”的开发节奏和阶段顺序;其下一步 `WECOM-CAPABILITY-POC-V1` 已由 WCP1/WCPC 执行并收口,HR 主数据镜像已由 WHMS/WHMSLIVE 实现并部署验证,不得跳过阶段直接开发考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。
|
||||
- WCP1 是 WDRG 后的企业微信能力 POC 合同:新增 QA-only 只读 runner `scripts/qa/check-wecom-capability-poc.mjs`,对人事助手、通讯录、打卡、审批、假期余额、回调和权限配置输出脱敏能力矩阵。远端 live 只读历史结论为 `PAUSE_FOR_CONFIG`,作为初始配置缺口证据保留;当前 HR 主数据镜像准入以 WCPC 复跑结论为准。
|
||||
- WCPC 是 WCP1 后的配置收口合同:已使用既有在职低风险测试号 `SMOKE002/测试员工`(报告只记录 `oa_smoke***`)完成远端只读复跑,报告 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json`,结论 `GO_TO_HR_MASTER_SYNC`。WHMS 已承接该准入结论;审批模板 ID、审批单号 `sp_no`、真实回调配置和 HR 写接口仍需后续独立合同处理。
|
||||
- WHMS 是 WCPC 后的企微 HR 主数据镜像合同:已本地实现 `wecom_hr_master_sync_v1`、企微/人事助手读取服务、dry-run/apply、同步批次/逐员工记录、People 管理入口和 QA-only runner;默认 `force_off`,未部署公网,未执行生产真实员工批量 apply。下一阶段仍需在 WHMS 部署和受控验证后另建 `wecom_attendance_approval_mirror_v1`。
|
||||
- WHMS/WHMSLIVE 是 WCPC 后的企微 HR 主数据镜像合同和部署验证合同:已实现并部署 `wecom_hr_master_sync_v1`、企微/人事助手读取服务、dry-run/apply、同步批次/逐员工记录、People 管理入口和 QA-only runner;公网对 `SMOKE002`(脱敏 `oa_smoke***`)完成 dry-run/apply 管道验证,缺手机号、邮箱和部门按 `missing_required_field` 跳过;权限负例 403;最终 `force_off`,未执行生产真实员工批量 apply。下一阶段可另建 `wecom_attendance_approval_mirror_v1`。
|
||||
|
||||
## 当前活跃治理流
|
||||
|
||||
@@ -109,7 +109,8 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M
|
||||
| `WDRG` | `issues/2026-05-18_12-44-10-wecom-development-roadmap-gate.csv` | 已收口:企微优先开发路线图门禁 | 固定路线图门禁、阶段顺序、单功能 Issue CSV 节奏、并行规则和下一轮 POC 合同口径 | 不改业务代码、不新增 API/schema/UI、不部署、不改公网配置、不调用公网写接口;不代表任何运行时迁移已完成 |
|
||||
| `WCP1` | `issues/2026-05-18_13-30-07-wecom-capability-poc-v1.csv` | 已收口:企业微信能力 POC 已完成,历史结论 `PAUSE_FOR_CONFIG` | QA-only 只读探测人事助手、通讯录、打卡、审批、假期余额、回调和权限配置;输出能力矩阵和配置阻断清单 | 不改业务代码、不新增 API/schema/UI、不部署、不调用生产写接口;初始阻断已由 WCPC 复跑收口 |
|
||||
| `WCPC` | `issues/2026-05-18_15-01-23-wecom-capability-poc-config-closeout-v1.csv` | 已收口:既有测试号 POC 复跑通过 | 使用 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)完成远端只读复跑,结论 `GO_TO_HR_MASTER_SYNC`,已由 WHMS 承接 | 不开发业务功能、不部署、不持久改服务器 env;考勤/审批镜像仍需后续补审批模板、审批单和回调配置 |
|
||||
| `WHMS` | `issues/2026-05-18_18-43-19-wecom-hr-master-sync-v1.csv` | 本地已实现:企微 HR 主数据镜像待部署验证 | 新增 `wecom_hr_master_sync_v1`、Prisma 同步批次/逐员工记录、企微通讯录/人事助手读取、dry-run/apply、管理员 API、People 管理卡片和 QA-only runner | 不部署、不启用公网 flag、不对真实员工批量 apply;不做考勤/审批镜像、审批回调、应急接管、恢复回写或 RuleOps |
|
||||
| `WHMS` | `issues/2026-05-18_18-43-19-wecom-hr-master-sync-v1.csv` | 已实现:企微 HR 主数据镜像 | 新增 `wecom_hr_master_sync_v1`、Prisma 同步批次/逐员工记录、企微通讯录/人事助手读取、dry-run/apply、管理员 API、People 管理卡片和 QA-only runner | 默认 `force_off`;不做考勤/审批镜像、审批回调、应急接管、恢复回写或 RuleOps |
|
||||
| `WHMSLIVE` | `issues/2026-05-18_19-28-25-whms-deploy-live-verify-v1.csv` | 已部署验证:企微 HR 主数据镜像公网受控验证 | 部署 WHMS、应用 migration、公网 dry-run/apply 管道验证、普通员工权限负例、最终 `wecom_hr_master_sync_v1=force_off` | `SMOKE002` 缺手机号、邮箱和部门按 `missing_required_field` 跳过,未写 OA 主数据;未执行生产真实员工批量 apply |
|
||||
|
||||
旧 Issue CSV 不删除、不批量回写、不移动到归档目录。若新治理流替代旧合同,只在新 CSV 的 `Notes` 或本索引说明 supersedes,旧文件保留历史审计语义。
|
||||
|
||||
@@ -132,7 +133,7 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M
|
||||
| [海音达OA-MVP需求规格说明书](./海音达OA-MVP需求规格说明书.md) | PRD 主事实源 |
|
||||
| [文档事实源状态矩阵](./文档事实源状态矩阵.md) | 文档分类、删除恢复和冲突规则 |
|
||||
| [产品设计规则](./产品设计规则.md) | PC、移动、企业微信 WebView 设计事实源;DG8 后飞书工作台/飞书审批为唯一主 UI/布局参考;DG9 后按页面分层和样板选型 |
|
||||
| [企微优先开发路线图](./企微优先开发路线图.md) | WDRG/WCP1/WCPC/WHMS 后企微优先 HR/考勤改造的阶段顺序、准入/退出门禁、并行规则、禁止跳阶段和当前 HR 主数据镜像本地实现事实源 |
|
||||
| [企微优先开发路线图](./企微优先开发路线图.md) | WDRG/WCP1/WCPC/WHMS/WHMSLIVE 后企微优先 HR/考勤改造的阶段顺序、准入/退出门禁、并行规则、禁止跳阶段和当前 HR 主数据镜像部署验证事实源 |
|
||||
| [产品口径](./产品口径.md) | 已拍板产品边界和业务规则 |
|
||||
| [需求 - 统一审批中心规约](./需求-统一审批中心规约.md) | OA 主办审批、企微主办 HR/考勤员工日常审批镜像、催办、超时提醒、审批效率 |
|
||||
| [报销发票附件规则](./报销发票附件规则.md) | 报销、发票、OCR、附件细则 |
|
||||
|
||||
+2
-2
@@ -111,7 +111,7 @@ WCP1 历史结论为 `PAUSE_FOR_CONFIG`,不是 `GO_TO_HR_MASTER_SYNC`;该阻
|
||||
|
||||
### 1.9 WCPC 配置收口
|
||||
|
||||
WCPC 是 WCP1 后的配置复跑合同,只处理企业微信后台配置和只读 POC 复跑,不开发运行时功能。2026-05-18 已按用户要求自动查找并使用既有在职低风险测试号 `SMOKE002/测试员工` 复跑,报告只记录脱敏企业微信 userid 前缀 `oa_smoke***`;远端报告 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json` 的结论为 `GO_TO_HR_MASTER_SYNC`,`nextStageAllowed=true`,`blockingCapabilities=[]`。WHMS 已承接该结论并完成 `wecom_hr_master_sync_v1` 本地实现;审批模板 ID、审批单号 `sp_no`、真实回调配置和 HR 写接口仍需后续独立合同处理,不得直接跳到考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。
|
||||
WCPC 是 WCP1 后的配置复跑合同,只处理企业微信后台配置和只读 POC 复跑,不开发运行时功能。2026-05-18 已按用户要求自动查找并使用既有在职低风险测试号 `SMOKE002/测试员工` 复跑,报告只记录脱敏企业微信 userid 前缀 `oa_smoke***`;远端报告 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json` 的结论为 `GO_TO_HR_MASTER_SYNC`,`nextStageAllowed=true`,`blockingCapabilities=[]`。WHMS 已承接该结论并完成 `wecom_hr_master_sync_v1` 本地实现、部署和受控公网验证;审批模板 ID、审批单号 `sp_no`、真实回调配置和 HR 写接口仍需后续独立合同处理,不得直接跳到考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。
|
||||
|
||||
### 1.10 WHMS 企微 HR 主数据镜像
|
||||
|
||||
@@ -126,7 +126,7 @@ WHMS 将企业微信通讯录/人事助手作为 HR 主数据源的读取能力
|
||||
- 企微不在职状态记录 `needs_offboarding_confirmation`,不自动禁用 OA 账号;离职仍走 OA checklist。
|
||||
- 已有 OA 员工只更新姓名、部门、职位、直属主管、手机号、邮箱和企微绑定,不覆盖银行账户、身份证、工资、合同附件或历史审批。
|
||||
|
||||
当前状态为本地已实现、待部署和公网验证;尚未开启公网 feature flag,尚未对真实员工执行生产批量 apply。下一阶段仍为 `wecom_attendance_approval_mirror_v1`,但必须在 WHMS 部署和受控验证后另建合同。
|
||||
当前状态为已部署并完成受控公网验证:`WHMSLIVE` 已将 WHMS 部署到 `https://oa.hyinda.com`,远端应用 migration `20260518184319_wecom_hr_master_sync_v1`;验证窗口临时 `force_on` 后对 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)执行 dry-run 和显式 userids apply,企微读取链路通过,因企微侧缺手机号、邮箱和部门按 `missing_required_field` 跳过,未写 OA 主数据;普通员工访问同步 API 返回 403;最终 `wecom_hr_master_sync_v1=force_off`。尚未对真实员工执行生产批量 apply。下一阶段可规划 `wecom_attendance_approval_mirror_v1`,但必须另建合同。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+6
-5
@@ -1,6 +1,6 @@
|
||||
# hyb-oa 管理员手册(10 人以下团队版)
|
||||
|
||||
**当前状态(2026-05-18 / WHMS)**:R7E、PRELAUNCH、CASHIER-VOUCHER-V1、LAUNCH-DEPLOY-FINANCE、FIN-PROD-ENABLE、ACCOUNTING-HANDOFF-V1、ATTV1、HR-WECOM-DIRECTORY-V1、HRWD-CONTACT-LIVE-TEST、DBWFOC、WFDG、WDRG、WCPC 均已收口;SYSTEM-COMPLETE-GATE 结论为 `GO_TO_USE`。WCP1 历史结论为 `PAUSE_FOR_CONFIG`,WCPC 已使用既有在职测试号 `SMOKE002/测试员工`(报告只记录 `oa_smoke***`)复跑通过,结论为 `GO_TO_HR_MASTER_SYNC`。WHMS 已本地实现 `wecom_hr_master_sync_v1`:企微/人事助手 HR 主数据可 dry-run/apply 到 OA 员工镜像、账号、角色、绑定和审计;默认 `force_off`,尚未部署公网,未对真实员工执行生产批量 apply。后续“路线图门禁 + 单功能 Issue CSV”的开发节奏保持不变:下一阶段为 `wecom_attendance_approval_mirror_v1`,但必须在 WHMS 部署和受控验证后另建合同;HR/考勤员工日常审批优先复用企业微信,OA 做按域镜像、人工接管、恢复回写、财务闭环和审计中台;采购、费用、合同、项目、报销、付款、AP、代账交接和高敏附件继续 OA 主办,企业微信只做脱敏提醒和 OA deeplink。公网 `payment_batch_v1=force_on`,`erp_sync=force_off`。公司当前无 ERP/独立财务系统,且 ERP 未来不接入 OA;财务闭环以 OA 内审批、台账、付款批次、银行对公付款回单和月度代账交接为准。
|
||||
**当前状态(2026-05-18 / WHMSLIVE)**:R7E、PRELAUNCH、CASHIER-VOUCHER-V1、LAUNCH-DEPLOY-FINANCE、FIN-PROD-ENABLE、ACCOUNTING-HANDOFF-V1、ATTV1、HR-WECOM-DIRECTORY-V1、HRWD-CONTACT-LIVE-TEST、DBWFOC、WFDG、WDRG、WCPC、WHMSLIVE 均已收口;SYSTEM-COMPLETE-GATE 结论为 `GO_TO_USE`。WCP1 历史结论为 `PAUSE_FOR_CONFIG`,WCPC 已使用既有在职测试号 `SMOKE002/测试员工`(报告只记录 `oa_smoke***`)复跑通过,结论为 `GO_TO_HR_MASTER_SYNC`。WHMS 已实现并部署验证 `wecom_hr_master_sync_v1`:企微/人事助手 HR 主数据可 dry-run/apply 到 OA 员工镜像、账号、角色、绑定和审计;默认和最终均为 `force_off`,公网 `SMOKE002` 因企微侧缺手机号、邮箱和部门按 `missing_required_field` 跳过,未对真实员工执行生产批量 apply。后续“路线图门禁 + 单功能 Issue CSV”的开发节奏保持不变:下一阶段为 `wecom_attendance_approval_mirror_v1`,必须另建合同;HR/考勤员工日常审批优先复用企业微信,OA 做按域镜像、人工接管、恢复回写、财务闭环和审计中台;采购、费用、合同、项目、报销、付款、AP、代账交接和高敏附件继续 OA 主办,企业微信只做脱敏提醒和 OA deeplink。公网 `payment_batch_v1=force_on`,`erp_sync=force_off`。公司当前无 ERP/独立财务系统,且 ERP 未来不接入 OA;财务闭环以 OA 内审批、台账、付款批次、银行对公付款回单和月度代账交接为准。
|
||||
|
||||
## 1. 适用范围
|
||||
- 适用于 `small_team_internal` 工作区模式。
|
||||
@@ -24,7 +24,7 @@
|
||||
5. 检查功能开关:
|
||||
- 建议开启:`portal_home_v1`、企业微信入口相关开关、报销/OCR、审批待办、请假、项目基础能力和 `payment_batch_v1`。
|
||||
- 按需开启:`announcements_v1`、`presence_board_v1`、`weekly_report_v1`、`employee_lifecycle_v1`、`hr_wecom_directory_sync_v1`、`todo_board_v1`、`global_search_v1`。
|
||||
- 本地已实现待部署:`wecom_hr_master_sync_v1`,默认 `force_off`;启用和生产 apply 需单独确认。
|
||||
- 已实现并部署验证:`wecom_hr_master_sync_v1`,默认和最终 `force_off`;启用和生产 apply 需单独确认。
|
||||
- 后续按独立合同评估:`wecom_attendance_approval_mirror_v1`(承接旧口径 `wecom_native_approval_mirror_v1`)、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1`、`wecom_ruleops_v1`。
|
||||
- 建议保留备用:`cutover_console_v1`、预算、AI 和完整差旅相关开关;`erp_sync` 保持关闭且不再作为后续接入目标。
|
||||
|
||||
@@ -196,7 +196,7 @@ WCP1/WCPC/WHMS 后续推进:
|
||||
1. 继续先读取 [企微优先开发路线图](./企微优先开发路线图.md) 和 WCP1 报告,再判断能否进入下一阶段。
|
||||
2. WCP1 历史结论为 `PAUSE_FOR_CONFIG`;WCPC 已用既有在职测试号完成远端只读复跑,报告 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json`,结论 `GO_TO_HR_MASTER_SYNC`。
|
||||
3. WCPC 已证明 HR 主数据镜像准入项可用:通讯录成员读取、人事助手花名册读取、打卡短窗口记录/规则读取和假期余额读取均达到可复用状态;审批模板、审批实例和回调配置仍是后续考勤/审批镜像前置项。
|
||||
4. WHMS 已本地实现 `wecom_hr_master_sync_v1`,包括同步批次、逐员工结果、dry-run/apply、People 管理入口和 QA-only runner;当前尚未部署公网。
|
||||
4. WHMS 已实现并部署验证 `wecom_hr_master_sync_v1`,包括同步批次、逐员工结果、dry-run/apply、People 管理入口和 QA-only runner;公网验证后最终保持 `force_off`。
|
||||
5. 正式开发仍按 `wecom_hr_master_sync_v1` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1` 分合同实施;阶段未退出前禁止跳阶段。
|
||||
6. 任何生产写接口、企微规则写入、应急模式开启或恢复回写都必须有单独批准、dry-run 或可审计记录。
|
||||
|
||||
@@ -210,12 +210,13 @@ WCPC 配置复跑清单:
|
||||
|
||||
WHMS 管理操作口径:
|
||||
|
||||
1. 部署并开启 `wecom_hr_master_sync_v1` 前,先确认 `WECOM_HR_MASTER_SYNC_ENABLED`、`WECOM_HR_ASSISTANT_SECRET` 或已验证 fallback Secret 可用。
|
||||
1. 当前 `wecom_hr_master_sync_v1` 已部署并完成受控公网验证,但最终默认保持 `force_off`;正式批量同步真实员工前必须另行批准。
|
||||
2. 在 `人员管理` 的“企微 HR 主数据镜像”卡片先执行 `同步预检`;预检只生成差异和同步记录,不写员工主数据。
|
||||
3. 确认差异后再执行 `确认写入`;生产真实员工批量 apply 必须另有批准,不在日常巡检中自动触发。
|
||||
4. 缺姓名、手机号、邮箱或部门时系统跳过并记录 `missing_required_field`,管理员应先回企微/人事助手补齐,不在 OA 造占位数据。
|
||||
5. 企微不在职或禁用状态只记录 `needs_offboarding_confirmation`,管理员按 OA 离职 checklist 处理,不由同步任务静默禁用账号。
|
||||
6. 同步报告、日志和审计只看脱敏摘要;不得导出完整手机号、邮箱、userid、Secret、access token 或企微原始 payload。
|
||||
7. `WHMSLIVE` 验证证据:`SMOKE002/测试员工`(脱敏 `oa_smoke***`)dry-run 和显式 userids apply 已在公网执行;因企微侧缺手机号、邮箱和部门按 `missing_required_field` 跳过,未写 OA 主数据;普通员工访问同步 API 返回 403。
|
||||
|
||||
### 3.3 正式财务闭环与代账交接
|
||||
|
||||
@@ -442,7 +443,7 @@ WHMS 管理操作口径:
|
||||
- `APP_ORIGIN=https://oa.example.com`
|
||||
- `COOKIE_SECURE=true`
|
||||
- `PUBLIC_SECURITY_HARDENING_ENABLED=true`
|
||||
3. 若启用企业微信入口,补齐:`WECOM_*` 与 `WECOM_ALLOWED_RETURN_HOSTS`。若启用 OA 驱动企业微信通讯录同步,还需补齐 `WECOM_CONTACT_SYNC_ENABLED=true`、`WECOM_CONTACT_SECRET`、`WECOM_CONTACT_DEFAULT_DEPARTMENT_ID`,并确认该 Secret 具备通讯录写权限。若启用企微打卡同步,确认 `海音达工作台` 已被授权调用打卡 API;`WECOM_CHECKIN_SECRET` 留空时复用 `WECOM_AGENT_SECRET`,单独考勤同步应用才需要填写独立 Secret。
|
||||
3. 若启用企业微信入口,补齐:`WECOM_*` 与 `WECOM_ALLOWED_RETURN_HOSTS`。若启用 OA 驱动企业微信通讯录同步,还需补齐 `WECOM_CONTACT_SYNC_ENABLED=true`、`WECOM_CONTACT_SECRET`、`WECOM_CONTACT_DEFAULT_DEPARTMENT_ID`,并确认该 Secret 具备通讯录写权限。若启用企微打卡同步,确认 `海音达工作台` 已被授权调用打卡 API;`WECOM_CHECKIN_SECRET` 留空时复用 `WECOM_AGENT_SECRET`,单独考勤同步应用才需要填写独立 Secret。若启用企微 HR 主数据镜像,确认 `WECOM_HR_MASTER_SYNC_ENABLED=true` 且人事助手 Secret 或已授权工作台应用 Secret 可读取通讯录和花名册;正式批量 apply 仍由 `wecom_hr_master_sync_v1` feature flag 和单独批准控制。
|
||||
4. 将 `OPENAPI_DOCS_ENABLED` 保持为 `false`,不要在公网生产暴露文档入口。
|
||||
5. 定期检查审计日志中的登录失败、Refresh 来源不匹配与涉密资料查看记录。
|
||||
6. 准备独立 smoke 账号,不使用老板、管理员或真实员工日常账号跑自动化;smoke 账号的角色和直属上级应按正式审批链配置。
|
||||
|
||||
+8
-6
@@ -173,7 +173,7 @@ deeplink 必须校验目标地址白名单,避免跳转到非 OA 域名或未
|
||||
| --- | --- | --- |
|
||||
| OA 员工生命周期 | `DONE` | 支持入职、转正、调岗、离职 checklist、账号禁用、会话失效和审计。 |
|
||||
| OA 驱动企微通讯录创建/更新/禁用 | `DONE_LIVE_VERIFIED` | 代码、同步记录、员工管理状态和重试入口已部署;HCLT 公网真实写入闭环通过,`HRWDTEST-20260517214548` create/update/disable 均返回 `errcode=0`。其他环境缺 Secret、默认部门或通讯录 API 权限时仍按 `SKIP/BLOCKED_BY_EXTERNAL_CONFIG` 或失败可重试处理。 |
|
||||
| 企微 HR 主数据同步 OA | `LOCAL_IMPLEMENTED_PENDING_DEPLOY` | `wecom_hr_master_sync_v1` 已本地实现:读取企微通讯录/人事助手,支持 dry-run/apply、同步记录、审计、People 管理入口和 QA-only runner;默认 `force_off`,尚未部署公网,未执行生产真实员工批量 apply。 |
|
||||
| 企微 HR 主数据同步 OA | `DEPLOYED_LIVE_VERIFIED_CONTROLLED` | `wecom_hr_master_sync_v1` 已部署并完成受控公网验证:读取企微通讯录/人事助手,支持 dry-run/apply、同步记录、审计、People 管理入口和 QA-only runner;公网 `SMOKE002` 因缺手机号、邮箱和部门按 `missing_required_field` 跳过;最终 `force_off`,未执行生产真实员工批量 apply。 |
|
||||
| 企业微信原生审批 | `PARTIAL_REUSE_BY_WFOC` | HR/考勤员工日常审批优先复用企业微信,OA 同步按域镜像;报销、财务、采购、合同、项目等 OA 主办审批不迁移。 |
|
||||
|
||||
---
|
||||
@@ -276,13 +276,13 @@ WCP1 历史结论不是 `GO_TO_HR_MASTER_SYNC`,但该阻断已由 WCPC 复跑
|
||||
| `hr.staff_update_classification` | `NEEDS_API_POC`,资料更新属于写接口,需单独批准后再做低风险 POC。 |
|
||||
| `approval.oa_primary_sensitive_domains` | `KEEP_OA_PRIMARY`,采购、合同、报销、财务等继续 OA 主办。 |
|
||||
|
||||
WCPC 已达到 `GO_TO_HR_MASTER_SYNC`。WHMS 已承接该结论并完成 `wecom_hr_master_sync_v1` 本地实现;不得直接开发考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。
|
||||
WCPC 已达到 `GO_TO_HR_MASTER_SYNC`。WHMS 已承接该结论并完成 `wecom_hr_master_sync_v1` 本地实现、部署和受控公网验证;不得直接开发考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。
|
||||
|
||||
## 7.11 WHMS 企微 HR 主数据同步 OA
|
||||
|
||||
`WECOM-HR-MASTER-SYNC-V1` 承接 WCPC 的 `GO_TO_HR_MASTER_SYNC` 结论,把企业微信/人事助手作为员工主数据源的读取能力落成 OA 镜像能力。本阶段仅同步 HR 主数据,不迁移考勤/审批镜像、审批回调、恢复回写、RuleOps、HR 写企微接口、采购/合同/财务流程。
|
||||
|
||||
本地实现范围:
|
||||
已实现范围:
|
||||
|
||||
- 新增 feature flag `wecom_hr_master_sync_v1`,默认 `force_off`。
|
||||
- 新增配置 `WECOM_HR_MASTER_SYNC_ENABLED`、`WECOM_HR_ASSISTANT_SECRET`;`WECOM_AGENT_SECRET` 仅作为已验证授权应用的只读 fallback,并在同步批次中记录 token source,不输出 Secret。
|
||||
@@ -303,8 +303,10 @@ WCPC 已达到 `GO_TO_HR_MASTER_SYNC`。WHMS 已承接该结论并完成 `wecom_
|
||||
|
||||
当前状态:
|
||||
|
||||
- WHMS 已本地实现并进入本轮门禁验证;尚未部署公网。
|
||||
- 生产批量 `apply`、公网开启 `wecom_hr_master_sync_v1`、正式真实员工同步和部署复检必须另行确认或纳入部署/公网验证合同。
|
||||
- WHMS 已通过 `WHMSLIVE` 部署并完成公网验证;部署时应用 migration `20260518184319_wecom_hr_master_sync_v1`,`/ready`、live smoke、public bundle 和 feature flag 基线复检通过。
|
||||
- 公网验证临时开启 `wecom_hr_master_sync_v1=force_on`,对 `SMOKE002/测试员工`(脱敏 `oa_smoke***`)执行 dry-run 和显式 userids apply;通讯录 Secret 遇到 `48009` 时已按 WCPC 逻辑 fallback 到已授权工作台应用 Secret。
|
||||
- `SMOKE002` 企微侧缺手机号、邮箱和部门,apply 按 `missing_required_field` 跳过,未写 OA 主数据;这符合“缺 OA 必填字段默认跳过待补”的边界,不代表真实员工批量同步已启用。
|
||||
- 已验证普通员工访问同步 API 返回 403;验证结束后 `wecom_hr_master_sync_v1` 已恢复为 `force_off`。
|
||||
- WHMS 不解除考勤/审批镜像前置缺口;`wecom_attendance_approval_mirror_v1` 仍需另建合同补审批模板、审批单号和回调配置。
|
||||
|
||||
---
|
||||
@@ -336,7 +338,7 @@ WCPC 已达到 `GO_TO_HR_MASTER_SYNC`。WHMS 已承接该结论并完成 `wecom_
|
||||
- A4:离职停用、组织权限和绑定异常拦截。
|
||||
- A5:企业微信通知 provider 和失败重试,不阻断主业务。
|
||||
- A6:deeplink 白名单和移动目标页回跳。
|
||||
- A7:`wecom_hr_master_sync_v1`,企微/人事助手员工主数据同步 OA;WHMS 已本地实现,待部署和受控公网验证。
|
||||
- A7:`wecom_hr_master_sync_v1`,企微/人事助手员工主数据同步 OA;WHMS 已部署并完成受控公网验证,最终 `force_off`,真实员工批量 apply 仍需单独批准。
|
||||
- A8:`wecom_attendance_approval_mirror_v1`,企微请假、补卡、外出、加班审批和打卡数据按域镜像;该命名承接旧口径 `wecom_native_approval_mirror_v1`。
|
||||
- A9:`oa_hr_emergency_mode_v1`,OA 人工接管 HR/考勤应急提交。
|
||||
- A10:`wecom_recovery_writeback_v1`,企微恢复后 dry-run、自动回写、失败重试和冲突清单。
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
ID,Title,Description,Acceptance,Test_Method,Tools,Dev_Status,Review1_Status,Regression_Status,Files,Dependencies,Notes
|
||||
"WHMSLIVE-0","合同建档","建立 WHMS-DEPLOY-LIVE-VERIFY-V1 执行合同,锁定本轮只做 WHMS 部署、公网验证、证据和事实源回写;不做真实员工批量 apply、考勤/审批镜像、应急接管、恢复回写或 RuleOps。","1) CSV 校验通过;2) 范围限定为 commit 27968fb 的 WHMS 部署与受控公网验证;3) 明确最终 wecom_hr_master_sync_v1 保持 force_off;4) 不打印 Secret、token、完整手机号、邮箱、userid 或企微原始 payload。","受影响流程:WHMS 本地完成 -> 部署验证合同 -> 受控公网验证;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-18_19-28-25-whms-deploy-live-verify-v1.csv。","python3|manual","DONE","DONE","DONE","issues/2026-05-18_19-28-25-whms-deploy-live-verify-v1.csv","[]","已完成合同建档;本轮部署验证中发现并修复通讯录 token 48009 fallback 和 QA runner 判定问题,未新增业务 API/schema/UI;回滚路径:删除本 CSV 或回退 WHMSLIVE 证据提交。"
|
||||
"WHMSLIVE-1","部署前门禁","复核本地基线和 WHMS 静态/构建/单测门禁,确认工作区干净且待部署提交为 27968fb。","1) git log -1 显示 27968fb 或其后续等价验证提交;2) git status 无非预期脏文件;3) Prisma validate、node --check、WHMS focused vitest、QA runner syntax、client typecheck/build、git diff --check 通过。","受影响流程:本地 WHMS 代码 -> 部署前质量门禁;验证步骤:cd server && npm run prisma:validate;cd server && node --check src/routes/employees.js src/services/integrations/wecomHrMaster.js;cd server && npx vitest run tests/unit/wecomHrMaster.service.test.js --reporter=verbose;node --check scripts/qa/check-wecom-hr-master-sync.mjs;cd client && npm run typecheck && npm run build;git diff --check。","git|npm|node|vitest","DONE","DONE","DONE","server/|client/|scripts/qa/check-wecom-hr-master-sync.mjs","[""WHMSLIVE-0""]","本地门禁已通过;部署验证发现的 fallback/runner 修复已追加 focused 单测和语法检查。"
|
||||
"WHMSLIVE-2","远端配置核对","在服务器 /opt/hyb-oa-trialrun/deploy/trialrun/.env 补齐或确认 WECOM_HR_MASTER_SYNC_ENABLED=true;WECOM_HR_ASSISTANT_SECRET 缺失时允许使用已验证 WECOM_AGENT_SECRET fallback;不打印 Secret/token。","1) 远端配置存在 WECOM_HR_MASTER_SYNC_ENABLED=true;2) 只输出 Secret 存在性或 MASKED,不输出明文;3) 不持久开启 DB feature flag;4) 不修改与本轮无关配置。","受影响流程:远端容器环境 -> WHMS 只读/受控 apply 能力;验证步骤:ssh [email protected] 进入 /opt/hyb-oa-trialrun 后检查 env 键名和值,Secret 仅脱敏输出。","ssh|manual","DONE","DONE","DONE","deploy/trialrun/.env|external","[""WHMSLIVE-1""]","已确认远端 WECOM_HR_MASTER_SYNC_ENABLED=true;WECOM_HR_ASSISTANT_SECRET 缺失时走已授权工作台应用 Secret fallback,未输出 Secret/token。"
|
||||
"WHMSLIVE-3","受控部署","使用现有 deploy/trialrun/deploy.sh 且 SYNC_ENV=0 部署本地当前提交到远端,应用 Prisma migration 和 seed-config。","1) 部署脚本成功完成;2) 远端服务重启后健康;3) migration/seed-config 无失败;4) 本地 .env 不同步到远端。","受影响流程:本地提交 -> trialrun 部署 -> 服务启动;验证步骤:SYNC_ENV=0 bash deploy/trialrun/deploy.sh 并检查脚本结果。","bash|docker|prisma","DONE","DONE","DONE","deploy/trialrun/deploy.sh|server/prisma/migrations/","[""WHMSLIVE-2""]","已用 SYNC_ENV=0 完成受控部署并应用 migration 20260518184319_wecom_hr_master_sync_v1;部署过程中未同步本地 .env。"
|
||||
"WHMSLIVE-4","公网基础复检","部署后验证 /ready、public bundle、live smoke、feature flags 基线和 People 页面资源可加载。","1) https://oa.hyinda.com/ready 返回健康;2) live smoke env/readiness 通过;3) payment_batch_v1=force_on 且 erp_sync=force_off;4) People 页面资源可加载。","受影响流程:公网 OA 基础访问 -> 管理员 People 页面入口;验证步骤:curl -fsS https://oa.hyinda.com/ready;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-smoke-env.mjs --strict;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-live-smoke-readiness.sh;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-feature-flags.mjs --expect payment_batch_v1=force_on --expect erp_sync=force_off。","curl|node|bash","DONE","DONE","DONE","scripts/qa/|client/dist/","[""WHMSLIVE-3""]","/ready、live smoke、public bundle 和 feature flag 基线均通过;payment_batch_v1=force_on,erp_sync=force_off。"
|
||||
"WHMSLIVE-5","WHMS 临时验证窗口","临时开启 wecom_hr_master_sync_v1=force_on,使用既有低风险测试号 SMOKE002/测试员工做 live dry-run;apply 仅允许显式 userids 且设置 WECOM_HR_MASTER_SYNC_APPLY_APPROVED=1。","1) dry-run 对 SMOKE002 生成脱敏差异报告;2) apply 仅对显式 SMOKE002 userid 执行一次;3) 同步批次、逐员工记录、审计、脱敏摘要和 People 最近同步摘要可查;4) 普通员工无法访问同步 API 或入口;5) 不执行真实员工批量 apply。","受影响流程:管理员临时开启 WHMS -> live dry-run -> 显式测试号 apply -> 同步记录与权限验证;验证步骤:在验证窗口临时 force_on 后执行 scripts/qa/check-wecom-hr-master-sync.mjs,dry-run 使用 WECOM_HR_MASTER_SYNC_LIVE=1 WECOM_HR_MASTER_SYNC_JSON=1 WECOM_HR_MASTER_SYNC_USERIDS=<SMOKE002-userid>;apply 额外设置 WECOM_HR_MASTER_SYNC_APPLY_APPROVED=1;报告仅输出脱敏 userid 前缀、统计、状态和错误码。","node|ssh|manual","DONE","DONE","DONE","scripts/qa/check-wecom-hr-master-sync.mjs|server/src/routes/employees.js|server/src/services/integrations/wecomHrMaster.js","[""WHMSLIVE-4""]","公网 dry-run 和显式 userids apply 管道已验证;SMOKE002 因企微缺手机号、邮箱和部门按 missing_required_field 跳过,未写 OA 主数据;普通员工同步 API 权限负例 403;未执行真实员工批量 apply。"
|
||||
"WHMSLIVE-6","收口状态","验证完成后将 wecom_hr_master_sync_v1 恢复或保持 force_off,记录代码已部署、公网验证结果和正式批量 apply 未启用。","1) 最终 feature flag 为 force_off;2) 证据记录部署和验证结果;3) 不误写为真实员工批量同步已启用;4) 若失败记录 PAUSE_FOR_FIX。","受影响流程:WHMS 验证窗口关闭 -> 生产默认安全态;验证步骤:通过 live feature flag 查询或远端 DB/管理脚本确认 wecom_hr_master_sync_v1=force_off。","node|ssh|manual","DONE","DONE","DONE","external|docs/trialrun/人工试运行报告.md","[""WHMSLIVE-5""]","已验证最终 wecom_hr_master_sync_v1=force_off;代码已部署并公网受控验证,正式真实员工批量 apply 未启用。"
|
||||
"WHMSLIVE-7","文档和 skill 回写","更新路线图、企微规约、管理员手册、人工试运行报告、文档索引、事实源矩阵和项目 skill,反映 WHMS 部署和公网验证状态。","1) 文档写明 WHMS 部署/公网验证结论和最终 force_off;2) 明确真实员工批量 apply 未启用;3) 路线图下一阶段仍需单独 Issue CSV;4) skill 不误导后续 agent 跳阶段。","受影响流程:事实源 -> 后续企微优先开发节奏;验证步骤:node scripts/qa/audit-docs.mjs --check-registry;python3 /home/shunli/.codex/skills/.system/skill-creator/scripts/quick_validate.py .agents/skills/hyb-oa-delivery;rg -n 'WHMSLIVE|wecom_hr_master_sync_v1|force_off|SMOKE002|企微 HR 主数据|公网验证' docs issues .agents/skills/hyb-oa-delivery/SKILL.md。","node|python3|rg","DONE","DONE","DONE","docs/企微优先开发路线图.md|docs/需求-企业微信基础设施规约.md|docs/管理员手册.md|docs/trialrun/人工试运行报告.md|docs/文档索引.md|docs/文档事实源状态矩阵.md|.agents/skills/hyb-oa-delivery/SKILL.md","[""WHMSLIVE-6""]","事实源已回写 WHMSLIVE 部署、公网验证、最终 force_off 和下一阶段需另建合同;文档只记录事实和边界。"
|
||||
"WHMSLIVE-8","中文提交","回填 Issue 状态,提交公网验证证据和事实源更新,commit message 使用中文并引用 WHMSLIVE。","1) 所有已执行 Test_Method 通过并回填 DONE;2) git diff --check 通过;3) 中文 commit 引用 WHMSLIVE;4) 最终工作区干净或仅保留用户未要求提交的外部变更。","受影响流程:Issue CSV -> 验证证据 -> 中文提交 -> 用户可审计;验证步骤:git diff --check;git status --short;git commit -m 'WHMSLIVE 部署验证企微HR主数据镜像'。","git|manual","DONE","DONE","DONE","issues/2026-05-18_19-28-25-whms-deploy-live-verify-v1.csv|docs/|.agents/skills/hyb-oa-delivery/SKILL.md","[""WHMSLIVE-7""]","提交前确认不包含 Secret、token、完整手机号、邮箱、userid 或企微原始 payload;本轮提交引用 WHMSLIVE。"
|
||||
|
@@ -100,6 +100,9 @@ function summarizeError(json) {
|
||||
async function login(baseUrl, credential) {
|
||||
const result = await fetchJson(`${baseUrl}/api/auth/login`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"x-device-fingerprint": "whmslive-hr-master-sync",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
identifier: credential.identifier,
|
||||
password: credential.password,
|
||||
@@ -145,6 +148,14 @@ function sanitizeRun(run) {
|
||||
};
|
||||
}
|
||||
|
||||
function isAcceptableRun(run) {
|
||||
return run?.status === "success" || run?.status === "partial";
|
||||
}
|
||||
|
||||
function isSkippedRun(run) {
|
||||
return run?.status === "skipped";
|
||||
}
|
||||
|
||||
async function execute(options) {
|
||||
const startedAt = new Date().toISOString();
|
||||
const steps = [];
|
||||
@@ -206,7 +217,18 @@ async function execute(options) {
|
||||
steps: [...steps, step("FAIL", "dry-run", { status: dryRun.status, error: summarizeError(dryRun.json) })],
|
||||
};
|
||||
}
|
||||
steps.push(step("PASS", "dry-run", sanitizeRun(dryRun.json?.data)));
|
||||
const dryRunSummary = sanitizeRun(dryRun.json?.data);
|
||||
if (!isAcceptableRun(dryRunSummary)) {
|
||||
const status = isSkippedRun(dryRunSummary) ? "SKIP" : "FAIL";
|
||||
return {
|
||||
status,
|
||||
conclusion: isSkippedRun(dryRunSummary) ? "DRY_RUN_SKIPPED" : "DRY_RUN_FAILED",
|
||||
startedAt,
|
||||
finishedAt: new Date().toISOString(),
|
||||
steps: [...steps, step(status, "dry-run", dryRunSummary)],
|
||||
};
|
||||
}
|
||||
steps.push(step("PASS", "dry-run", dryRunSummary));
|
||||
|
||||
if (!options.applyApproved) {
|
||||
return {
|
||||
@@ -245,12 +267,24 @@ async function execute(options) {
|
||||
};
|
||||
}
|
||||
|
||||
const applySummary = sanitizeRun(apply.json?.data);
|
||||
if (!isAcceptableRun(applySummary)) {
|
||||
const status = isSkippedRun(applySummary) ? "SKIP" : "FAIL";
|
||||
return {
|
||||
status,
|
||||
conclusion: isSkippedRun(applySummary) ? "APPLY_SKIPPED" : "APPLY_FAILED",
|
||||
startedAt,
|
||||
finishedAt: new Date().toISOString(),
|
||||
steps: [...steps, step(status, "apply", applySummary)],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "PASS",
|
||||
conclusion: "APPLY_DONE",
|
||||
startedAt,
|
||||
finishedAt: new Date().toISOString(),
|
||||
steps: [...steps, step("PASS", "apply", sanitizeRun(apply.json?.data))],
|
||||
steps: [...steps, step("PASS", "apply", applySummary)],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -300,6 +300,10 @@ function hrTokenCandidates(config) {
|
||||
];
|
||||
}
|
||||
|
||||
function canFallbackToAgentSecret(error) {
|
||||
return error instanceof WecomHrMasterSyncError && error.code === "wecom_errcode_48009";
|
||||
}
|
||||
|
||||
function normalizeDepartmentMap(payload) {
|
||||
const map = new Map();
|
||||
const departments = Array.isArray(payload?.department) ? payload.department : [];
|
||||
@@ -419,6 +423,78 @@ function normalizeWecomHrProfile({ contact = {}, staff = {}, departmentMap = new
|
||||
return profile;
|
||||
}
|
||||
|
||||
async function fetchContactProfilesInput({ config, token, userids, limit, fetchImpl, timeoutMs }) {
|
||||
const departmentMap = await fetchDepartmentMap({
|
||||
accessToken: token.accessToken,
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
});
|
||||
const departmentId = toSafeString(config.wecomContactDefaultDepartmentId, 32) || "1";
|
||||
const contacts = userids.length
|
||||
? await Promise.all(userids.map((userid) => fetchContactMember({
|
||||
accessToken: token.accessToken,
|
||||
userid,
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
})))
|
||||
: await listContactMembers({
|
||||
accessToken: token.accessToken,
|
||||
departmentId,
|
||||
limit,
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
});
|
||||
|
||||
return { departmentMap, contacts, tokenSource: token.source };
|
||||
}
|
||||
|
||||
async function fetchContactProfilesInputWithFallback({ config, contactToken, userids, limit, fetchImpl, timeoutMs }) {
|
||||
try {
|
||||
return await fetchContactProfilesInput({
|
||||
config,
|
||||
token: contactToken,
|
||||
userids,
|
||||
limit,
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
});
|
||||
} catch (error) {
|
||||
if (!canFallbackToAgentSecret(error) || contactToken.source === "WECOM_AGENT_SECRET_FALLBACK") {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const fallback = await getTokenFromCandidates({
|
||||
config,
|
||||
candidates: [{ source: "WECOM_AGENT_SECRET_FALLBACK", secret: config?.wecomAgentSecret }],
|
||||
timeoutMs,
|
||||
fetchImpl,
|
||||
});
|
||||
if (!fallback.ok) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
return await fetchContactProfilesInput({
|
||||
config,
|
||||
token: fallback,
|
||||
userids,
|
||||
limit,
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
});
|
||||
} catch (fallbackError) {
|
||||
if (canFallbackToAgentSecret(fallbackError)) {
|
||||
fallbackError.details = {
|
||||
...(fallbackError.details ?? {}),
|
||||
firstTokenSource: contactToken.source,
|
||||
fallbackTokenSource: fallback.source,
|
||||
};
|
||||
}
|
||||
throw fallbackError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchWecomHrProfiles({ config, userids, limit, fetchImpl = fetch }) {
|
||||
const timeoutMs = config.wecomRequestTimeoutMs ?? 10000;
|
||||
const contactToken = await getTokenFromCandidates({
|
||||
@@ -441,29 +517,17 @@ async function fetchWecomHrProfiles({ config, userids, limit, fetchImpl = fetch
|
||||
throw new WecomHrMasterSyncError(hrToken.code, hrToken.message, { missing: hrToken.missing });
|
||||
}
|
||||
|
||||
const departmentMap = await fetchDepartmentMap({
|
||||
accessToken: contactToken.accessToken,
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
});
|
||||
const departmentId = toSafeString(config.wecomContactDefaultDepartmentId, 32) || "1";
|
||||
const contacts = userids.length
|
||||
? await Promise.all(userids.map((userid) => fetchContactMember({
|
||||
accessToken: contactToken.accessToken,
|
||||
userid,
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
})))
|
||||
: await listContactMembers({
|
||||
accessToken: contactToken.accessToken,
|
||||
departmentId,
|
||||
const contactInput = await fetchContactProfilesInputWithFallback({
|
||||
config,
|
||||
contactToken,
|
||||
userids,
|
||||
limit,
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
});
|
||||
|
||||
const profiles = [];
|
||||
for (const contact of contacts) {
|
||||
for (const contact of contactInput.contacts) {
|
||||
const userid = toSafeString(contact.userid, 128);
|
||||
if (!userid) continue;
|
||||
const staff = await fetchHrStaffInfo({
|
||||
@@ -472,13 +536,13 @@ async function fetchWecomHrProfiles({ config, userids, limit, fetchImpl = fetch
|
||||
fetchImpl,
|
||||
timeoutMs,
|
||||
});
|
||||
profiles.push(normalizeWecomHrProfile({ contact, staff, departmentMap }));
|
||||
profiles.push(normalizeWecomHrProfile({ contact, staff, departmentMap: contactInput.departmentMap }));
|
||||
}
|
||||
|
||||
return {
|
||||
profiles,
|
||||
tokenSource: {
|
||||
contact: contactToken.source,
|
||||
contact: contactInput.tokenSource,
|
||||
hr: hrToken.source,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2,11 +2,20 @@ const {
|
||||
maskEmail,
|
||||
maskExternalUserId,
|
||||
maskPhone,
|
||||
fetchWecomHrProfiles,
|
||||
normalizeWecomHrProfile,
|
||||
__testables,
|
||||
} = require("../../src/services/integrations/wecomHrMaster");
|
||||
|
||||
describe("wecom HR master sync helpers", () => {
|
||||
function jsonResponse(payload, status = 200) {
|
||||
return {
|
||||
ok: status >= 200 && status < 300,
|
||||
status,
|
||||
json: async () => payload,
|
||||
};
|
||||
}
|
||||
|
||||
it("normalizes contact and HR assistant data without leaking full sensitive values in summary", () => {
|
||||
const departmentMap = new Map([
|
||||
["1", { externalId: "1", name: "研发部" }],
|
||||
@@ -101,4 +110,67 @@ describe("wecom HR master sync helpers", () => {
|
||||
expect(changes.email.before).toBe(maskEmail("[email protected]"));
|
||||
expect(changes.externalUserId.after).toBe(maskExternalUserId("oa_smoke002"));
|
||||
});
|
||||
|
||||
it("falls back to the authorized app secret when the contact secret is forbidden for read APIs", async () => {
|
||||
const calls = [];
|
||||
const fetchImpl = async (url, init = {}) => {
|
||||
const parsed = new URL(String(url));
|
||||
calls.push({ path: parsed.pathname, token: parsed.searchParams.get("access_token") });
|
||||
if (parsed.pathname === "/cgi-bin/gettoken") {
|
||||
const secret = parsed.searchParams.get("corpsecret");
|
||||
if (secret === "contact-secret-whms-fallback") {
|
||||
return jsonResponse({ errcode: 0, access_token: "contact-token", expires_in: 7200 });
|
||||
}
|
||||
if (secret === "agent-secret-whms-fallback") {
|
||||
return jsonResponse({ errcode: 0, access_token: "agent-token", expires_in: 7200 });
|
||||
}
|
||||
if (secret === "hr-secret-whms-fallback") {
|
||||
return jsonResponse({ errcode: 0, access_token: "hr-token", expires_in: 7200 });
|
||||
}
|
||||
}
|
||||
if (parsed.pathname === "/cgi-bin/department/list" && parsed.searchParams.get("access_token") === "contact-token") {
|
||||
return jsonResponse({ errcode: 48009, errmsg: "api forbidden for contact assistant" });
|
||||
}
|
||||
if (parsed.pathname === "/cgi-bin/department/list" && parsed.searchParams.get("access_token") === "agent-token") {
|
||||
return jsonResponse({ errcode: 0, department: [{ id: 1, name: "管理部", parentid: 0 }] });
|
||||
}
|
||||
if (parsed.pathname === "/cgi-bin/user/get" && parsed.searchParams.get("access_token") === "agent-token") {
|
||||
return jsonResponse({
|
||||
errcode: 0,
|
||||
userid: "oa_smoke002",
|
||||
name: "测试员工",
|
||||
mobile: "19912345678",
|
||||
email: "[email protected]",
|
||||
department: [1],
|
||||
enable: 1,
|
||||
});
|
||||
}
|
||||
if (parsed.pathname === "/cgi-bin/hr/get_staff_info" && parsed.searchParams.get("access_token") === "hr-token") {
|
||||
expect(init.method).toBe("POST");
|
||||
return jsonResponse({ errcode: 0, staff_info: [{ fieldid: "在职状态", value: "在职" }] });
|
||||
}
|
||||
return jsonResponse({ errcode: 40001, errmsg: "unexpected mock request" });
|
||||
};
|
||||
|
||||
const result = await fetchWecomHrProfiles({
|
||||
config: {
|
||||
wecomCorpId: "corp-whms-fallback",
|
||||
wecomAgentId: "1000002",
|
||||
wecomContactSecret: "contact-secret-whms-fallback",
|
||||
wecomAgentSecret: "agent-secret-whms-fallback",
|
||||
wecomHrAssistantSecret: "hr-secret-whms-fallback",
|
||||
wecomContactDefaultDepartmentId: "1",
|
||||
},
|
||||
userids: ["oa_smoke002"],
|
||||
limit: 1,
|
||||
fetchImpl,
|
||||
});
|
||||
|
||||
expect(result.tokenSource.contact).toBe("WECOM_AGENT_SECRET_FALLBACK");
|
||||
expect(result.tokenSource.hr).toBe("WECOM_HR_ASSISTANT_SECRET");
|
||||
expect(result.profiles).toHaveLength(1);
|
||||
expect(result.profiles[0].externalUserId).toBe("oa_smoke002");
|
||||
expect(calls.some((call) => call.path === "/cgi-bin/department/list" && call.token === "contact-token")).toBe(true);
|
||||
expect(calls.some((call) => call.path === "/cgi-bin/department/list" && call.token === "agent-token")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
在新工单中引用
屏蔽一个用户