diff --git a/.agents/skills/hyb-oa-delivery/SKILL.md b/.agents/skills/hyb-oa-delivery/SKILL.md index 37ce02d7..5ce0924f 100644 --- a/.agents/skills/hyb-oa-delivery/SKILL.md +++ b/.agents/skills/hyb-oa-delivery/SKILL.md @@ -17,8 +17,8 @@ Read only what is relevant: - 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, account disablement, or Enterprise WeChat API work, read `docs/需求-企业微信基础设施规约.md`, `docs/企微API能力目录.md`, `docs/管理员手册.md`, and the latest HCLT/HRWD/WAPI/WRRA Issue CSV evidence first. - For any Enterprise WeChat capability, Secret, callback, approval, check-in, HR assistant, or contact-directory task, read `docs/企微API能力目录.md` before planning or coding. WAPI fixes the current Secret matrix: contacts use `WECOM_CONTACT_SECRET`; workbench/OAuth/messages/HR assistant/roster/check-in/approval use `WECOM_AGENT_SECRET`; `WECOM_CHECKIN_SECRET` is only an explicit check-in override; `WECOM_HR_ASSISTANT_SECRET` is historical compatibility and not a default. Do not write runtime code that tries multiple Secrets to guess the correct one. -- For Enterprise WeChat-first HR/attendance runtime migration, read `docs/企微优先开发路线图.md` before planning or coding. WDRG makes the roadmap authoritative for stage order; WAPI adds the runtime-first stage before deep mirror work; WRRA states that WOUA `PASS_WITH_FINDINGS` does not clear deep mirror work; WOUA-FIX has now soft-archived the 7 OA active test accounts missing in WeCom, fixed the `T0000` seed reactivation behavior, transferred the `SMOKE201` test-manager side effects, and rerun WOUA with `oaActiveMissingInWecom=0`. 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. WMSG1 proves real app-message delivery and Deeplink return only; WAPC1 fixes the approval configuration preparation checklist before mirror work; WAPC2 adds the leave/missed-punch approval template and low-risk `sp_no` read-only POC runner. WPROC1/WPROC2 fixed the engineering process gate; WEGOV1 is the route gate, and WACP3 has now implemented the compensation-pull runner but public live read is `PARTIAL_COMPENSATION_NEEDS_CONFIG` because the remote env lacks complete leave/missed-punch template IDs. WREAD1 readability/misapproval check, WADM1 self-owned archive/mirror model design, and WARCH1 minimum history archive still remain before `wecom_attendance_approval_mirror_v1`. WPROC2 adds the executable `process gate`: before WAPC2F or other high-risk WeCom work, run `node scripts/qa/check-process-contract.mjs --baseline` and the issue-specific profile check to enforce DoR/DoD, fixed Secret source, non-self approval, live write switches, missing-config classification, and redaction boundaries. WAPC2F has implemented and deployed `npm run check:wecom-approval-fixtures`; public dry-run reached `PASS_FIXTURE_DRY_RUN_READY` at `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T045001Z/summary.json`, but no real WeCom template or approval was created because `WECOM_APPROVAL_FIXTURE_WRITE=1` was not set. 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. -- WAPC2FLIVE supersedes the WAPC2F dry-run gap for OA-POC samples: after user approval, the runner was corrected to the official `template_name` + `property` controls create-template payload, deployed with `SYNC_ENV=0`, and the public live report `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` reached `PASS_FIXTURE_CREATED`; leave/missed-punch OA-POC templates and low-risk test approvals were created and retained for audit, with WAPC2 auto-rerun `PASS_APPROVAL_POC`. WCBK1 has added and deployed read-only `GET/POST /api/wecom/approval/callback`, `wecomCallbackCrypto`, `npm run check:wecom-approval-callback-poc`, and the `wecom-callback` process gate. After remote callback config was set, public report `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` reached `PASS_CALLBACK_URL_VERIFIED`; after `SMOKE101` approved an existing OA-POC missed-punch test approval, `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` reached `PASS_CALLBACK_EVENT_CONFIRMED` with one redacted event. WACP3 has added and deployed `npm run check:wecom-approval-compensation-poc` and `POST /cgi-bin/oa/getapprovalinfo` read support; public report `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T112117Z/summary.json` is `PARTIAL_COMPENSATION_NEEDS_CONFIG` because `WECOM_APPROVAL_LEAVE_TEMPLATE_ID` and `WECOM_APPROVAL_MISSED_PUNCH_TEMPLATE_ID` are not configured, so it did not pull details or compare callback evidence. This still does not clear mirror data model, emergency mode, writeback, or RuleOps. +- For Enterprise WeChat-first HR/attendance runtime migration, read `docs/企微优先开发路线图.md` before planning or coding. WDRG makes the roadmap authoritative for stage order; WAPI adds the runtime-first stage before deep mirror work; WRRA states that WOUA `PASS_WITH_FINDINGS` does not clear deep mirror work; WOUA-FIX has now soft-archived the 7 OA active test accounts missing in WeCom, fixed the `T0000` seed reactivation behavior, transferred the `SMOKE201` test-manager side effects, and rerun WOUA with `oaActiveMissingInWecom=0`. 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. WMSG1 proves real app-message delivery and Deeplink return only; WAPC1 fixes the approval configuration preparation checklist before mirror work; WAPC2 adds the leave/missed-punch approval template and low-risk `sp_no` read-only POC runner. WPROC1/WPROC2 fixed the engineering process gate; WEGOV1 is the route gate, and WACP3R has now rerun the compensation-pull POC by automatically discovering OA-POC leave/missed-punch template IDs from `SMOKE002` creator. Public report `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` is `PASS_WITH_FINDINGS`: compensation pull and detail read work, with finding that callback evidence files are not persisted across deploys. WREAD1 readability/misapproval check, WADM1 self-owned archive/mirror model design, and WARCH1 minimum history archive still remain before `wecom_attendance_approval_mirror_v1`. WPROC2 adds the executable `process gate`: before WAPC2F or other high-risk WeCom work, run `node scripts/qa/check-process-contract.mjs --baseline` and the issue-specific profile check to enforce DoR/DoD, fixed Secret source, non-self approval, live write switches, missing-config classification, and redaction boundaries. WAPC2F has implemented and deployed `npm run check:wecom-approval-fixtures`; public dry-run reached `PASS_FIXTURE_DRY_RUN_READY` at `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T045001Z/summary.json`, but no real WeCom template or approval was created because `WECOM_APPROVAL_FIXTURE_WRITE=1` was not set. 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. +- WAPC2FLIVE supersedes the WAPC2F dry-run gap for OA-POC samples: after user approval, the runner was corrected to the official `template_name` + `property` controls create-template payload, deployed with `SYNC_ENV=0`, and the public live report `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` reached `PASS_FIXTURE_CREATED`; leave/missed-punch OA-POC templates and low-risk test approvals were created and retained for audit, with WAPC2 auto-rerun `PASS_APPROVAL_POC`. WCBK1 has added and deployed read-only `GET/POST /api/wecom/approval/callback`, `wecomCallbackCrypto`, `npm run check:wecom-approval-callback-poc`, and the `wecom-callback` process gate. After remote callback config was set, public report `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` reached `PASS_CALLBACK_URL_VERIFIED`; after `SMOKE101` approved an existing OA-POC missed-punch test approval, `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` reached `PASS_CALLBACK_EVENT_CONFIRMED` with one redacted event. WACP3/WACP3R has added and deployed `npm run check:wecom-approval-compensation-poc`, `POST /cgi-bin/oa/getapprovalinfo` read support, and automatic template discovery by `SMOKE002` creator; public report `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` is `PASS_WITH_FINDINGS`, because approval details were pulled but callback evidence is not persisted after deploy. This still does not clear mirror data model, emergency mode, writeback, or RuleOps. - WEGOV1 changes the current WeCom route to "Enterprise WeChat owns mature HR/attendance flows; OA stores self-owned history, audit, entry, messages, and emergency fallback." Treat four domains explicitly: WeCom-owned domain is check-in, leave, missed punch, outing, overtime, leave balance, and HR assistant; OA-owned domain remains reimbursement, procurement, contracts, projects, payments, invoices, bank receipts, sensitive attachments, and operating audit; OA archive domain stores WeCom business history, full external keys, and necessary snapshots; OA emergency domain is manually enabled only when WeCom is unavailable. Do not assume a full isolated WeCom sandbox; use the controlled test domain `SMOKE002 -> SMOKE101`, `OA-POC` templates, low-risk approvals, synthetic tests, public live runners, and limited real-device confirmation. Do not start deep mirror until WACP3 compensation pull POC, WREAD1 readability/misapproval gate, WADM1 self-owned archive/mirror data model, and WARCH1 minimum archive implementation have their own contracts and evidence. - 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`. @@ -108,8 +108,8 @@ 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 WAPI, 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 self-owned archive, 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/企微API能力目录.md` and `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 WAPI rule: contacts read with `WECOM_CONTACT_SECRET` and `POST /cgi-bin/user/list_id`; HR assistant/roster uses `WECOM_AGENT_SECRET` and `POST /cgi-bin/hr/get_staff_info`; check-in defaults to `WECOM_AGENT_SECRET` with optional explicit `WECOM_CHECKIN_SECRET`; approval template/detail reads use `WECOM_AGENT_SECRET`; no runtime Secret guessing. 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. WOUA-FIX rerun result remains `PASS_WITH_FINDINGS` only because 5 matched WeCom users lack accepted fields and one archived test binding is retained; `oaActiveMissingInWecom=0`, active OA employees 5/5 match WeCom. WRV1 adds QA-only `npm run check:wecom-runtime-ready` to verify entry, OAuth/bindings, dehydrated app-message dry-run, OA deeplink, contact `user/list_id`, HR assistant `get_staff_info`, and check-in short-window reads; WRA1 fixes the check-in gate so `WECOM_CHECKIN_SYNC_ENABLED` remains only the formal sync-batch switch, while QA-only runtime checks pass `requireSyncEnabled=false` for read-only probing and still block on real Secret, trusted IP, visible scope, permission, or WeCom API failures. WRA1 public report `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T180506Z/summary.json` is `PASS_WITH_CONFIG_GAPS`: entry/OAuth, Secret matrix, OA active bindings, contact, HR assistant, message dry-run, and check-in read passed, with check-in recorded as `readable_sync_disabled`. Real message sending still requires both `--send-test-message` and `WECOM_RUNTIME_TEST_SEND=1`. WAPC2FLIVE has supplied low-risk leave/missed-punch OA-POC samples in live memory and WCBK1 has verified real callback URL plus one approval-status event; WACP3 added the compensation-pull runner but public live read is still `PARTIAL_COMPENSATION_NEEDS_CONFIG` because full template IDs are not persisted in remote env. Attendance/approval mirror, WACP3 config rerun, readability gate, self-owned archive model, minimum history archive, emergency mode, recovery writeback, RuleOps, outing/overtime samples, and HR write APIs remain later-stage gaps. WAPC1 fixed the approval configuration preparation checklist but did not implement mirror. WAPC2 adds `npm run check:wecom-approval-poc` for leave/missed-punch `gettemplatedetail` and low-risk `getapprovaldetail`; missing template ID or `sp_no` must remain `PARTIAL_APPROVAL_POC_NEEDS_CONFIG`, and API/permission/trusted-IP/scope failures remain `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`. WPROC1 adds Definition of Ready, Definition of Done, automatic-first gates, and non-self approval requirements. WAPC2F defaults to applicant `SMOKE002` and approver `SMOKE101`; both must be active, bound, visible, and not the same OA employee or WeCom userid. If `SMOKE101` is unavailable, stop and ask the user instead of switching to another approver. Do not skip stage order: `WECOM-CAPABILITY-POC-V1`/WCPC -> `wecom_hr_master_sync_v1`/WHMSLIVE -> `runtime_first_wecom_enablement`/WAPI+WOUA rerun -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`. UI and API work must distinguish `OA 主办`, `企微主办`, `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. -- WMSG1 has verified real Enterprise WeChat personal-app delivery and Deeplink return: report `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T234431Z/summary.json` has `checks.message.status=OK`, `errcode=0`, and `recipientCount=1`; the user confirmed receiving "OA 运行就绪检查" and opening the OA notifications page from the message. This only clears message/deeplink runtime evidence; approval template IDs, approval `sp_no`, callback event confirmation, compensation pull, and deep mirror work remain separate later gates; template/detail and callback evidence are covered by WAPC2FLIVE/WCBK1 in the OA-POC leave/missed-punch scope, while WACP3 still needs full template IDs configured for a PASS rerun. +- After WAPI, 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 self-owned archive, 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/企微API能力目录.md` and `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 WAPI rule: contacts read with `WECOM_CONTACT_SECRET` and `POST /cgi-bin/user/list_id`; HR assistant/roster uses `WECOM_AGENT_SECRET` and `POST /cgi-bin/hr/get_staff_info`; check-in defaults to `WECOM_AGENT_SECRET` with optional explicit `WECOM_CHECKIN_SECRET`; approval template/detail reads use `WECOM_AGENT_SECRET`; no runtime Secret guessing. 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. WOUA-FIX rerun result remains `PASS_WITH_FINDINGS` only because 5 matched WeCom users lack accepted fields and one archived test binding is retained; `oaActiveMissingInWecom=0`, active OA employees 5/5 match WeCom. WRV1 adds QA-only `npm run check:wecom-runtime-ready` to verify entry, OAuth/bindings, dehydrated app-message dry-run, OA deeplink, contact `user/list_id`, HR assistant `get_staff_info`, and check-in short-window reads; WRA1 fixes the check-in gate so `WECOM_CHECKIN_SYNC_ENABLED` remains only the formal sync-batch switch, while QA-only runtime checks pass `requireSyncEnabled=false` for read-only probing and still block on real Secret, trusted IP, visible scope, permission, or WeCom API failures. WRA1 public report `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T180506Z/summary.json` is `PASS_WITH_CONFIG_GAPS`: entry/OAuth, Secret matrix, OA active bindings, contact, HR assistant, message dry-run, and check-in read passed, with check-in recorded as `readable_sync_disabled`. Real message sending still requires both `--send-test-message` and `WECOM_RUNTIME_TEST_SEND=1`. WAPC2FLIVE has supplied low-risk leave/missed-punch OA-POC samples in live memory, WCBK1 has verified real callback URL plus one approval-status event, and WACP3R has publicly verified compensation pull/details with `PASS_WITH_FINDINGS` due to non-persisted callback evidence. Attendance/approval mirror, readability gate, self-owned archive model, minimum history archive, emergency mode, recovery writeback, RuleOps, outing/overtime samples, and HR write APIs remain later-stage gaps. WAPC1 fixed the approval configuration preparation checklist but did not implement mirror. WAPC2 adds `npm run check:wecom-approval-poc` for leave/missed-punch `gettemplatedetail` and low-risk `getapprovaldetail`; missing template ID or `sp_no` must remain `PARTIAL_APPROVAL_POC_NEEDS_CONFIG`, and API/permission/trusted-IP/scope failures remain `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`. WPROC1 adds Definition of Ready, Definition of Done, automatic-first gates, and non-self approval requirements. WAPC2F defaults to applicant `SMOKE002` and approver `SMOKE101`; both must be active, bound, visible, and not the same OA employee or WeCom userid. If `SMOKE101` is unavailable, stop and ask the user instead of switching to another approver. Do not skip stage order: `WECOM-CAPABILITY-POC-V1`/WCPC -> `wecom_hr_master_sync_v1`/WHMSLIVE -> `runtime_first_wecom_enablement`/WAPI+WOUA rerun -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3/WACP3R 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`. UI and API work must distinguish `OA 主办`, `企微主办`, `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. +- WMSG1 has verified real Enterprise WeChat personal-app delivery and Deeplink return: report `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T234431Z/summary.json` has `checks.message.status=OK`, `errcode=0`, and `recipientCount=1`; the user confirmed receiving "OA 运行就绪检查" and opening the OA notifications page from the message. This only clears message/deeplink runtime evidence; template/detail, callback evidence, and compensation pull are covered by WAPC2FLIVE/WCBK1/WACP3R in the OA-POC leave/missed-punch scope, while readability, self-owned archive model, minimum archive, and deep mirror work remain separate later gates. - WAPC1 has fixed the WeCom approval configuration preparation gate: first templates are leave, missed punch, outing, and overtime; each needs template ID, scope, fields, approver rules, visible scope, and self-built app permission; low-risk test `sp_no` must not contain procurement, contract, reimbursement, invoice, bank receipt, sensitive attachment, or real sensitive business material; callback URL/Token/EncodingAESKey are deployment-only values and must not be written to repo docs or Issue CSV. Do not implement real approval callback handling, deep mirror, emergency mode, recovery writeback, or RuleOps until a later approved Issue covers the POC or implementation. - WAPC2 has added the WeCom approval template/detail read-only POC runner for leave and missed punch. Use `npm run check:wecom-approval-poc`; pass template IDs with `--template=leave:` / `--template=missed_punch:` and low-risk test approval numbers with `--sp-no=leave:` / `--sp-no=missed_punch:`. The runner must use only `WECOM_AGENT_SECRET`, redact full template IDs and `sp_no`, and never output form values, attachments, comments, full userid, token, Secret, or raw payload. - WPROC1 fixes the WeCom approval engineering process. Future WeCom work must satisfy route gate, capability gate, and implementation gate; use automatic runners before asking the user to do manual work. WPROC2 makes this executable through `node scripts/qa/check-process-contract.mjs --baseline` plus issue-specific profiles such as `--profile wecom-approval-fixture`; run it before WAPC2F and later high-risk WeCom contracts. Manual work is limited to write approval, secrets/callback config, WeCom backend settings that cannot be API-driven, real-device confirmation, and risk decisions. High-risk stages require POC before implementation: callback signature/decryption/idempotency, compensation pull, mirror data model, then mirror implementation. diff --git a/docs/trialrun/人工试运行报告.md b/docs/trialrun/人工试运行报告.md index 8f8af6de..97ba5bec 100644 --- a/docs/trialrun/人工试运行报告.md +++ b/docs/trialrun/人工试运行报告.md @@ -58,7 +58,7 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开 - 2026-05-19 WAPC2FLIVE 完成企微审批 OA-POC 样件 live 创建和 WAPC2 自动复跑:用户批准一次 live 创建并选择保留审计后,先以 `SYNC_ENV=0` 部署修正后的 runner,再远端 dry-run 复核 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053335Z/summary.json` 为 `PASS_FIXTURE_DRY_RUN_READY`。首次 live 写入 API 因旧 `create_template` payload 返回 `301086 zh_CN text empty`,未创建任何模板或审批单;随后将 payload 修正为官方 `template_name` + `property` controls 结构并复跑有效 live,报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,请假/补卡 OA-POC 测试模板和低风险测试审批单均创建成功,`checks.autoRerun.status=OK` 且结论 `PASS_APPROVAL_POC`。报告只记录脱敏 template_id / `sp_no` 前缀;测试模板和测试审批记录保留审计,不自动删除。本轮不配置真实回调、不做补偿拉取、不建镜像表、不进入 `wecom_attendance_approval_mirror_v1`。 - 2026-05-19 WCBK1 实现并完成企微审批回调只读 POC:新增只读 `GET/POST /api/wecom/approval/callback`、企微回调验签/AES 解密/事件归一化服务、`npm run check:wecom-approval-callback-poc` 和 `wecom-callback` process gate。已以 `SYNC_ENV=0` 部署并复检 `/ready`;初始远端报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T065414Z/summary.json` 为 `PARTIAL_CALLBACK_NEEDS_CONFIG`,synthetic 回调验签、解密和审批事件解析通过。配置真实回调后,远端报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 达到 `PASS_CALLBACK_URL_VERIFIED`;用户随后由 `SMOKE101` 同意一条现有 OA-POC 补卡测试审批单,复跑报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 达到 `PASS_CALLBACK_EVENT_CONFIRMED`,脱敏证据记录 1 条已通过审批状态事件。本轮不建镜像表、不写 OA 业务数据、不写企微数据、不创建新模板或审批单。 - 2026-05-19 WEGOV1 完成企微主办治理与 OA 自建留存路线修正:本轮只更新 Issue CSV 和事实源,不改业务代码、不部署、不写 OA/企微数据。结论固定为“企微成熟功能优先上线,OA 做自建数据留存、审计、入口、消息和应急兜底”;HR/考勤日常流程优先企微主办,报销、采购、合同、项目、付款、发票、银行回单、高敏附件和经营审计继续 OA 主办。后续顺序调整为 `WACP3 -> WREAD1 -> WADM1 -> WARCH1 -> wecom_attendance_approval_mirror_v1`,其中 WARCH1 先保证企微不可用时可查看已保存历史,再进入完整镜像增强。 -- 2026-05-19 WACP3 实现企微审批补偿拉取只读 POC runner:新增 `server/src/scripts/check-wecom-approval-compensation-poc.js` / `npm run check:wecom-approval-compensation-poc`,固定 `WECOM_AGENT_SECRET` 调用 `POST /cgi-bin/oa/getapprovalinfo`,按最近 72 小时和 `template_id` filters 拉审批单号,再复用 `getapprovaldetail` 拉详情并与 WCBK1 回调证据脱敏比对。本地 CSV、process gate、Prisma、node --check、focused vitest、`scripts/check-minimal.sh` 均通过;已以 `SYNC_ENV=0` 部署并复检 `/ready`。公网只读报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T112117Z/summary.json` 为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`:Secret 矩阵 OK,但远端缺 `WECOM_APPROVAL_LEAVE_TEMPLATE_ID` 和 `WECOM_APPROVAL_MISSED_PUNCH_TEMPLATE_ID`,因此未拉取审批详情、未比对回调事件、未写 OA/企微数据。 +- 2026-05-19 WACP3/WACP3R 完成企微审批补偿拉取只读 POC:新增 `server/src/scripts/check-wecom-approval-compensation-poc.js` / `npm run check:wecom-approval-compensation-poc`,固定 `WECOM_AGENT_SECRET` 调用 `POST /cgi-bin/oa/getapprovalinfo`,按时间窗口和模板过滤拉审批单号,再复用 `getapprovaldetail` 拉详情并与 WCBK1 回调证据脱敏比对。初始公网报告因缺模板 ID 为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`;WACP3R 改为按 `SMOKE002` creator 自动发现 OA-POC 请假/补卡模板并复跑,公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`:请假/补卡各拉到 1 条详情,finding 为回调证据文件未持久化。本轮未写 OA/企微数据,未保存完整模板 ID。 ## 关键证据索引 @@ -114,8 +114,8 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开 | WAPC2F | 已部署并公网 dry-run 通过:新增企微审批 POC 样件 runner;远端 dry-run 报告为 `PASS_FIXTURE_DRY_RUN_READY`,确认 `SMOKE002 -> SMOKE101` 非自审链、Secret 矩阵和脱敏报告边界 | `issues/2026-05-19_10-24-43-wecom-approval-fixture-auto-generate-v1.csv`、`server/src/scripts/check-wecom-approval-fixtures.js`、`/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T045001Z/summary.json` | | WAPC2FLIVE | 已部署并完成 live 创建:修正 `create_template` payload 后,远端报告 `PASS_FIXTURE_CREATED`,OA-POC 请假/补卡测试模板和低风险测试审批单已创建并保留审计;自动复跑 WAPC2 为 `PASS_APPROVAL_POC`。不代表真实回调、补偿拉取、镜像模型或深度镜像已完成 | `issues/2026-05-19_13-24-12-wecom-approval-fixture-live-create-v1.csv`、`/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` | | WCBK1 | 已完成公网真实回调只读 POC:只读回调端点和 synthetic runner 通过本地加密链路;远端配置真实回调后达到 `PASS_CALLBACK_URL_VERIFIED`,`SMOKE101` 同意现有 OA-POC 补卡测试单后达到 `PASS_CALLBACK_EVENT_CONFIRMED`;只保存脱敏事件证据,不写业务镜像 | `issues/2026-05-19_14-11-20-wecom-approval-callback-readonly-poc-v1.csv`、`/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` | -| WEGOV1 | 已完成 docs-only 路线治理:固定企微主办域、OA 主办域、OA 留存域、OA 应急域、受控测试域和自动化/人工边界;明确 WCBK1 证据不直接放行完整镜像,后续先做 WACP3、WREAD1、WADM1 和 WARCH1 | `issues/2026-05-19_18-17-44-wecom-governance-owned-oa-archive-route-v1.csv` | -| WACP3 | 已实现并公网只读复跑:新增补偿拉取 runner 和 `getapprovalinfo` 只读封装;远端报告为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`,缺完整请假/补卡模板 ID 过滤参数,未拉详情、未比对回调、未写数据 | `issues/2026-05-19_19-03-06-wecom-approval-compensation-pull-poc-v1.csv`、`/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T112117Z/summary.json` | +| WEGOV1 | 已完成 docs-only 路线治理:固定企微主办域、OA 主办域、OA 留存域、OA 应急域、受控测试域和自动化/人工边界;明确 WCBK1 证据不直接放行完整镜像,后续先做 WACP3/WACP3R、WREAD1、WADM1 和 WARCH1 | `issues/2026-05-19_18-17-44-wecom-governance-owned-oa-archive-route-v1.csv` | +| WACP3/WACP3R | 已实现并公网只读复跑:新增补偿拉取 runner 和 `getapprovalinfo` 只读封装;WACP3R 不再要求人工填写模板 ID,改为按 `SMOKE002` creator 自动发现 OA-POC 请假/补卡模板并复跑。远端报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`:请假/补卡各拉到 1 条详情,finding 为回调证据文件未持久化,未写 OA/企微数据 | `issues/2026-05-19_19-03-06-wecom-approval-compensation-pull-poc-v1.csv`、`issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv`、`/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` | ## 当前门禁 diff --git a/docs/产品口径.md b/docs/产品口径.md index 8b99395b..17c193cf 100644 --- a/docs/产品口径.md +++ b/docs/产品口径.md @@ -22,7 +22,7 @@ - 企业微信打卡用于原始采集,保留其定位、人脸、Wi-Fi、规则与设备能力。 - OA 后续同步企业微信打卡规则、排班、记录、日报、月报和 HR/考勤审批镜像,形成正式考勤口径。 - 请假、补卡、外出、加班等考勤修正正常在企业微信完成;OA 只在应急模式下接管,并在企微恢复后 dry-run 和自动回写。 -- `wecom_hr_master_sync_v1` 已本地实现并部署公网完成受控验证;最终保持 `force_off`。WOUA-FIX 已按用户确认软归档 7 个缺企微测试账号,复检 OA active 5、企微 active 5、匹配 5、OA active 缺企微 0;剩余企微缺字段先接受不补,归档绑定保留审计。WCBK1 已完成审批回调 URL 验证和一条真实测试审批事件确认。WEGOV1 后,后续考勤/审批镜像、应急接管、恢复回写或 RuleOps 仍必须先完成 WACP3 补偿拉取、WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型和 WARCH1 最小历史留存,再另建 `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`。WOUA-FIX 已按用户确认软归档 7 个缺企微测试账号,复检 OA active 5、企微 active 5、匹配 5、OA active 缺企微 0;剩余企微缺字段先接受不补,归档绑定保留审计。WCBK1 已完成审批回调 URL 验证和一条真实测试审批事件确认。WACP3R 已自动发现 OA-POC 请假/补卡模板并复跑补偿拉取到 `PASS_WITH_FINDINGS`,finding 为回调证据文件未持久化。WEGOV1 后,后续考勤/审批镜像、应急接管、恢复回写或 RuleOps 仍必须先完成 WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型和 WARCH1 最小历史留存,再另建 `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/考勤规则。 @@ -37,8 +37,8 @@ ### P0-5 WDRG 开发路线图门禁 - WDRG 后采用“路线图门禁 + 单功能 Issue CSV”:路线图只控制阶段顺序、准入/退出门禁、并行规则和禁止跳阶段,具体功能仍单独方案、单独 Issue CSV、单独验证。 -- 当前企微优先 HR/考勤路线顺序固定为:`WECOM-CAPABILITY-POC-V1` -> `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC(真实事件已确认)` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`。 -- `WECOM-CAPABILITY-POC-V1` 已由 WCPC 收口,WHMS/WHMSLIVE 已完成 HR 主数据镜像实现和受控公网验证,WOUA-FIX 已完成测试账号差异收口;WRV1/WRA1/WMSG1 固定运行入口、OAuth/绑定、脱敏消息、Deeplink、通讯录、人事助手和打卡只读门禁。后续不得跳过 WAPC2F 自动样件、真实回调 POC、补偿拉取 POC 和镜像数据模型设计,直接开发考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps 正式写入。 +- 当前企微优先 HR/考勤路线顺序固定为:`WECOM-CAPABILITY-POC-V1` -> `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC(真实事件已确认)` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3/WACP3R 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`。 +- `WECOM-CAPABILITY-POC-V1` 已由 WCPC 收口,WHMS/WHMSLIVE 已完成 HR 主数据镜像实现和受控公网验证,WOUA-FIX 已完成测试账号差异收口;WRV1/WRA1/WMSG1 固定运行入口、OAuth/绑定、脱敏消息、Deeplink、通讯录、人事助手和打卡只读门禁;WACP3R 已证明请假/补卡补偿拉取和详情读取可用。后续不得跳过审批可读性门禁、镜像数据模型设计和最小历史留存,直接开发考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps 正式写入。 - 线上缺陷、正式使用阻断、真实反馈扫尾和 QA-only 脚本维护可以另开合同并行;采购、合同、报销、付款、AP、代账和高敏附件继续 OA 主办,不混入企微 HR/考勤路线。 - 路线图事实源为 [企微优先开发路线图](./企微优先开发路线图.md);该路线图不代表任何运行时迁移能力已完成。 - API 和 Secret 事实源为 [企微 API 能力目录](./企微API能力目录.md):通讯录用 `WECOM_CONTACT_SECRET`;人事助手、打卡、消息和 OAuth 默认用 `WECOM_AGENT_SECRET`;不得在运行时代码里轮询多个 Secret 试错。 @@ -46,14 +46,14 @@ ### P0-6 WCP1 企业微信能力 POC 结论 - WCP1 已完成 QA-only 只读 POC,历史结论为 `PAUSE_FOR_CONFIG`;该阻断已由 WCPC 复跑收口。 - 已可复用:工作台应用 token、核心配置、HCLT 通讯录 create/update/disable 证据、通讯录部门读取、人事助手字段配置读取;WCPC 又确认既有在职测试号的通讯录成员读取、人事助手花名册读取、打卡短窗口记录/规则读取和假期余额读取可用。 -- WCP1 初始缺口已留痕:通讯录测试成员读取 `wecom_errcode_48009`、人事助手测试员工读取 `wecom_errcode_60021`、打卡同步开关、审批模板 ID、测试审批单号、假期权限 `wecom_errcode_301062`、回调 URL/Token/AESKey。WAPC2FLIVE 已解决请假/补卡 OA-POC 模板和低风险测试审批单样例;WCBK1 已解决请假/补卡范围内的真实回调 URL 与事件确认。当前仍未补齐的是补偿拉取、镜像数据模型、外出/加班样例或处理决策,以及 HR 写接口 POC。 +- WCP1 初始缺口已留痕:通讯录测试成员读取 `wecom_errcode_48009`、人事助手测试员工读取 `wecom_errcode_60021`、打卡同步开关、审批模板 ID、测试审批单号、假期权限 `wecom_errcode_301062`、回调 URL/Token/AESKey。WAPC2FLIVE 已解决请假/补卡 OA-POC 模板和低风险测试审批单样例;WCBK1 已解决请假/补卡范围内的真实回调 URL 与事件确认;WACP3R 已解决请假/补卡范围内的补偿拉取只读 POC。当前仍未补齐的是镜像数据模型、最小历史留存、外出/加班样例或处理决策,以及 HR 写接口 POC。 - WCP1 报告继续作为初始配置缺口证据保留,当前 HR 主数据镜像准入以 WCPC 结论为准。 ### P0-7 WCPC 配置复跑口径 - WCPC 只做企业微信后台配置收口和只读 POC 复跑,不改业务代码、不部署、不持久写服务器 `.env`。 - 已按用户要求自动查找并使用既有在职低风险测试号 `SMOKE002/测试员工` 复跑;报告和文档只记录脱敏企业微信 userid 前缀 `oa_smoke***`,不得使用已离职/禁用的 `HRWDTEST-20260517214548` 作为主测试号。 - 复跑报告为远端 `/tmp/wecom-capability-poc-wcpc-smoke002/summary.json`,结论 `GO_TO_HR_MASTER_SYNC`,`nextStageAllowed=true`,`blockingCapabilities=[]`。 -- WCPC 已由 WHMS 承接;请假/补卡审批模板 ID、测试审批单号 `sp_no` 和真实回调已由 WAPC2FLIVE/WCBK1 验证;补偿拉取、镜像数据模型、外出/加班样例和 HR 写接口仍需后续独立合同处理。WAPC1/WAPC2 已固定配置准备和只读 POC,但不得据此直接跳到考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。 +- WCPC 已由 WHMS 承接;请假/补卡审批模板 ID、测试审批单号 `sp_no`、真实回调和补偿拉取已由 WAPC2FLIVE/WCBK1/WACP3R 验证;镜像数据模型、最小历史留存、外出/加班样例和 HR 写接口仍需后续独立合同处理。WAPC1/WAPC2 已固定配置准备和只读 POC,但不得据此直接跳到考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps。 ### P0-8 WHMS 企微 HR 主数据镜像口径 - WHMS 已本地实现并部署验证 `wecom_hr_master_sync_v1`,默认和最终均为 `force_off`,未执行生产真实员工批量 apply。 @@ -63,7 +63,7 @@ - WHMSLIVE 公网验证中,`SMOKE002/测试员工`(脱敏 `oa_smoke***`)因企微侧缺手机号、邮箱和部门按 `missing_required_field` 跳过,证明缺字段不会写入占位数据;普通员工访问同步 API 已验证为 403。 - 已有 OA 员工只更新安全主数据字段,不覆盖银行账户、身份证、工资、合同附件或历史审批。 - WAPI 后 WHMS/WOUA 读取策略修正为通讯录 `user/list_id` + 可选成员详情 + 人事助手 `get_staff_info`,通讯录用 `WECOM_CONTACT_SECRET`,人事助手用 `WECOM_AGENT_SECRET`,不再靠 fallback 试错。 -- WHMS/WOUA-FIX 不代表考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps 已完成;WRA1 后 WRV1 的 `PASS_WITH_CONFIG_GAPS` 只代表运行优先主链路可用且曾有审批/回调配置缺口;WMSG1 只证明消息和 Deeplink 可用;WAPC1 只证明审批配置准备清单已固化;WAPC2 只证明只读 runner 已具备;WAPC2FLIVE 只证明 OA-POC 样件可创建并可读;WCBK1 已证明真实回调 URL 验证、验签/解密和一条现有 OA-POC 测试审批单事件脱敏留证;WEGOV1 只修正路线和治理。后续先做 WACP3 补偿拉取 POC、WREAD1 可读性门禁、WADM1 自建留存/镜像模型设计和 WARCH1 最小历史留存,不直接另建 `wecom_attendance_approval_mirror_v1`。 +- WHMS/WOUA-FIX 不代表考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps 已完成;WRA1 后 WRV1 的 `PASS_WITH_CONFIG_GAPS` 只代表运行优先主链路可用且曾有审批/回调配置缺口;WMSG1 只证明消息和 Deeplink 可用;WAPC1 只证明审批配置准备清单已固化;WAPC2 只证明只读 runner 已具备;WAPC2FLIVE 只证明 OA-POC 样件可创建并可读;WCBK1 已证明真实回调 URL 验证、验签/解密和一条现有 OA-POC 测试审批单事件脱敏留证;WACP3R 已证明补偿拉取和审批详情读取可用但发现回调证据文件未持久化;WEGOV1 只修正路线和治理。后续先做 WREAD1 可读性门禁、WADM1 自建留存/镜像模型设计和 WARCH1 最小历史留存,不直接另建 `wecom_attendance_approval_mirror_v1`。 --- diff --git a/docs/企微API能力目录.md b/docs/企微API能力目录.md index 306de9a3..4b4d37bf 100644 --- a/docs/企微API能力目录.md +++ b/docs/企微API能力目录.md @@ -2,8 +2,8 @@ **文档状态**:当前企微 API 调研与本项目使用事实源。 **分类**:集成事实源 / API 能力目录。 -**适用时间**:WAPI / WAPC1 / WAPC2 / WPROC1 / WPROC2 / WAPC2F / WAPC2FLIVE / WCBK1 / WEGOV1 / WACP3 之后。 -**关联 Issue**:`WAPI,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1,WACP3`。 +**适用时间**:WAPI / WAPC1 / WAPC2 / WPROC1 / WPROC2 / WAPC2F / WAPC2FLIVE / WCBK1 / WEGOV1 / WACP3 / WACP3R 之后。 +**关联 Issue**:`WAPI,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1,WACP3,WACP3R`。 **最近核对**:2026-05-19。 **不得误读**:本文只记录本项目会用到的企业微信官方 API 摘要、链接和项目决策,不复制官方文档全文,不保存 Secret、access token、完整 userid、手机号、邮箱或企微原始 payload。官方文档和企业微信后台权限配置始终是最终依据。 @@ -60,7 +60,7 @@ | 审批模板详情 | [获取审批模板详情](https://developer.work.weixin.qq.com/document/path/91982) | `/cgi-bin/oa/gettemplatedetail` | `POST` | `WECOM_AGENT_SECRET` | `CAN_REUSE_NOW_FOR_POC_FIXTURES` | WAPC2 runner 已可读模板详情;WAPC2FLIVE 已自动创建 OA-POC 请假/补卡测试模板并复跑得到 `PASS_APPROVAL_POC`。正式模板和外出/加班仍需单独配置或 POC。 | | 审批申请详情 | [获取审批申请详情](https://developer.work.weixin.qq.com/document/path/91983) | `/cgi-bin/oa/getapprovaldetail` | `POST` | `WECOM_AGENT_SECRET` | `CAN_REUSE_NOW_FOR_POC_FIXTURES` | WAPC2 runner 已可读审批详情;WAPC2FLIVE 已提交低风险请假/补卡测试审批单并自动复跑通过。测试单不得包含采购、合同、报销、发票、银行回单或高敏附件。 | | 审批状态回调 | [审批申请状态变化回调通知](https://developer.work.weixin.qq.com/document/path/91815) | 事件回调 | `GET` URL 验证 / `POST` 事件 | 自建应用回调 Token/EncodingAESKey | `CAN_REUSE_NOW_FOR_CALLBACK_POC` | WCBK1 已部署只读 `GET/POST /api/wecom/approval/callback` 和 `check:wecom-approval-callback-poc`;公网 synthetic 验签/解密/解析通过后,远端配置真实回调并完成 URL 验证,报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 为 `PASS_CALLBACK_URL_VERIFIED`;`SMOKE101` 同意现有 OA-POC 补卡测试单后,报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`。该能力仅证明只读回调链路和脱敏证据,不代表镜像入库已实现。 | -| 批量获取审批单号 | [批量获取审批单号](https://developer.work.weixin.qq.com/document/path/91816) | `/cgi-bin/oa/getapprovalinfo` | `POST` | `WECOM_AGENT_SECRET` | `PARTIAL_COMPENSATION_NEEDS_CONFIG` | WACP3 已新增 `check:wecom-approval-compensation-poc`,按时间窗口和 `template_id` filters 拉审批单号,再用 `getapprovaldetail` 拉详情并与 WCBK1 回调证据比对;公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T112117Z/summary.json` 显示 Secret 可用,但缺完整请假/补卡模板 ID 环境变量,暂未证明 live 拉取通过。 | +| 批量获取审批单号 | [批量获取审批单号](https://developer.work.weixin.qq.com/document/path/91816) | `/cgi-bin/oa/getapprovalinfo` | `POST` | `WECOM_AGENT_SECRET` | `CAN_REUSE_NOW_WITH_FINDINGS` | WACP3/WACP3R 已新增 `check:wecom-approval-compensation-poc`,支持按 `creator` 自动发现 OA-POC 模板,再按 `template_id` filters 拉审批单号,并用 `getapprovaldetail` 拉详情;公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`,证明请假/补卡补偿拉取和详情读取可用,finding 为回调证据文件未持久化导致当前无法跨部署比对历史回调。 | | 提交审批申请 | [提交审批申请](https://developer.work.weixin.qq.com/document/path/91853) | `/cgi-bin/oa/applyevent` | `POST` | `WECOM_AGENT_SECRET` | `DONE_LIVE_VERIFIED_FOR_OA_POC_FIXTURES` | 已接入 WAPC2F QA-only runner;仅可用于 OA-POC 低风险请假/补卡测试审批单自动样件。默认 dry-run 不获取写入 token、不提交审批;live 写入需显式 CLI、`WECOM_APPROVAL_FIXTURE_WRITE=1` 和人工批准,申请人/审批人必须非自审。WAPC2FLIVE 已提交请假/补卡测试审批单并保留审计;OA 主办报销、采购、合同、项目不迁到企微原生审批。 | | 假期余额 | [获取成员假期余额](https://developer.work.weixin.qq.com/document/path/93376) | `/cgi-bin/oa/vacation/getuservacationquota` | `POST` | `WECOM_AGENT_SECRET` | `CAN_REUSE_NOW_OR_NEEDS_PERMISSION` | WCPC 已证明可读但历史有权限错误;后续作为考勤镜像的只读项。 | | 审批模板创建/更新 | [创建审批模板](https://developer.work.weixin.qq.com/document/path/97437)、[更新审批模板](https://developer.work.weixin.qq.com/document/path/97438) | `/cgi-bin/oa/approval/create_template` 等官方模板写接口 | `POST` | `WECOM_AGENT_SECRET` | `DONE_LIVE_VERIFIED_FOR_OA_POC_FIXTURES` | WAPC2FLIVE 已用 `template_name` + `property` controls 结构创建 OA-POC 请假/补卡测试模板并保留审计。正式模板更新、外出/加班模板、RuleOps 写入仍留后期合同。 | @@ -94,7 +94,7 @@ WAPC2 不代表真实回调、审批镜像、应急接管、恢复回写或 Rule WPROC1 将 WAPC2 之后的审批路线固定为: -`WAPC2 -> WAPC2F 自动生成 POC 样件 -> WAPC2FLIVE live 创建与 WAPC2 自动复跑 -> WCBK1 回调只读 POC -> WEGOV1 企微主办治理与自建留存路线修正 -> WACP3 补偿拉取 POC -> WREAD1 审批可读性与误审批防护门禁 -> WADM1 自建留存/镜像数据模型设计 -> WARCH1 最小自建历史留存实现 -> wecom_attendance_approval_mirror_v1` +`WAPC2 -> WAPC2F 自动生成 POC 样件 -> WAPC2FLIVE live 创建与 WAPC2 自动复跑 -> WCBK1 回调只读 POC -> WEGOV1 企微主办治理与自建留存路线修正 -> WACP3/WACP3R 补偿拉取 POC -> WREAD1 审批可读性与误审批防护门禁 -> WADM1 自建留存/镜像数据模型设计 -> WARCH1 最小自建历史留存实现 -> wecom_attendance_approval_mirror_v1` 门禁要求: @@ -106,7 +106,7 @@ WPROC1 将 WAPC2 之后的审批路线固定为: - `WCBK1` 必须先证明真实回调 URL 验证、验签、解密、幂等键和重复投递,不保存 Token、EncodingAESKey 或原始密文。 - `WCBK1` 已完成真实回调 POC:`npm run check:wecom-approval-callback-poc -- --live` 先达到 `PASS_CALLBACK_URL_VERIFIED`,随后由 `SMOKE101` 同意一条现有 OA-POC 补卡测试审批单并复跑达到 `PASS_CALLBACK_EVENT_CONFIRMED`。报告只记录事件类型、审批类型、状态、脱敏 `sp_no`/模板前缀和幂等键摘要,不保存 Token、EncodingAESKey、原始 XML、密文、完整 `sp_no`、完整 userid、表单值、附件或评论。 - `WEGOV1` 固定混合架构:企微主办域为 HR/考勤成熟功能,OA 主办域为财务经营和高敏业务,OA 留存域保存企微关键历史和完整外部关联键,OA 应急域只在企微不可用时人工开启。 -- `WACP3` 已实现补偿拉取 runner,但当前公网只读复跑为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`,原因是远端缺 `WECOM_APPROVAL_LEAVE_TEMPLATE_ID` 和 `WECOM_APPROVAL_MISSED_PUNCH_TEMPLATE_ID`;后续补齐完整模板 ID 后复跑,必须真实输出 `PASS_COMPENSATION_POC`、`PASS_WITH_FINDINGS` 或 `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`,不得无过滤拉取高风险业务审批详情。 +- `WACP3R` 已把补偿拉取复跑改为自动发现:先按 `SMOKE002` creator 获取 OA-POC 审批单号和详情,识别请假/补卡模板,再按模板过滤拉取详情;公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`。finding 是回调证据文件未持久化,不得误读为镜像入库或自建留存已完成。 - `WREAD1` 必须用真机或代表设备确认审批消息、审批列表和详情页的可读性;若快捷同意/驳回容易误操作,则模板调整或该模板回退 OA 主办。 - `WADM1` 必须先设计自建留存和镜像字段、状态机、幂等键、索引、隐私保留和迁移回滚方案,再进入 schema 或业务代码实现。 - `WARCH1` 必须先实现最小自建历史留存,让 OA 在企微 API 不可用时仍可查看已保存历史,再进入完整镜像增强。 @@ -114,7 +114,7 @@ WPROC1 将 WAPC2 之后的审批路线固定为: ## 7. 运行优先结论 - 近期优先利用:企业微信工作台入口、OAuth/免登、绑定、个人应用消息、OA deeplink、通讯录 userid 清单、可选成员详情、人事助手花名册读取、打卡记录和打卡规则读取。 -- 暂缓深度镜像:`wecom_attendance_approval_mirror_v1`、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1`、`wecom_ruleops_v1` 均等 WEGOV1 路线治理后的 WACP3 补偿拉取 POC、WREAD1 可读性门禁、WADM1 自建留存/镜像模型设计、WARCH1 最小历史留存、外出/加班模板测试和打卡细项明确后再拆;WOUA-FIX、WAPC2FLIVE 和 WCBK1 只作为已完成前置证据,不直接放行深度镜像。 +- 暂缓深度镜像:`wecom_attendance_approval_mirror_v1`、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1`、`wecom_ruleops_v1` 均等 WEGOV1/WACP3R 后的 WREAD1 可读性门禁、WADM1 自建留存/镜像模型设计、WARCH1 最小历史留存、外出/加班模板测试和打卡细项明确后再拆;WOUA-FIX、WAPC2FLIVE、WCBK1 和 WACP3R 只作为已完成前置证据,不直接放行深度镜像。 - OA 主办边界不变:报销、采购、费用、合同、项目、付款批次、AP、代账交接、审计和高敏附件继续在 OA 内完成,只向企业微信发送脱敏提醒和 OA 链接。 ## 8. 后续使用要求 diff --git a/docs/企微优先开发路线图.md b/docs/企微优先开发路线图.md index 72f0937c..371966cb 100644 --- a/docs/企微优先开发路线图.md +++ b/docs/企微优先开发路线图.md @@ -2,10 +2,10 @@ **文档状态**:当前开发路线图事实源。 **分类**:开发治理 / 路线图。 -**适用时间**:WDRG / WCP1 / WHMSLIVE / WOUA / WAPI / WRRA / WOUA-FIX / WRV1 / WRA1 / WMSG1 / WAPC1 / WAPC2 / WPROC1 / WPROC2 / WAPC2F / WAPC2FLIVE / WCBK1 / WEGOV1 / WACP3 之后。 -**关联 Issue**:`WDRG,WCP1,WHMS,WHMSLIVE,WOUA,WAPI,WRRA,WOUAFIX,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1,WACP3`。 +**适用时间**:WDRG / WCP1 / WHMSLIVE / WOUA / WAPI / WRRA / WOUA-FIX / WRV1 / WRA1 / WMSG1 / WAPC1 / WAPC2 / WPROC1 / WPROC2 / WAPC2F / WAPC2FLIVE / WCBK1 / WEGOV1 / WACP3 / WACP3R 之后。 +**关联 Issue**:`WDRG,WCP1,WHMS,WHMSLIVE,WOUA,WAPI,WRRA,WOUAFIX,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1,WACP3,WACP3R`。 **最近审计**:2026-05-19。 -**不得误读**:本文只控制后续开发节奏、阶段顺序和门禁。WHMSLIVE 后只代表企微 HR 主数据镜像已部署并受控验证;WAPI 后进一步固定企微 API/Secret 口径并转为运行优先;WRRA 后明确 `PASS_WITH_FINDINGS` 只代表只读对账成功且存在差异,不代表企微考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps 已完成运行时实现。WMSG1 只证明企业微信应用消息可达和 Deeplink 可回到 OA;WAPC1 只固化审批配置准备清单;WAPC2 只新增请假/补卡模板详情和低风险 `sp_no` 审批详情只读 POC,不代表真实回调或镜像能力已完成。WPROC1 后,WAPC2 不直接放行深度镜像,必须先完成自动样件、回调、补偿拉取和镜像数据模型设计门禁。WPROC2 只新增可执行 process gate。WAPC2FLIVE 已创建 OA-POC 请假/补卡测试模板和低风险测试审批单,并自动复跑 WAPC2 得到 `PASS_APPROVAL_POC`。WCBK1 已完成真实回调 URL 验证和一条现有 OA-POC 测试审批单事件确认,公网报告为 `PASS_CALLBACK_EVENT_CONFIRMED`;WEGOV1 后路线明确为“企微成熟功能优先上线,OA 做自建留存、审计、入口、消息和应急兜底”。WACP3 已新增补偿拉取只读 runner 并完成公网复跑,但当前结论为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`:远端缺请假/补卡完整模板 ID 环境变量,尚未证明按窗口拉取 OA-POC 审批单号和详情。上述证据只证明企微主办 HR/考勤的可用基础,不代表补偿拉取已 PASS、可读性门禁、自建留存模型、最小历史留存或 `wecom_attendance_approval_mirror_v1` 已完成。 +**不得误读**:本文只控制后续开发节奏、阶段顺序和门禁。WHMSLIVE 后只代表企微 HR 主数据镜像已部署并受控验证;WAPI 后进一步固定企微 API/Secret 口径并转为运行优先;WRRA 后明确 `PASS_WITH_FINDINGS` 只代表只读对账成功且存在差异,不代表企微考勤/审批镜像、OA 应急接管、恢复回写或 RuleOps 已完成运行时实现。WMSG1 只证明企业微信应用消息可达和 Deeplink 可回到 OA;WAPC1 只固化审批配置准备清单;WAPC2 只新增请假/补卡模板详情和低风险 `sp_no` 审批详情只读 POC,不代表真实回调或镜像能力已完成。WPROC1 后,WAPC2 不直接放行深度镜像,必须先完成自动样件、回调、补偿拉取和镜像数据模型设计门禁。WPROC2 只新增可执行 process gate。WAPC2FLIVE 已创建 OA-POC 请假/补卡测试模板和低风险测试审批单,并自动复跑 WAPC2 得到 `PASS_APPROVAL_POC`。WCBK1 已完成真实回调 URL 验证和一条现有 OA-POC 测试审批单事件确认,公网报告为 `PASS_CALLBACK_EVENT_CONFIRMED`;WEGOV1 后路线明确为“企微成熟功能优先上线,OA 做自建留存、审计、入口、消息和应急兜底”。WACP3R 已将补偿拉取复跑修正为自动按 `SMOKE002` creator 发现 OA-POC 请假/补卡模板,公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`:已拉到请假/补卡审批详情,但当前回调证据文件未持久化到可跨部署读取的位置,作为 findings 进入 WADM1/WARCH1。上述证据只证明企微主办 HR/考勤的可用基础,不代表可读性门禁、自建留存模型、最小历史留存或 `wecom_attendance_approval_mirror_v1` 已完成。 ## 1. 路线图原则 @@ -44,7 +44,7 @@ | `WAPC2FLIVE` | 已完成 live 创建与 WAPC2 自动复跑 | 用户批准后执行一次 live 创建窗口:第一次旧 payload 返回 `301086` 且未创建任何模板或审批单;修正为官方 `template_name` + `property` controls 后,远端报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,已创建 OA-POC 请假/补卡测试模板和低风险测试审批单,`checks.autoRerun.status=OK` 且 `PASS_APPROVAL_POC`。测试模板和测试审批记录保留审计,不自动删除;仍不放行深度镜像。 | | `WCBK1` | 真实回调 URL 与事件已确认 | 新增只读 `GET/POST /api/wecom/approval/callback`、`npm run check:wecom-approval-callback-poc` 和 `wecom-callback` process gate。远端配置回调 URL、Token 和 EncodingAESKey 后,live runner 报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 达到 `PASS_CALLBACK_URL_VERIFIED`;用户随后由 `SMOKE101` 同意一条现有 OA-POC 补卡测试审批单,复跑报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 达到 `PASS_CALLBACK_EVENT_CONFIRMED`,脱敏证据记录 `eventCount=1`、状态 `已通过`。 | | `WEGOV1` | 路线和治理已调整 | 明确混合架构:企微成熟功能优先上线,OA 做自建数据留存、审计、入口、消息和应急兜底;固化受控测试域、自动化优先和人工边界;后续顺序调整为 WACP3、WREAD1、WADM1、WARCH1 后再评估深度镜像。 | -| `WACP3` | 已实现并公网只读复跑,当前缺配置 | 新增 QA-only `npm run check:wecom-approval-compensation-poc` 和 `POST /cgi-bin/oa/getapprovalinfo` 只读封装,固定 `WECOM_AGENT_SECRET`,默认最近 72 小时窗口并仅按请假/补卡模板 ID 过滤拉取审批单号,再复用 `getapprovaldetail` 拉详情。已以 `SYNC_ENV=0` 部署,公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T112117Z/summary.json` 为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`:Secret 矩阵 OK,但缺 `WECOM_APPROVAL_LEAVE_TEMPLATE_ID` 和 `WECOM_APPROVAL_MISSED_PUNCH_TEMPLATE_ID`,因此未拉详情、未比对回调、未写 OA/企微数据。 | +| `WACP3/WACP3R` | 已实现并公网只读复跑,有 findings | 新增 QA-only `npm run check:wecom-approval-compensation-poc` 和 `POST /cgi-bin/oa/getapprovalinfo` 只读封装,固定 `WECOM_AGENT_SECRET`。WACP3R 改为按 `SMOKE002` creator 自动发现 OA-POC 请假/补卡模板 ID,再按模板过滤拉审批单号并用 `getapprovaldetail` 拉详情;公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`:请假/补卡各拉到 1 条详情,发现回调证据文件未持久化导致当前无法跨部署比对历史回调。未写 OA/企微数据,未保存完整模板 ID。 | ## 3. 阶段路线 @@ -58,7 +58,7 @@ | 6 | `WAPC2 自动复跑` | 使用 WAPC2F 生成的脱敏模板 ID 和 `sp_no` 自动复跑只读 POC。 | WAPC2F live 写入生成全部或部分样件。 | 已完成:live 报告中 `checks.autoRerun.status=OK`,请假/补卡模板详情与审批详情可读,结论 `PASS_APPROVAL_POC`。 | | 7 | `WCBK1 回调只读 POC` | 证明真实回调 URL 验证、验签、解密、幂等键和重复投递处理。 | 回调 URL、Token、EncodingAESKey 由部署环境配置;不得写入仓库或聊天。 | 已完成:`PASS_CALLBACK_EVENT_CONFIRMED`。远端 live URL 验证通过后,由 `SMOKE101` 处理现有 OA-POC 补卡测试单触发真实事件;报告只记录脱敏事件类型、状态、`sp_no`/模板前缀和幂等键摘要。 | | 8 | `WEGOV1 企微主办治理与自建留存路线修正` | 固化混合主办边界、OA 自建留存策略、受控测试域和后续顺序。 | WCBK1 已确认真实回调事件;用户选择优先利用企微成熟功能并要求 OA 保存关键历史。 | docs-only 收口;文档明确企微主办域、OA 主办域、OA 留存域、OA 应急域、自动化与人工边界。 | -| 9 | `WACP3 补偿拉取 POC` | 证明按时间窗口批量获取审批单号并可拉取审批详情,作为回调丢失补偿。 | WEGOV1 完成;WAPC2/WAPC2FLIVE/WCBK1 已提供低风险样例、详情读取和真实事件证据;官方 API 和权限明确。 | 已实现 runner 并公网复跑;当前远端结论为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`,缺完整请假/补卡模板 ID 过滤参数。补齐后需复跑到 `PASS_COMPENSATION_POC` 或真实 `PASS_WITH_FINDINGS/SKIP`,才能作为 WADM1 输入。 | +| 9 | `WACP3 补偿拉取 POC` | 证明按时间窗口批量获取审批单号并可拉取审批详情,作为回调丢失补偿。 | WEGOV1 完成;WAPC2/WAPC2FLIVE/WCBK1 已提供低风险样例、详情读取和真实事件证据;官方 API 和权限明确。 | WACP3R 已自动发现 OA-POC 请假/补卡模板并复跑到 `PASS_WITH_FINDINGS`:补偿拉取和详情读取可用;findings 为当前回调证据文件未持久化,需在 WADM1/WARCH1 设计留存模型时解决。 | | 10 | `WREAD1 企微审批可读性与误审批防护门禁` | 真机确认请假、补卡、外出、加班在企微里是否看得清再批,评估快捷同意/驳回误操作风险。 | WACP3 完成或并行准备低风险样例;审批模板可在企微手机端由代表审批人查看。 | 输出 `PASS_READABLE`、`PASS_WITH_TEMPLATE_ADJUSTMENTS` 或 `FAIL_KEEP_OA_PRIMARY_FOR_THIS_TEMPLATE`;不可读模板不得进入正式镜像。 | | 11 | `WADM1 自建留存/镜像数据模型设计` | 先设计 OA 留存字段、状态机、幂等键、索引、隐私保留、审计和迁移回滚方案。 | WACP3 证明补偿拉取可用;WREAD1 明确模板可读性或回退策略。 | 模型覆盖审批、打卡、人事关键快照、回调事件和补偿拉取记录;设计经 Issue CSV 固化后才允许 schema 或业务代码实现。 | | 12 | `WARCH1 最小自建历史留存实现` | 只读保存企微审批、打卡、人事关键快照,先满足企微不可用时可查看历史。 | WADM1 完成并批准 schema/接口实现。 | OA 可查看已保存历史摘要和完整外部关联键;报告和日志只输出脱敏前缀;不保存 Secret、token、EncodingAESKey、原始密文或无治理原始 payload。 | diff --git a/docs/开发交付与变更管理规约.md b/docs/开发交付与变更管理规约.md index 2820cc3a..e82831fe 100644 --- a/docs/开发交付与变更管理规约.md +++ b/docs/开发交付与变更管理规约.md @@ -22,7 +22,7 @@ WDRG 后,企微优先 HR/考勤改造增加一层路线图门禁;WAPI/WRRA `需求事实源 -> 设计门禁 -> 路线图门禁 -> 企微能力 POC -> 单功能 Issue CSV -> 方案批准 -> 开发实现 -> review -> QA 回归 -> 部署 / 公网验证` -路线图只控制顺序、边界、准入和退出条件;具体接口、schema、页面、权限、审计和测试仍必须在单功能 Issue CSV 中声明。阶段未退出前不得跳阶段:WOUA-FIX 已完成测试账号差异收口,但 `PASS_WITH_FINDINGS` 的剩余缺字段/归档绑定不直接放行深度镜像;WRA1 已完成 `WECOM-RUNTIME-READY-V1` 的运行入口、OAuth/绑定、脱敏消息、通讯录、人事助手和打卡只读门禁修正;WMSG1 已完成真实应用消息和 Deeplink 确认。当前 `PASS_WITH_CONFIG_GAPS` 只表示运行优先主链路可用,WAPC1 只表示审批配置准备清单已固化;WAPC2 只证明请假/补卡模板详情和审批详情只读 runner 已具备。WAPC2FLIVE 已创建 OA-POC 请假/补卡测试样件并自动复跑 WAPC2 通过;WCBK1 已完成回调只读代码、synthetic 验签/解密/解析、真实 URL 验证和一条现有 OA-POC 测试审批单事件确认。WEGOV1 后,审批镜像前仍必须先完成 WACP3 补偿拉取 POC、WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存。 +路线图只控制顺序、边界、准入和退出条件;具体接口、schema、页面、权限、审计和测试仍必须在单功能 Issue CSV 中声明。阶段未退出前不得跳阶段:WOUA-FIX 已完成测试账号差异收口,但 `PASS_WITH_FINDINGS` 的剩余缺字段/归档绑定不直接放行深度镜像;WRA1 已完成 `WECOM-RUNTIME-READY-V1` 的运行入口、OAuth/绑定、脱敏消息、通讯录、人事助手和打卡只读门禁修正;WMSG1 已完成真实应用消息和 Deeplink 确认。当前 `PASS_WITH_CONFIG_GAPS` 只表示运行优先主链路可用,WAPC1 只表示审批配置准备清单已固化;WAPC2 只证明请假/补卡模板详情和审批详情只读 runner 已具备。WAPC2FLIVE 已创建 OA-POC 请假/补卡测试样件并自动复跑 WAPC2 通过;WCBK1 已完成回调只读代码、synthetic 验签/解密/解析、真实 URL 验证和一条现有 OA-POC 测试审批单事件确认;WACP3R 已完成补偿拉取公网只读复跑并发现回调证据未持久化。WEGOV1 后,审批镜像前仍必须先完成 WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存。 ## 2. Issue 生命周期 @@ -97,7 +97,7 @@ WDRG 后,企微优先 HR/考勤路线采用“路线图门禁 + 单功能 Issu 当前企微优先路线顺序固定为: -`WECOM-CAPABILITY-POC-V1 -> wecom_hr_master_sync_v1 -> runtime_first_wecom_enablement -> WOUA-FIX / WECOM-RUNTIME-READY-V1 -> WAPC1 审批配置准备 -> WAPC2 请假/补卡只读 POC -> WAPC2F 自动生成 POC 样件 -> WAPC2FLIVE live 创建与 WAPC2 自动复跑 -> WCBK1 回调只读 POC(真实事件已确认) -> WEGOV1 企微主办治理与自建留存路线修正 -> WACP3 补偿拉取 POC -> WREAD1 审批可读性与误审批防护门禁 -> WADM1 自建留存/镜像数据模型设计 -> WARCH1 最小自建历史留存实现 -> wecom_attendance_approval_mirror_v1 -> oa_hr_emergency_mode_v1 -> wecom_recovery_writeback_v1 -> wecom_ruleops_v1` +`WECOM-CAPABILITY-POC-V1 -> wecom_hr_master_sync_v1 -> runtime_first_wecom_enablement -> WOUA-FIX / WECOM-RUNTIME-READY-V1 -> WAPC1 审批配置准备 -> WAPC2 请假/补卡只读 POC -> WAPC2F 自动生成 POC 样件 -> WAPC2FLIVE live 创建与 WAPC2 自动复跑 -> WCBK1 回调只读 POC(真实事件已确认) -> WEGOV1 企微主办治理与自建留存路线修正 -> WACP3/WACP3R 补偿拉取 POC -> WREAD1 审批可读性与误审批防护门禁 -> WADM1 自建留存/镜像数据模型设计 -> WARCH1 最小自建历史留存实现 -> wecom_attendance_approval_mirror_v1 -> oa_hr_emergency_mode_v1 -> wecom_recovery_writeback_v1 -> wecom_ruleops_v1` 允许并行处理线上缺陷、正式使用阻断、真实反馈扫尾和 QA-only 脚本维护;但采购、合同、报销、付款、AP、代账和高敏附件等 OA 主办域必须另开合同,不得混入企微 HR/考勤路线。 diff --git a/docs/文档事实源状态矩阵.md b/docs/文档事实源状态矩阵.md index cd963902..fd5b23eb 100644 --- a/docs/文档事实源状态矩阵.md +++ b/docs/文档事实源状态矩阵.md @@ -84,7 +84,7 @@ | `WAPC2FLIVE` | `issues/2026-05-19_13-24-12-wecom-approval-fixture-live-create-v1.csv` | `CURRENT` | 企微审批 OA-POC 样件 live 创建已完成:修正 `create_template` payload 为官方 `template_name` + `property` controls 结构后,远端报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,请假/补卡测试模板和低风险测试审批单已创建并保留审计,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`;仍不代表真实回调、补偿拉取、镜像模型或深度镜像已完成 | | `WCBK1` | `issues/2026-05-19_14-11-20-wecom-approval-callback-readonly-poc-v1.csv` | `CURRENT` | 企微审批回调只读 POC 已完成公网真实事件验证:只读回调端点、验签/AES 解密/归一化服务和 runner 已部署;远端报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 为 `PASS_CALLBACK_URL_VERIFIED`,`SMOKE101` 同意现有 OA-POC 补卡测试单后复跑 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`;仍不代表补偿拉取、镜像模型或深度镜像已完成 | | `WEGOV1` | `issues/2026-05-19_18-17-44-wecom-governance-owned-oa-archive-route-v1.csv` | `CURRENT` | 企微主办治理与 OA 自建留存路线修正:docs-only 固定企微主办域、OA 主办域、OA 留存域、OA 应急域、受控测试域、自动化/人工边界和后续顺序;WCBK1 后仍需 WACP3、WREAD1、WADM1、WARCH1,不能直接进入深度镜像 | -| `WACP3` | `issues/2026-05-19_19-03-06-wecom-approval-compensation-pull-poc-v1.csv` | `CURRENT` | 企微审批补偿拉取 POC 已实现 runner 并公网只读复跑:新增 `check:wecom-approval-compensation-poc` 和 `getapprovalinfo` 只读封装,固定 `WECOM_AGENT_SECRET`;远端报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T112117Z/summary.json` 为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`,缺完整请假/补卡模板 ID 过滤参数,未拉详情、未比对回调、未写 OA/企微数据 | +| `WACP3/WACP3R` | `issues/2026-05-19_19-03-06-wecom-approval-compensation-pull-poc-v1.csv`、`issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv` | `CURRENT` | 企微审批补偿拉取 POC 已实现并公网只读复跑:新增 `check:wecom-approval-compensation-poc` 和 `getapprovalinfo` 只读封装,固定 `WECOM_AGENT_SECRET`;WACP3R 改为按 `SMOKE002` creator 自动发现 OA-POC 请假/补卡模板并复跑,远端报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`,请假/补卡各拉到 1 条详情,finding 为回调证据文件未持久化;未写 OA/企微数据 | 旧 Issue CSV 保留为历史审计证据:不删除、不批量回写、不移动到 `docs/archive/` 或其他归档目录。新连续合同如替代旧合同,只在新合同 `Notes` 或文档索引中说明 supersedes。 @@ -94,17 +94,17 @@ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | `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,WOUA,WAPI,WRRA,WOUAFIX,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1` | `rg` | none | 2026-05-19 | `node scripts/qa/audit-docs.mjs --check-registry` | medium | 判断当前该读什么;WEGOV1 后优先读取企微主办 + OA 自建留存路线 | | `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,WOUA,WAPI,WRRA,WOUAFIX,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1` | `audit-docs` | none | 2026-05-19 | `audit-docs --check-registry` | medium | 判断文档权威性;WEGOV1 登记当前企微主办与自建留存治理事实 | -| `PRD-MVP` | `docs/海音达OA-MVP需求规格说明书.md` | 需求事实源 | PRD 主事实源 | `CURRENT` | product | `REQ8,P2T,GOV8,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE,WOUA,WAPI,WRRA,WAPC1,WAPC2,WAPC2FLIVE,WCBK1,WEGOV1` | Issue CSV | `docs/requirements-specification.md` | 2026-05-19 | `rg` | high | WEGOV1 后定义 HR/考勤企微主办、OA 自建留存、受控测试域、WACP3/WREAD1/WADM1/WARCH1 前置和深度镜像边界;ERP 未来不接入 OA | +| `PRD-MVP` | `docs/海音达OA-MVP需求规格说明书.md` | 需求事实源 | PRD 主事实源 | `CURRENT` | product | `REQ8,P2T,GOV8,HR-WECOM-DIRECTORY-V1,WFOC,DBWFOC,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE,WOUA,WAPI,WRRA,WAPC1,WAPC2,WAPC2FLIVE,WCBK1,WEGOV1,WACP3,WACP3R` | Issue CSV | `docs/requirements-specification.md` | 2026-05-19 | `rg` | high | WEGOV1 后定义 HR/考勤企微主办、OA 自建留存、受控测试域、WACP3/WACP3R、WREAD1/WADM1/WARCH1 前置和深度镜像边界;ERP 未来不接入 OA | | `PRODUCT-SCOPE` | `docs/产品口径.md` | 需求事实源 | 产品边界事实源 | `CURRENT` | product | `REQ8,P2T,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE,WOUA,WAPI,WRRA,WAPC1,WAPC2FLIVE,WCBK1,WEGOV1` | `rg` | none | 2026-05-19 | `rg` | high | 记录已拍板产品边界、企微/OA 设计门禁、开发路线图、WCBK1 真实回调事件证据、WEGOV1 混合主办边界和 OA 自建留存策略 | | `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,WHMSLIVE,WOUA,WAPI,WRRA,WOUAFIX,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1` | Issue CSV | none | 2026-05-19 | `rg` | high | WEGOV1 后记录企微主办域、OA 主办域、OA 留存域、OA 应急域、受控测试域、WACP3/WREAD1/WADM1/WARCH1 顺序和禁止跳阶段 | +| `ROADMAP-WECOM` | `docs/企微优先开发路线图.md` | 开发治理 | 企微优先开发路线图事实源 | `CURRENT` | product/dev | `WDRG,WCP1,WCPC,WHMS,WHMSLIVE,WOUA,WAPI,WRRA,WOUAFIX,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1,WACP3,WACP3R` | Issue CSV | none | 2026-05-19 | `rg` | high | WACP3R 后记录补偿拉取 `PASS_WITH_FINDINGS`、回调证据未持久化 finding、WREAD1/WADM1/WARCH1 顺序和禁止跳阶段 | | `WECOM-API-CATALOG` | `docs/企微API能力目录.md` | 集成事实源 | 企微 API 能力目录和 Secret 矩阵事实源 | `CURRENT` | product/backend/qa | `WAPI,WRRA,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1` | 官方企业微信开发者中心链接/Issue CSV | none | 2026-05-19 | `rg` | high | 企微开发先读;只保存摘要、链接和项目决策,不保存 Secret、token、完整 userid、手机号、邮箱或原始 payload;WEGOV1 后记录无完整 sandbox 假设、自建留存策略和后续 POC 顺序 | | `DELIVERY` | `docs/开发交付与变更管理规约.md` | 开发治理 | 开发交付事实源 | `CURRENT` | dev/qa | `GOV8,WDRG,WRRA,WAPC1,WPROC1,WPROC2,WCBK1,WEGOV1` | `rg` | none | 2026-05-19 | `rg` | high | Issue、review、commit、交付规则;WEGOV1 后采用自动化优先、受控测试域、自建留存说明和 WACP3/WREAD1/WADM1/WARCH1 前置门禁 | | `QA-GATE` | `docs/测试规约与回归门禁.md` | 测试验收 | 测试和回归门禁事实源 | `CURRENT` | qa | `QAF8,GOV8,WPROC1,WPROC2,WAPC2FLIVE,WCBK1,WEGOV1` | 回归脚本/Playwright | none | 2026-05-19 | `rg` | high | 测试计划、DONE 门禁、企微三层门禁、自动化优先、非自审、无完整 sandbox 假设、WREAD1 真机可读性和 WARCH1 留存验收门禁 | | `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,WHMSLIVE,WOUA,WAPI,WRRA,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1` | quick_validate | none | 2026-05-19 | `quick_validate.py` | medium | 每轮交付操作入口;企微/OA 后续先读 API 能力目录、Secret 矩阵、路线图、WEGOV1 自建留存边界和 WCBK1 真实回调证据,不得跳过 WACP3/WREAD1/WADM1/WARCH1 直接做考勤审批镜像 | -| `REQ-WF` | `docs/需求-统一审批中心规约.md` | 需求事实源 | 审批模块规约 | `CURRENT` | product/backend | `AP6,WF8,WFOC,DBWFOC,WFDG,WOUA,WAPI,WRRA,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1` | workflow 回归 | none | 2026-05-19 | `rg` | high | OA 主办审批、企微主办 HR/考勤审批、OA 自建留存、真实回调事件证据、WACP3/WREAD1/WADM1/WARCH1 前置和 OA 应急接管边界 | +| `SKILL-HYB` | `.agents/skills/hyb-oa-delivery/SKILL.md` | Skill | 项目交付 Skill | `CURRENT` | dev | `GOV8,DG8,WFDG,WDRG,WCP1,WCPC,WHMS,WHMSLIVE,WOUA,WAPI,WRRA,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1,WACP3,WACP3R` | quick_validate | none | 2026-05-19 | `quick_validate.py` | medium | 每轮交付操作入口;企微/OA 后续先读 API 能力目录、Secret 矩阵、路线图、WEGOV1 自建留存边界、WCBK1 真实回调证据和 WACP3R 补偿拉取 findings,不得跳过 WREAD1/WADM1/WARCH1 直接做考勤审批镜像 | +| `REQ-WF` | `docs/需求-统一审批中心规约.md` | 需求事实源 | 审批模块规约 | `CURRENT` | product/backend | `AP6,WF8,WFOC,DBWFOC,WFDG,WOUA,WAPI,WRRA,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1,WACP3,WACP3R` | workflow 回归 | none | 2026-05-19 | `rg` | high | OA 主办审批、企微主办 HR/考勤审批、OA 自建留存、真实回调事件证据、WACP3R 补偿拉取 findings、WREAD1/WADM1/WARCH1 前置和 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,WHMSLIVE,WOUA,WAPI,WRRA,WRV1,WRA1,WMSG1,WAPC1,WAPC2,WPROC1,WPROC2,WAPC2F,WAPC2FLIVE,WCBK1,WEGOV1` | live smoke/真机反馈/Issue CSV | none | 2026-05-19 | `rg` | high | 企微优先承担 HR/考勤员工日常审批和人事/打卡能力;WEGOV1 固定 OA 自建留存和受控测试域;采购、合同、项目、报销和财务继续 OA 主办 | @@ -133,7 +133,7 @@ | `docs/报销发票附件规则.md` | 当前事实源 | 报销、发票、附件细则 | | `docs/需求-报销发票OCR规约.md` | 当前事实源 | OCR 和报销模块规约 | | `docs/需求-企业微信基础设施规约.md` | 当前事实源 | 企业微信入口、身份、消息、deeplink、企微主办域、OA 自建留存和应急兜底 | -| `docs/需求-请假考勤修正规约.md` | 当前事实源 | 请假、补卡、考勤修正、WAPC2/WAPC2FLIVE/WCBK1 证据、WEGOV1 自建留存路线和 WACP3/WREAD1/WADM1/WARCH1 后续门禁 | +| `docs/需求-请假考勤修正规约.md` | 当前事实源 | 请假、补卡、考勤修正、WAPC2/WAPC2FLIVE/WCBK1/WACP3R 证据、WEGOV1 自建留存路线和 WREAD1/WADM1/WARCH1 后续门禁 | | `docs/需求-采购费用审批规约.md` | 当前事实源 | 采购和费用审批 | | `docs/需求-合同附件归档规约.md` | 当前事实源 | 合同台账和附件归档 | | `docs/需求-项目轻管理规约.md` | 当前事实源 | 项目轻管理 | @@ -202,12 +202,12 @@ - `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 配置复跑、WHMSLIVE、WAPI、WRRA、WOUA-FIX、WRA1、WMSG1、WAPC1、WAPC2、WPROC1、WPROC2、WAPC2F dry-run、WAPC2FLIVE、WCBK1 代码部署和 WEGOV1 路线治理均已完成,当前 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。WAPI 已将企微官方 API 能力目录、Secret 矩阵和运行优先路线落为当前事实源:通讯录读取使用 `WECOM_CONTACT_SECRET` 和 `user/list_id`,成员详情只作可选富化,人事助手/花名册、打卡、消息、OAuth 和审批读取默认使用 `WECOM_AGENT_SECRET`,`WECOM_CHECKIN_SECRET` 只作专用打卡 override,`WECOM_HR_ASSISTANT_SECRET` 不参与默认读取;后续企微能力不清楚时先查官方 API 和 [企微 API 能力目录](./企微API能力目录.md),不得靠运行时多个 Secret 试错。WOUA-FIX 已按用户确认执行受控写入并复检:7 个 OA active 缺企微测试账号软归档,`T0000` seed 复活问题修正,`SMOKE201` 测试主管和待办副作用已转交,最终 WOUA 报告 `/app/artifacts/qa-flow/wecom-oa-user-consistency-20260518T161716Z/summary.json` 为 `PASS_WITH_FINDINGS`,但 OA active 5、企微 active 5、匹配 5、OA active 缺企微 0;剩余 5 个企微缺字段先接受不补,`HRWDTEST-20260517214548` 归档绑定保留审计。WRV1 原始报告 `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T173402Z/summary.json` 曾因同步开关误阻断;WRA1 已修正并公网复跑,报告 `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T180506Z/summary.json` 为 `PASS_WITH_CONFIG_GAPS`,入口/OAuth、Secret 矩阵、OA active 绑定、通讯录、人事助手、消息 dry-run 和打卡只读链路均通过,打卡记录 `readable_sync_disabled`。WMSG1 已证明企业微信应用消息和 Deeplink 可用;WAPC1 已固定首批审批模板(请假、补卡、外出、加班)、低风险 `sp_no`、真实回调配置项、验签/解密/幂等/重试和补偿拉取准入清单;WAPC2 已新增请假/补卡模板详情和审批详情只读 POC runner;WPROC1 已固定后续自动化优先、非自审和三层门禁,WPROC2 已将其升级为 `check-process-contract` process gate;WAPC2F 已新增审批样件 runner并公网 dry-run 通过;WAPC2FLIVE 已在用户批准后修正 `create_template` payload,创建 OA-POC 请假/补卡测试模板和低风险测试审批单,报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`。WCBK1 已新增并部署只读 `GET/POST /api/wecom/approval/callback`、验签/AES 解密/归一化服务和 synthetic runner,远端报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 为 `PASS_CALLBACK_URL_VERIFIED`;`SMOKE101` 同意现有 OA-POC 补卡测试单后复跑 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`。WEGOV1 固定混合架构:HR/考勤日常流程优先复用企业微信,OA 做自建数据留存、审计、入口、消息和应急兜底;采购、费用、合同、项目、报销、付款、AP、代账交接、审计和高敏附件继续 OA 主办。考勤/审批镜像、OA 应急接管、恢复回写和 RuleOps 尚未实现;补偿拉取、审批可读性、自建留存/镜像数据模型、最小历史留存和 HR 写接口仍需后续独立合同处理;不得跳过 WACP3、WREAD1、WADM1、WARCH1 直接进入 `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 配置复跑、WHMSLIVE、WAPI、WRRA、WOUA-FIX、WRA1、WMSG1、WAPC1、WAPC2、WPROC1、WPROC2、WAPC2F dry-run、WAPC2FLIVE、WCBK1 代码部署、WEGOV1 路线治理和 WACP3/WACP3R 补偿拉取 POC 均已完成,当前 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。WAPI 已将企微官方 API 能力目录、Secret 矩阵和运行优先路线落为当前事实源:通讯录读取使用 `WECOM_CONTACT_SECRET` 和 `user/list_id`,成员详情只作可选富化,人事助手/花名册、打卡、消息、OAuth 和审批读取默认使用 `WECOM_AGENT_SECRET`,`WECOM_CHECKIN_SECRET` 只作专用打卡 override,`WECOM_HR_ASSISTANT_SECRET` 不参与默认读取;后续企微能力不清楚时先查官方 API 和 [企微 API 能力目录](./企微API能力目录.md),不得靠运行时多个 Secret 试错。WOUA-FIX 已按用户确认执行受控写入并复检:7 个 OA active 缺企微测试账号软归档,`T0000` seed 复活问题修正,`SMOKE201` 测试主管和待办副作用已转交,最终 WOUA 报告 `/app/artifacts/qa-flow/wecom-oa-user-consistency-20260518T161716Z/summary.json` 为 `PASS_WITH_FINDINGS`,但 OA active 5、企微 active 5、匹配 5、OA active 缺企微 0;剩余 5 个企微缺字段先接受不补,`HRWDTEST-20260517214548` 归档绑定保留审计。WRV1 原始报告 `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T173402Z/summary.json` 曾因同步开关误阻断;WRA1 已修正并公网复跑,报告 `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T180506Z/summary.json` 为 `PASS_WITH_CONFIG_GAPS`,入口/OAuth、Secret 矩阵、OA active 绑定、通讯录、人事助手、消息 dry-run 和打卡只读链路均通过,打卡记录 `readable_sync_disabled`。WMSG1 已证明企业微信应用消息和 Deeplink 可用;WAPC1 已固定首批审批模板(请假、补卡、外出、加班)、低风险 `sp_no`、真实回调配置项、验签/解密/幂等/重试和补偿拉取准入清单;WAPC2 已新增请假/补卡模板详情和审批详情只读 POC runner;WPROC1 已固定后续自动化优先、非自审和三层门禁,WPROC2 已将其升级为 `check-process-contract` process gate;WAPC2F 已新增审批样件 runner并公网 dry-run 通过;WAPC2FLIVE 已在用户批准后修正 `create_template` payload,创建 OA-POC 请假/补卡测试模板和低风险测试审批单,报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`。WCBK1 已新增并部署只读 `GET/POST /api/wecom/approval/callback`、验签/AES 解密/归一化服务和 synthetic runner,远端报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 为 `PASS_CALLBACK_URL_VERIFIED`;`SMOKE101` 同意现有 OA-POC 补卡测试单后复跑 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`。WEGOV1 固定混合架构:HR/考勤日常流程优先复用企业微信,OA 做自建数据留存、审计、入口、消息和应急兜底;采购、费用、合同、项目、报销、付款、AP、代账交接、审计和高敏附件继续 OA 主办。WACP3R 已按 `SMOKE002` creator 自动发现请假/补卡 OA-POC 模板并公网复跑补偿拉取,报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`,请假/补卡各拉到 1 条详情,finding 为回调证据文件未持久化。考勤/审批镜像、OA 应急接管、恢复回写和 RuleOps 尚未实现;审批可读性、自建留存/镜像数据模型、最小历史留存和 HR 写接口仍需后续独立合同处理;不得跳过 WREAD1、WADM1、WARCH1 直接进入 `wecom_attendance_approval_mirror_v1`、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1` 或 `wecom_ruleops_v1`。HRWD 已完成 OA 驱动企业微信通讯录同步,并通过 `HRWDTEST-20260517214548` 真实公网 create/update/disable 验证;测试成员按审计要求保留离职/禁用状态。 - WMSG1 已完成企微应用消息实发与 Deeplink 真机验证:远端报告 `/app/artifacts/qa-flow/wecom-runtime-ready-20260518T234431Z/summary.json` 显示 `checks.message.status=OK`、`errcode=0`、`recipientCount=1`,用户确认收到“OA 运行就绪检查”并可点击进入 OA 通知页面;本证据只证明消息和 Deeplink 可用,不放行审批模板、测试 `sp_no`、真实回调或深度镜像。 - WAPC1 已完成企微审批配置准备清单:首批只准备请假、补卡、外出、加班模板;每个模板需准备模板 ID、适用范围、字段项、审批人规则、可见范围和自建应用权限;测试 `sp_no` 必须低风险且不得含采购、合同、报销、发票、银行回单或高敏附件;真实回调 Token/EncodingAESKey 不写入仓库或文档。本证据只代表配置准备口径已固化,不代表真实回调、审批镜像、应急接管、恢复回写或 RuleOps 已实现。 - WAPC2 已完成企微审批模板与低风险 `sp_no` 只读 POC 本地实现、部署和公网只读复跑:范围只包括请假和补卡,固定 `WECOM_AGENT_SECRET`,远端报告为 `PARTIAL_APPROVAL_POC_NEEDS_CONFIG`;本证据只代表模板详情/审批详情只读 runner 已具备且远端 Secret 可用,不代表模板 ID、测试 `sp_no`、真实回调或深度镜像已配置完成。 - WPROC1 已修正企微路线与开发流程工程化门禁:后续默认自动化优先,人工只处理批准、密钥/回调配置、企微后台不可 API 化配置、真机确认和风险拍板;WAPC2F 默认使用 `SMOKE002 -> SMOKE101` 非自审链,`SMOKE101` 不可用时停止问答确认;WEGOV1 后,`wecom_attendance_approval_mirror_v1` 前必须完成 WAPC2F、WAPC2 自动复跑、WCBK1、WACP3、WREAD1、WADM1 和 WARCH1。当前 WAPC2F、WAPC2 自动复跑和 WCBK1 已由 WAPC2FLIVE/WCBK1 完成。 - WPROC2 已新增开发流程自动化门禁:`node scripts/qa/check-process-contract.mjs --baseline` 检查核心事实源和 WAPC2F 合同,`wecom-approval-fixture` profile 检查非自审、Secret 固定、live 双开关、缺配置分类和脱敏边界;该门禁已接入 `scripts/check-minimal.sh`。 - WAPC2F 已实现企微审批 POC 样件自动生成 dry-run:`npm run check:wecom-approval-fixtures` 已部署公网并返回 `PASS_FIXTURE_DRY_RUN_READY`,报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T045001Z/summary.json`。WAPC2FLIVE 已在用户批准后执行 live 创建,报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`;后续不再重复创建样件。 -- WCBK1 已完成企微审批回调只读 POC 的真实事件确认:新增只读回调端点、`wecomCallbackCrypto` 验签/解密/归一化服务、`check:wecom-approval-callback-poc` runner 和 `wecom-callback` process gate;远端 URL 验证报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 为 `PASS_CALLBACK_URL_VERIFIED`,`SMOKE101` 同意现有 OA-POC 补卡测试单后复跑 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`。WEGOV1 后下一步仍是 WACP3 补偿拉取 POC、WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存。 +- WCBK1 已完成企微审批回调只读 POC 的真实事件确认:新增只读回调端点、`wecomCallbackCrypto` 验签/解密/归一化服务、`check:wecom-approval-callback-poc` runner 和 `wecom-callback` process gate;远端 URL 验证报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 为 `PASS_CALLBACK_URL_VERIFIED`,`SMOKE101` 同意现有 OA-POC 补卡测试单后复跑 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`。WEGOV1/WACP3R 后下一步仍是 WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存。 - WEGOV1 已完成企微主办治理与 OA 自建留存路线修正:企微主办域为打卡、请假、补卡、外出、加班、假期余额和人事助手;OA 主办域为报销、采购、合同、项目、付款、发票、银行回单、高敏附件和经营审计;OA 留存域保存企微关键历史、完整外部关联键和必要业务快照;OA 应急域只在企微不可用时人工开启。企业微信自建应用不按完整隔离 sandbox 处理,后续默认采用 `SMOKE002 -> SMOKE101`、`OA-POC` 模板、低风险审批单、synthetic 自动测试、公网 live runner 和少量真机确认。 diff --git a/docs/文档索引.md b/docs/文档索引.md index dbff7ad9..866972e2 100644 --- a/docs/文档索引.md +++ b/docs/文档索引.md @@ -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 -> WHMSLIVE -> WOUA -> WAPI -> WRRA -> WOUA-FIX -> WRV1 -> WRA1 -> WMSG1 -> WAPC1 -> WAPC2 -> WPROC1 -> WPROC2 -> WAPC2F dry-run -> WAPC2FLIVE -> WCBK1 -> WEGOV1。 +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 -> WOUA -> WAPI -> WRRA -> WOUA-FIX -> WRV1 -> WRA1 -> WMSG1 -> WAPC1 -> WAPC2 -> WPROC1 -> WPROC2 -> WAPC2F dry-run -> WAPC2FLIVE -> WCBK1 -> WEGOV1 -> WACP3/WACP3R。 - R6、PC6、PA6、FL6、AP6、RI6、LP6 已完成并部署。 - ME6 自动化、公网视觉矩阵和 `ME6-3` 代表性企业微信真机门禁已完成。 @@ -76,8 +76,8 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M - WAPC2F 是 WPROC2 后的企微审批 POC 样件自动生成 dry-run 合同:新增 `server/src/scripts/check-wecom-approval-fixtures.js` 和 `npm run check:wecom-approval-fixtures`,公网报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T045001Z/summary.json` 为 `PASS_FIXTURE_DRY_RUN_READY`。 - WAPC2FLIVE 是 WAPC2F 后的企微审批 OA-POC 样件 live 创建合同:用户批准后执行 live 窗口,修正 `create_template` payload 为官方 `template_name` + `property` controls 结构;远端报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,请假/补卡测试模板和低风险测试审批单已创建并保留审计,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`;不代表真实回调、补偿拉取、镜像模型或深度镜像已完成。 - WCBK1 是 WAPC2FLIVE 后的企微审批回调只读 POC 合同:已新增只读回调端点、验签/解密/归一化服务、QA runner 和 `wecom-callback` process gate;远端配置真实回调后报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T083422Z/summary.json` 为 `PASS_CALLBACK_URL_VERIFIED`,`SMOKE101` 同意现有 OA-POC 补卡测试单后报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`。本证据不代表补偿拉取、镜像模型或深度镜像已完成。 -- WEGOV1 是 WCBK1 后的企微主办治理与 OA 自建留存路线修正合同:只更新合同和事实源,不改业务代码、不部署、不写 OA/企微数据;固定混合主办边界、OA 自建历史留存、企业微信无完整 sandbox 假设、受控测试域、自动化与人工边界,并把后续顺序调整为 `WACP3 -> WREAD1 -> WADM1 -> WARCH1 -> wecom_attendance_approval_mirror_v1`。 -- WACP3 是 WEGOV1 后的企微审批补偿拉取 POC 合同:新增 `check:wecom-approval-compensation-poc` 和 `getapprovalinfo` 只读封装,公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T112117Z/summary.json` 为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`;远端 Secret 可用,但缺完整请假/补卡模板 ID,未证明补偿拉取 PASS。 +- WEGOV1 是 WCBK1 后的企微主办治理与 OA 自建留存路线修正合同:只更新合同和事实源,不改业务代码、不部署、不写 OA/企微数据;固定混合主办边界、OA 自建历史留存、企业微信无完整 sandbox 假设、受控测试域、自动化与人工边界,并把后续顺序调整为 `WACP3/WACP3R -> WREAD1 -> WADM1 -> WARCH1 -> wecom_attendance_approval_mirror_v1`。 +- WACP3 是 WEGOV1 后的企微审批补偿拉取 POC 合同:新增 `check:wecom-approval-compensation-poc` 和 `getapprovalinfo` 只读封装;初始公网报告缺模板 ID,WACP3R 已改为按 `SMOKE002` creator 自动发现 OA-POC 请假/补卡模板并复跑,公网报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`,补偿拉取和详情读取可用,finding 为回调证据文件未持久化。 ## 当前活跃治理流 @@ -142,7 +142,7 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M | `WAPC2FLIVE` | `issues/2026-05-19_13-24-12-wecom-approval-fixture-live-create-v1.csv` | 当前审批样件 live:OA-POC 请假/补卡测试模板和测试审批单已创建 | 修正 `create_template` payload 后,远端报告 `PASS_FIXTURE_CREATED`,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`;测试模板和审批记录保留审计,只记录脱敏 template_id / `sp_no` 前缀 | 不改公开 API/schema/UI;不接真实回调;不做补偿拉取;不建镜像表;不进入深度镜像 | | `WCBK1` | `issues/2026-05-19_14-11-20-wecom-approval-callback-readonly-poc-v1.csv` | 当前回调只读 POC:真实 URL 和事件已确认 | 新增只读 `GET/POST /api/wecom/approval/callback`、`check:wecom-approval-callback-poc` 和 `wecom-callback` process gate;远端报告 `PASS_CALLBACK_URL_VERIFIED` 后,`SMOKE101` 处理现有 OA-POC 测试单并复跑达到 `PASS_CALLBACK_EVENT_CONFIRMED` | 不改 schema/UI;不建镜像表;不写 OA/企微业务数据;不创建新模板或审批单;后续仍需 WEGOV1/WACP3/WREAD1/WADM1/WARCH1 | | `WEGOV1` | `issues/2026-05-19_18-17-44-wecom-governance-owned-oa-archive-route-v1.csv` | 当前路线治理:企微主办 + OA 自建留存 | 固定 HR/考勤企微主办、财务经营和高敏业务 OA 主办、OA 留存关键企微历史、企业微信受控测试域、自动化与人工边界;后续新增 WREAD1 和 WARCH1 门禁 | docs-only;不改业务代码/API/schema/UI;不部署;不写 OA/企微数据;不进入深度镜像 | -| `WACP3` | `issues/2026-05-19_19-03-06-wecom-approval-compensation-pull-poc-v1.csv` | 当前补偿拉取 POC:runner 已部署,公网缺模板 ID 配置 | 新增 `check:wecom-approval-compensation-poc`,固定 `WECOM_AGENT_SECRET` 只读调用 `getapprovalinfo` 和 `getapprovaldetail`;远端报告为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`,缺 `WECOM_APPROVAL_LEAVE_TEMPLATE_ID` 和 `WECOM_APPROVAL_MISSED_PUNCH_TEMPLATE_ID` | 不新增公开 API/schema/UI;不写 OA/企微数据;不无过滤拉取高风险审批详情;不进入深度镜像 | +| `WACP3/WACP3R` | `issues/2026-05-19_19-03-06-wecom-approval-compensation-pull-poc-v1.csv`、`issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv` | 当前补偿拉取 POC:runner 已部署并自动发现模板复跑 | 新增 `check:wecom-approval-compensation-poc`,固定 `WECOM_AGENT_SECRET` 只读调用 `getapprovalinfo` 和 `getapprovaldetail`;WACP3R 按 `SMOKE002` creator 自动发现 OA-POC 请假/补卡模板,远端报告为 `PASS_WITH_FINDINGS`,finding 为回调证据文件未持久化 | 不新增公开 API/schema/UI;不写 OA/企微数据;不保存完整模板 ID;不无过滤拉取高风险审批详情;不进入深度镜像 | 旧 Issue CSV 不删除、不批量回写、不移动到归档目录。若新治理流替代旧合同,只在新 CSV 的 `Notes` 或本索引说明 supersedes,旧文件保留历史审计语义。 @@ -165,8 +165,8 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M | [海音达OA-MVP需求规格说明书](./海音达OA-MVP需求规格说明书.md) | PRD 主事实源;WAPC2FLIVE 后包含企微审批配置、只读 POC、工程化前置、process gate、请假/补卡样例和深度镜像前置口径 | | [文档事实源状态矩阵](./文档事实源状态矩阵.md) | 文档分类、删除恢复和冲突规则 | | [产品设计规则](./产品设计规则.md) | PC、移动、企业微信 WebView 设计事实源;DG8 后飞书工作台/飞书审批为唯一主 UI/布局参考;DG9 后按页面分层和样板选型 | -| [企微优先开发路线图](./企微优先开发路线图.md) | WDRG/WCP1/WCPC/WHMS/WHMSLIVE/WOUA/WAPI/WRRA/WOUA-FIX/WRV1/WRA1/WMSG1/WAPC1/WAPC2/WPROC1/WPROC2/WAPC2F/WAPC2FLIVE/WCBK1/WEGOV1 后企微优先 HR/考勤改造的阶段顺序、准入/退出门禁、并行规则、禁止跳阶段、API/Secret 口径、运行优先、消息实发、审批配置、只读 POC、process gate、自动样件 live 证据、真实回调事件证据、自建留存、补偿拉取、可读性和模型设计事实源 | -| [企微 API 能力目录](./企微API能力目录.md) | WAPI/WAPC1/WAPC2/WPROC1/WPROC2/WAPC2F/WAPC2FLIVE/WCBK1/WEGOV1 后企微官方 API、Secret 矩阵、权限/可信 IP/回调模板、读写边界、运行优先、审批配置、只读 POC、WAPC2F dry-run、WAPC2FLIVE live 创建、WCBK1 回调真实事件 POC、无完整 sandbox 假设和 WACP3/WREAD1/WADM1/WARCH1 决策事实源 | +| [企微优先开发路线图](./企微优先开发路线图.md) | WDRG/WCP1/WCPC/WHMS/WHMSLIVE/WOUA/WAPI/WRRA/WOUA-FIX/WRV1/WRA1/WMSG1/WAPC1/WAPC2/WPROC1/WPROC2/WAPC2F/WAPC2FLIVE/WCBK1/WEGOV1/WACP3/WACP3R 后企微优先 HR/考勤改造的阶段顺序、准入/退出门禁、并行规则、禁止跳阶段、API/Secret 口径、运行优先、消息实发、审批配置、只读 POC、process gate、自动样件 live 证据、真实回调事件证据、自建留存、补偿拉取、可读性和模型设计事实源 | +| [企微 API 能力目录](./企微API能力目录.md) | WAPI/WAPC1/WAPC2/WPROC1/WPROC2/WAPC2F/WAPC2FLIVE/WCBK1/WEGOV1/WACP3/WACP3R 后企微官方 API、Secret 矩阵、权限/可信 IP/回调模板、读写边界、运行优先、审批配置、只读 POC、WAPC2F dry-run、WAPC2FLIVE live 创建、WCBK1 回调真实事件 POC、无完整 sandbox 假设、补偿拉取自动发现和 WREAD1/WADM1/WARCH1 决策事实源 | | [产品口径](./产品口径.md) | 已拍板产品边界和业务规则;WEGOV1 后包含混合主办、自建留存、受控测试域、后续阶段顺序和深度镜像前置口径 | | [需求 - 统一审批中心规约](./需求-统一审批中心规约.md) | OA 主办审批、企微主办 HR/考勤员工日常审批镜像、催办、超时提醒、审批效率 | | [报销发票附件规则](./报销发票附件规则.md) | 报销、发票、OCR、附件细则 | diff --git a/docs/测试规约与回归门禁.md b/docs/测试规约与回归门禁.md index 54b049f1..e167dde7 100644 --- a/docs/测试规约与回归门禁.md +++ b/docs/测试规约与回归门禁.md @@ -70,7 +70,7 @@ Definition of Done: - 人工只保留批准、密钥/回调配置、企微后台不可 API 化配置、真机确认和风险拍板。 - 若面向公网或企微可测,必须有 `/ready`、runtime smoke、public bundle scan 或对应 live runner 证据。 -高风险企微能力的 POC 顺序固定为:WAPC2F 自动样件 -> WAPC2FLIVE live 创建与 WAPC2 自动复跑 -> WCBK1 回调只读 POC -> WEGOV1 企微主办治理与自建留存路线修正 -> WACP3 补偿拉取 POC -> WREAD1 审批可读性与误审批防护门禁 -> WADM1 自建留存/镜像数据模型设计 -> WARCH1 最小自建历史留存实现 -> `wecom_attendance_approval_mirror_v1`。当前 WAPC2FLIVE 和 WCBK1 均已完成,后续不得跳过补偿、真机可读性、自建留存模型和最小历史留存门禁。真实回调必须先证明验签、解密、幂等和重复投递;补偿拉取必须先证明按时间窗口拿到审批单号并可拉详情;可读性门禁必须确认审批消息、列表、详情页和快捷同意/驳回误操作风险;镜像实现前必须先有字段、状态机、幂等键、索引和隐私保留边界设计。 +高风险企微能力的 POC 顺序固定为:WAPC2F 自动样件 -> WAPC2FLIVE live 创建与 WAPC2 自动复跑 -> WCBK1 回调只读 POC -> WEGOV1 企微主办治理与自建留存路线修正 -> WACP3/WACP3R 补偿拉取 POC -> WREAD1 审批可读性与误审批防护门禁 -> WADM1 自建留存/镜像数据模型设计 -> WARCH1 最小自建历史留存实现 -> `wecom_attendance_approval_mirror_v1`。当前 WAPC2FLIVE、WCBK1 和 WACP3R 均已完成,后续不得跳过真机可读性、自建留存模型和最小历史留存门禁。真实回调必须先证明验签、解密、幂等和重复投递;补偿拉取必须先证明按时间窗口拿到审批单号并可拉详情;可读性门禁必须确认审批消息、列表、详情页和快捷同意/驳回误操作风险;镜像实现前必须先有字段、状态机、幂等键、索引和隐私保留边界设计。 WEGOV1 后的企业微信测试环境口径:不假设自建应用有完整隔离 sandbox。自动化优先覆盖 API、回调、补偿拉取、脱敏报告和 OA 留存校验;人工只确认后台不可 API 化配置、真机收到/点击、审批详情是否看得清、正式写入和应急风险拍板。 diff --git a/docs/海音达OA-MVP需求规格说明书.md b/docs/海音达OA-MVP需求规格说明书.md index c0a1a605..adcf3098 100644 --- a/docs/海音达OA-MVP需求规格说明书.md +++ b/docs/海音达OA-MVP需求规格说明书.md @@ -56,7 +56,7 @@ | 恢复回写层 | OA + 企业微信 API | 企微恢复后由 `wecom_recovery_writeback_v1` 对应急数据执行 dry-run、自动回写、失败重试和冲突清单。 | | 财务主办层 | OA | 报销、PDF 发票 OCR、发票查重、付款批次、银行回单、AP 台账、代账交接继续 OA 主办,不迁移到企微。 | -无痛切换是长期目标,不代表本轮已实现完整替代。完整镜像按域定义:企微主办域镜像到 OA;OA 主办域不反向全量镜像到企微,只发送脱敏标题、业务类型、业务编号、状态和 OA 链接。WEGOV1 后,OA 不重造企业微信完整打卡/考勤/HR 产品,但必须保存企微关键历史、完整外部关联键和必要快照,保证企微不可用时可查看既有数据。后续必须按 `wecom_hr_master_sync_v1`、`runtime_first_wecom_enablement`、`WOUA-FIX / WECOM-RUNTIME-READY-V1`、`WAPC1 审批配置准备`、`WAPC2 请假/补卡只读 POC`、`WAPC2F 自动生成 POC 样件`、`WAPC2FLIVE live 创建与 WAPC2 自动复跑`、`WCBK1 回调只读 POC(真实事件已确认)`、`WEGOV1 企微主办治理与自建留存路线修正`、`WACP3 补偿拉取 POC`、`WREAD1 审批可读性与误审批防护门禁`、`WADM1 自建留存/镜像数据模型设计`、`WARCH1 最小自建历史留存实现`、`wecom_attendance_approval_mirror_v1`(承接旧口径 `wecom_native_approval_mirror_v1`)、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1` 和 `wecom_ruleops_v1` 分阶段拆 Issue CSV。 +无痛切换是长期目标,不代表本轮已实现完整替代。完整镜像按域定义:企微主办域镜像到 OA;OA 主办域不反向全量镜像到企微,只发送脱敏标题、业务类型、业务编号、状态和 OA 链接。WEGOV1 后,OA 不重造企业微信完整打卡/考勤/HR 产品,但必须保存企微关键历史、完整外部关联键和必要快照,保证企微不可用时可查看既有数据。后续必须按 `wecom_hr_master_sync_v1`、`runtime_first_wecom_enablement`、`WOUA-FIX / WECOM-RUNTIME-READY-V1`、`WAPC1 审批配置准备`、`WAPC2 请假/补卡只读 POC`、`WAPC2F 自动生成 POC 样件`、`WAPC2FLIVE live 创建与 WAPC2 自动复跑`、`WCBK1 回调只读 POC(真实事件已确认)`、`WEGOV1 企微主办治理与自建留存路线修正`、`WACP3/WACP3R 补偿拉取 POC`、`WREAD1 审批可读性与误审批防护门禁`、`WADM1 自建留存/镜像数据模型设计`、`WARCH1 最小自建历史留存实现`、`wecom_attendance_approval_mirror_v1`(承接旧口径 `wecom_native_approval_mirror_v1`)、`oa_hr_emergency_mode_v1`、`wecom_recovery_writeback_v1` 和 `wecom_ruleops_v1` 分阶段拆 Issue CSV。 ### 1.5 DBWFOC 数据边界修正 @@ -77,7 +77,7 @@ WFDG 将 DBWFOC 后的产品方向固化为开发前设计门禁。本节只代 | 报销、采购、合同、项目、付款、AP、代账 | OA | 主办提交、审批、附件、导出、付款批次、审计和代账资料 | 只发送脱敏消息和 OA deeplink | 采购单附件、合同正文、报价、供应商资料、发票、银行回单和代账资料不进入企微原生审批或企微附件 | | RuleOps | OA + 企业微信 API | AI 草拟、差异报告、dry-run、人工确认、审计和回滚建议 | 接收经确认的审批模板、打卡规则、排班、假期余额或人事字段配置写入 | AI 不得直接改正式规则;每次写入保存前后快照、确认人、API `errcode` 和失败原因 | -`WECOM-CAPABILITY-POC-V1` / WCPC 已按 `CAN_REUSE_NOW`、`NEEDS_CONFIG`、`NEEDS_API_POC`、`KEEP_OA_PRIMARY`、`NOT_SUPPORTED_BY_API` 输出人事助手、通讯录、打卡、审批、假期余额、回调和权限配置能力矩阵,并达到 HR 主数据镜像准入。WHMS/WHMSLIVE 已完成 HR 主数据镜像实现和受控公网验证;WAPI 已固定 API/Secret 口径并复跑 WOUA;WRRA 后明确 `PASS_WITH_FINDINGS` 不能直接放行深度镜像;WOUA-FIX 已将 7 个缺企微测试账号软归档并复检 `oaActiveMissingInWecom=0`,企微缺字段先接受不补;WMSG1 已证明真实企微应用消息和 Deeplink 可用;WAPC1 已固化审批配置准备清单;WAPC2 已提供请假/补卡只读 POC runner;WAPC2FLIVE 已创建 OA-POC 样件并自动复跑通过;WCBK1 已完成真实回调 URL 验证和审批状态事件确认;WPROC1/WPROC2 已固定自动化优先、非自审、高风险 POC 前置和 process gate;WEGOV1 固定企微主办 + OA 自建留存路线。生产写接口必须单独批准。正式开发顺序为 `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC(真实事件已确认)` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1`(承接旧口径 `wecom_native_approval_mirror_v1`)-> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`。 +`WECOM-CAPABILITY-POC-V1` / WCPC 已按 `CAN_REUSE_NOW`、`NEEDS_CONFIG`、`NEEDS_API_POC`、`KEEP_OA_PRIMARY`、`NOT_SUPPORTED_BY_API` 输出人事助手、通讯录、打卡、审批、假期余额、回调和权限配置能力矩阵,并达到 HR 主数据镜像准入。WHMS/WHMSLIVE 已完成 HR 主数据镜像实现和受控公网验证;WAPI 已固定 API/Secret 口径并复跑 WOUA;WRRA 后明确 `PASS_WITH_FINDINGS` 不能直接放行深度镜像;WOUA-FIX 已将 7 个缺企微测试账号软归档并复检 `oaActiveMissingInWecom=0`,企微缺字段先接受不补;WMSG1 已证明真实企微应用消息和 Deeplink 可用;WAPC1 已固化审批配置准备清单;WAPC2 已提供请假/补卡只读 POC runner;WAPC2FLIVE 已创建 OA-POC 样件并自动复跑通过;WCBK1 已完成真实回调 URL 验证和审批状态事件确认;WACP3R 已自动发现 OA-POC 请假/补卡模板并证明补偿拉取和详情读取可用;WPROC1/WPROC2 已固定自动化优先、非自审、高风险 POC 前置和 process gate;WEGOV1 固定企微主办 + OA 自建留存路线。生产写接口必须单独批准。正式开发顺序为 `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC(真实事件已确认)` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3/WACP3R 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1`(承接旧口径 `wecom_native_approval_mirror_v1`)-> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`。 ### 1.7 WDRG 开发路线图门禁 @@ -128,7 +128,7 @@ WHMS 将企业微信通讯录/人事助手作为 HR 主数据源的读取能力 - 企微不在职状态记录 `needs_offboarding_confirmation`,不自动禁用 OA 账号;离职仍走 OA checklist。 - 已有 OA 员工只更新姓名、部门、职位、直属主管、手机号、邮箱和企微绑定,不覆盖银行账户、身份证、工资、合同附件或历史审批。 -当前状态为已部署并完成受控公网验证:`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。WOUA-FIX 后复检为 OA active 5、企微 active 5、匹配 5、OA active 缺企微 0;剩余 5 个企微缺字段按用户决策先不补,1 个归档测试绑定保留审计。`wecom_attendance_approval_mirror_v1` 暂缓到 WAPC2F 自动样件、WAPC2 自动复跑、真实回调 POC、补偿拉取 POC、镜像数据模型和打卡细项明确后再另建合同。 +当前状态为已部署并完成受控公网验证:`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。WOUA-FIX 后复检为 OA active 5、企微 active 5、匹配 5、OA active 缺企微 0;剩余 5 个企微缺字段按用户决策先不补,1 个归档测试绑定保留审计。WACP3R 已证明请假/补卡补偿拉取和详情读取可用,但回调证据文件未持久化需在自建留存模型中解决;`wecom_attendance_approval_mirror_v1` 暂缓到 WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型、WARCH1 最小历史留存和打卡细项明确后再另建合同。 --- diff --git a/docs/管理员手册.md b/docs/管理员手册.md index a13a4530..29c40843 100644 --- a/docs/管理员手册.md +++ b/docs/管理员手册.md @@ -1,6 +1,6 @@ # hyb-oa 管理员手册(10 人以下团队版) -**当前状态(2026-05-19 / WACP3)**:R7E、PRELAUNCH、财务闭环、ATTV1、HR-WECOM-DIRECTORY-V1、WAPI、WOUA-FIX、WRV1/WRA1、WMSG1、WAPC1/WAPC2、WPROC1/WPROC2、WAPC2F dry-run、WAPC2FLIVE、WCBK1 和 WEGOV1 均已收口;SYSTEM-COMPLETE-GATE 结论为 `GO_TO_USE`。WAPI 后固定企微 API 能力目录和 Secret 矩阵:通讯录使用 `WECOM_CONTACT_SECRET`,人事助手/打卡/消息/OAuth/审批读取使用 `WECOM_AGENT_SECRET`,运行时代码不得靠多个 Secret 试错。WAPC2FLIVE 已创建 OA-POC 请假/补卡测试模板和低风险测试审批单,报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`;测试模板和审批记录保留审计,不自动删除。WCBK1 已部署只读回调端点和 runner,远端完成回调 URL 验证并收到一条由 `SMOKE101` 同意现有 OA-POC 补卡测试单触发的真实审批状态事件,报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`。WACP3 已新增补偿拉取 runner 并公网只读复跑,报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T112117Z/summary.json` 为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`:远端 `WECOM_AGENT_SECRET` 可用,但缺完整请假/补卡模板 ID 环境变量,尚未证明按窗口拉取审批单号和详情。后续仍需补齐 WACP3 配置复跑、WREAD1 审批可读性门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存,不能直接进入 `wecom_attendance_approval_mirror_v1`。采购、费用、合同、项目、报销、付款、AP、代账交接和高敏附件继续 OA 主办,企业微信只做脱敏提醒和 OA deeplink。公网 `payment_batch_v1=force_on`,`erp_sync=force_off`。公司当前无 ERP/独立财务系统,且 ERP 未来不接入 OA;财务闭环以 OA 内审批、台账、付款批次、银行对公付款回单和月度代账交接为准。 +**当前状态(2026-05-19 / WACP3R)**:R7E、PRELAUNCH、财务闭环、ATTV1、HR-WECOM-DIRECTORY-V1、WAPI、WOUA-FIX、WRV1/WRA1、WMSG1、WAPC1/WAPC2、WPROC1/WPROC2、WAPC2F dry-run、WAPC2FLIVE、WCBK1 和 WEGOV1 均已收口;SYSTEM-COMPLETE-GATE 结论为 `GO_TO_USE`。WAPI 后固定企微 API 能力目录和 Secret 矩阵:通讯录使用 `WECOM_CONTACT_SECRET`,人事助手/打卡/消息/OAuth/审批读取使用 `WECOM_AGENT_SECRET`,运行时代码不得靠多个 Secret 试错。WAPC2FLIVE 已创建 OA-POC 请假/补卡测试模板和低风险测试审批单,报告 `/app/artifacts/qa-flow/wecom-approval-fixtures-20260519T053400Z/summary.json` 为 `PASS_FIXTURE_CREATED`,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`;测试模板和审批记录保留审计,不自动删除。WCBK1 已部署只读回调端点和 runner,远端完成回调 URL 验证并收到一条由 `SMOKE101` 同意现有 OA-POC 补卡测试单触发的真实审批状态事件,报告 `/app/artifacts/qa-flow/wecom-approval-callback-poc-20260519T092648Z/summary.json` 为 `PASS_CALLBACK_EVENT_CONFIRMED`。WACP3R 已新增自动发现模板 ID 路径并公网只读复跑,报告 `/app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json` 为 `PASS_WITH_FINDINGS`:远端 `WECOM_AGENT_SECRET` 可用,已按 `SMOKE002` creator 自动发现请假/补卡 OA-POC 模板并拉取审批详情;finding 是回调证据文件未持久化,需在 WADM1/WARCH1 设计自建留存时解决。后续仍需 WREAD1 审批可读性门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存,不能直接进入 `wecom_attendance_approval_mirror_v1`。采购、费用、合同、项目、报销、付款、AP、代账交接和高敏附件继续 OA 主办,企业微信只做脱敏提醒和 OA deeplink。公网 `payment_batch_v1=force_on`,`erp_sync=force_off`。公司当前无 ERP/独立财务系统,且 ERP 未来不接入 OA;财务闭环以 OA 内审批、台账、付款批次、银行对公付款回单和月度代账交接为准。 ## 1. 适用范围 - 适用于 `small_team_internal` 工作区模式。 @@ -198,7 +198,7 @@ WCP1/WCPC/WHMS 后续推进: 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;公网验证后最终保持 `force_off`。 -5. 正式开发仍按 `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1` 分合同实施;WOUA-FIX 已收口测试账号差异和处理决策,WRV1/WRA1/WMSG1 已验证运行入口、OAuth/绑定、脱敏消息、Deeplink、通讯录、人事助手和打卡读取主链路。WAPC2FLIVE 已生成请假/补卡低风险样例,WCBK1 已证明真实审批回调 URL、验签/解密和事件脱敏留证;补偿拉取、审批可读性、自建留存模型和最小历史留存未明确前,不得进入深度考勤/审批镜像。 +5. 正式开发仍按 `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3/WACP3R 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1` 分合同实施;WOUA-FIX 已收口测试账号差异和处理决策,WRV1/WRA1/WMSG1 已验证运行入口、OAuth/绑定、脱敏消息、Deeplink、通讯录、人事助手和打卡读取主链路。WAPC2FLIVE 已生成请假/补卡低风险样例,WCBK1 已证明真实审批回调 URL、验签/解密和事件脱敏留证,WACP3R 已证明请假/补卡补偿拉取和详情读取可用;审批可读性、自建留存模型和最小历史留存未明确前,不得进入深度考勤/审批镜像。 6. 任何生产写接口、企微规则写入、应急模式开启或恢复回写都必须有单独批准、dry-run 或可审计记录。 WCPC 配置复跑清单: diff --git a/docs/需求-企业微信基础设施规约.md b/docs/需求-企业微信基础设施规约.md index 71febbc8..4e8580fd 100644 --- a/docs/需求-企业微信基础设施规约.md +++ b/docs/需求-企业微信基础设施规约.md @@ -6,7 +6,7 @@ **上级事实源**:[海音达OA-MVP需求规格说明书](./海音达OA-MVP需求规格说明书.md) **相关事实源**:[需求 - 统一审批中心规约](./需求-统一审批中心规约.md)、[企微 API 能力目录](./企微API能力目录.md) -本规约细化企业微信在 `hyb-oa` 中的基础设施边界、入口、免登/绑定、通讯录身份、消息通知、deeplink、打卡、人事助手、原生审批、OA 自建留存、OA 镜像、人工接管和恢复回写要求。WFOC 起产品方向调整为“企微优先 + OA 无痛接管”;DBWFOC 后进一步固定为:HR/考勤员工日常审批优先使用企业微信,OA 做按域镜像、备份接管、财务闭环和审计中台;采购、合同、项目、财务和高敏附件继续由 OA 主办。WAPI 后,所有企微相关开发必须先读取本规约和 [企微 API 能力目录](./企微API能力目录.md),确认官方 API、Secret、权限、可信 IP、回调/模板和读写边界,再拆 Issue CSV。WMSG1 已证明企业微信应用消息和 Deeplink 真机回流可用;WAPC1 后审批进入配置准备清单,WAPC2 后先做请假/补卡模板详情与低风险 `sp_no` 只读 POC;WAPC2F 已实现 OA-POC 样件 dry-run 并公网验证 `PASS_FIXTURE_DRY_RUN_READY`。WAPC2FLIVE 已在用户批准后创建 OA-POC 请假/补卡测试模板和低风险测试审批单,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`。WCBK1 已完成真实回调 URL 验证和一条现有 OA-POC 测试审批单事件确认,公网结论 `PASS_CALLBACK_EVENT_CONFIRMED`。WEGOV1 后固定“企微主办 HR/考勤成熟能力,OA 保存关键历史和外部关联键”的路线。WACP3 已实现补偿拉取只读 runner 并公网复跑,但当前因缺完整请假/补卡模板 ID 环境变量返回 `PARTIAL_COMPENSATION_NEEDS_CONFIG`;后续仍必须补齐补偿拉取 PASS 或真实 findings、完成审批可读性门禁、自建留存/镜像数据模型和最小历史留存,不是直接进入审批镜像实现。 +本规约细化企业微信在 `hyb-oa` 中的基础设施边界、入口、免登/绑定、通讯录身份、消息通知、deeplink、打卡、人事助手、原生审批、OA 自建留存、OA 镜像、人工接管和恢复回写要求。WFOC 起产品方向调整为“企微优先 + OA 无痛接管”;DBWFOC 后进一步固定为:HR/考勤员工日常审批优先使用企业微信,OA 做按域镜像、备份接管、财务闭环和审计中台;采购、合同、项目、财务和高敏附件继续由 OA 主办。WAPI 后,所有企微相关开发必须先读取本规约和 [企微 API 能力目录](./企微API能力目录.md),确认官方 API、Secret、权限、可信 IP、回调/模板和读写边界,再拆 Issue CSV。WMSG1 已证明企业微信应用消息和 Deeplink 真机回流可用;WAPC1 后审批进入配置准备清单,WAPC2 后先做请假/补卡模板详情与低风险 `sp_no` 只读 POC;WAPC2F 已实现 OA-POC 样件 dry-run 并公网验证 `PASS_FIXTURE_DRY_RUN_READY`。WAPC2FLIVE 已在用户批准后创建 OA-POC 请假/补卡测试模板和低风险测试审批单,自动复跑 WAPC2 为 `PASS_APPROVAL_POC`。WCBK1 已完成真实回调 URL 验证和一条现有 OA-POC 测试审批单事件确认,公网结论 `PASS_CALLBACK_EVENT_CONFIRMED`。WEGOV1 后固定“企微主办 HR/考勤成熟能力,OA 保存关键历史和外部关联键”的路线。WACP3R 已自动发现 OA-POC 请假/补卡模板并完成公网补偿拉取复跑,报告为 `PASS_WITH_FINDINGS`;补偿拉取和详情读取可用,finding 为回调证据文件未持久化。后续仍必须完成审批可读性门禁、自建留存/镜像数据模型和最小历史留存,不是直接进入审批镜像实现。 --- @@ -36,7 +36,7 @@ | 通讯录 | 成员创建、读取、更新、禁用或删除 | 近期已验证 OA 写企微;后续改为企微主源同步 OA,OA 保留修复和审计 | `CAN_REUSE_NOW`:HCLT create/update/disable、部门读取和 WCPC 既有在职测试号 `contact.member_read` 均已通过 | | 人事助手 | 员工字段配置、花名册读取、花名册更新 | 作为员工主数据源,驱动 OA 员工、账号、角色、绑定和状态镜像 | `LOCAL_IMPLEMENTED_FOR_READ_SYNC`:字段配置和既有在职测试号花名册读取已通过;WHMS 已本地实现只读同步到 OA;资料更新写接口仍需单独 POC | | 打卡 | 打卡记录、员工规则、日报、月报、排班、补卡、规则管理 | 企微主办规则和采集,OA 同步按域镜像和应急对账 | `CAN_REUSE_NOW_FOR_READ`:WCPC 短窗口打卡记录和规则读取通过;日报/月报/排班等细项留到考勤镜像合同继续验证 | -| 审批 | 模板详情、提交审批、审批状态回调、审批详情、模板创建/更新、批量获取审批单号、假期余额 | HR/考勤员工日常审批企微主办,OA 同步镜像;OA 主办财务、采购、合同、项目和报销审批不迁移 | `WACP3_PARTIAL_COMPENSATION_NEEDS_CONFIG`:WAPC2FLIVE 已创建请假/补卡 OA-POC 样件并复跑通过;WCBK1 已证明审批状态回调 URL 验证、验签、解密和真实事件脱敏留证;WACP3 已实现 `getapprovalinfo` 补偿拉取 runner,但远端缺完整模板 ID 过滤参数,尚未证明 live 拉取通过。镜像数据模型仍需在考勤/审批镜像前补齐 | +| 审批 | 模板详情、提交审批、审批状态回调、审批详情、模板创建/更新、批量获取审批单号、假期余额 | HR/考勤员工日常审批企微主办,OA 同步镜像;OA 主办财务、采购、合同、项目和报销审批不迁移 | `WACP3_PASS_WITH_FINDINGS`:WAPC2FLIVE 已创建请假/补卡 OA-POC 样件并复跑通过;WCBK1 已证明审批状态回调 URL 验证、验签、解密和真实事件脱敏留证;WACP3R 已通过 `getapprovalinfo` 自动发现模板并拉取请假/补卡详情。finding 为回调证据文件未持久化,镜像数据模型和最小留存仍需在考勤/审批镜像前补齐 | | 工作台和消息 | 自建应用入口、应用消息、deeplink | 继续作为 OA 移动入口和通知渠道 | `CAN_REUSE_NOW`;WRV1 新增 `check:wecom-runtime-ready` 对入口、OAuth、脱敏消息 dry-run 和 deeplink 做运行就绪门禁 | | 财务/报销 | 企微不提供本项目需要的 PDF OCR、付款批次、银行回单和代账闭环 | OA 主办 | `KEEP_OA_PRIMARY` | | 真实支付、ERP、图片 OCR、银行流水导入 | 非本路线目标 | 不进入当前路线 | `NOT_IN_SCOPE` | @@ -235,7 +235,7 @@ REQAUD 复核后,ATTV1 已完成统一入口实现,企业微信打卡边界 ## 7.8 WDRG 开发路线图门禁 - WDRG 后,企业微信相关运行时迁移采用“路线图门禁 + 单功能 Issue CSV”,路线图事实源为 [企微优先开发路线图](./企微优先开发路线图.md)。 -- WEGOV1 后阶段顺序调整为 `WECOM-CAPABILITY-POC-V1` -> `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`。 +- WEGOV1 后阶段顺序调整为 `WECOM-CAPABILITY-POC-V1` -> `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3/WACP3R 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` -> `wecom_ruleops_v1`。 - `WECOM-CAPABILITY-POC-V1` 已由 WCPC 收口,WHMS/WHMSLIVE 已完成 HR 主数据镜像实现和受控公网验证;后续不得跳过运行优先门禁和 WOUA 差异处理决策直接开发企微 HR/考勤审批镜像、OA 应急接管、恢复回写或 RuleOps 正式写入。 - 运行优先阶段先利用入口、免登/绑定、脱敏消息、deeplink、通讯录 userid 清单、人事助手花名册读取和打卡读取;WOUA-FIX 已按用户确认软归档 7 个缺企微测试账号,复检 `oaActiveMissingInWecom=0`;剩余企微缺字段先接受不补,归档测试绑定保留审计。WRV1 用 `server/src/scripts/check-wecom-runtime-ready.js` 固化运行优先门禁,WRA1 修正 QA-only 打卡只读门禁,WMSG1 完成真实消息和 Deeplink 真机确认。报告结论只能是 `PASS_RUNTIME_READY`、`PASS_WITH_CONFIG_GAPS` 或 `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`。该结论仍不能直接放行深度镜像,深度考勤/审批镜像需在 WAPC1、WAPC2、WAPC2F/WAPC2FLIVE、WCBK1、WEGOV1、WACP3、WREAD1、WADM1 和 WARCH1 完成后再拆。 - WAPC2F 自动样件默认申请人 `SMOKE002`、审批人 `SMOKE101`;两者必须 active、已绑定企微、可见、不是同一 OA 员工且不是同一企微 userid。`SMOKE101` 不可用时不自动换人,返回配置缺口并问答确认。 diff --git a/docs/需求-统一审批中心规约.md b/docs/需求-统一审批中心规约.md index 80d1b80e..423cf0bc 100644 --- a/docs/需求-统一审批中心规约.md +++ b/docs/需求-统一审批中心规约.md @@ -5,7 +5,7 @@ **状态**:模块级开发规约 **上级事实源**:[海音达OA-MVP需求规格说明书](./海音达OA-MVP需求规格说明书.md) -本规约细化 `hyb-oa` 审批中心和企业微信原生审批镜像的产品边界、角色权限、状态模型、异常规则、留痕要求和验收场景。WFOC 起,审批按主办方分层;DBWFOC 后边界进一步收窄:报销、财务、采购、合同和项目类审批继续由 OA 主办;请假、补卡、外出、加班等 HR/考勤员工日常审批优先由企业微信主办,OA 同步按域镜像并保留自建历史留存、人工接管和恢复回写能力。WMSG1 已验证企业微信应用消息和 Deeplink 回流,WAPC1 后审批镜像前置工作进入配置准备清单阶段,WAPC2 已提供请假/补卡只读 POC runner,WAPC2FLIVE 已自动生成请假/补卡 OA-POC 样件并复跑通过。WCBK1 已完成只读回调 URL 验证和真实审批事件确认,结论为 `PASS_CALLBACK_EVENT_CONFIRMED`。WEGOV1 后明确先利用企微成熟审批和考勤能力,同时由 OA 保存关键历史和外部关联键。WACP3 已实现补偿拉取只读 runner 并公网复跑,当前结论为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`,原因是远端缺请假/补卡完整模板 ID 过滤参数。后续仍必须补齐 WACP3 PASS 或真实 findings、完成 WREAD1 审批可读性与误审批防护门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存,不能直接放行镜像实现。后续审批相关开发必须先从本规约拆分 Issue CSV,再进入技术方案和代码实现。 +本规约细化 `hyb-oa` 审批中心和企业微信原生审批镜像的产品边界、角色权限、状态模型、异常规则、留痕要求和验收场景。WFOC 起,审批按主办方分层;DBWFOC 后边界进一步收窄:报销、财务、采购、合同和项目类审批继续由 OA 主办;请假、补卡、外出、加班等 HR/考勤员工日常审批优先由企业微信主办,OA 同步按域镜像并保留自建历史留存、人工接管和恢复回写能力。WMSG1 已验证企业微信应用消息和 Deeplink 回流,WAPC1 后审批镜像前置工作进入配置准备清单阶段,WAPC2 已提供请假/补卡只读 POC runner,WAPC2FLIVE 已自动生成请假/补卡 OA-POC 样件并复跑通过。WCBK1 已完成只读回调 URL 验证和真实审批事件确认,结论为 `PASS_CALLBACK_EVENT_CONFIRMED`。WEGOV1 后明确先利用企微成熟审批和考勤能力,同时由 OA 保存关键历史和外部关联键。WACP3R 已自动发现 OA-POC 请假/补卡模板并公网复跑到 `PASS_WITH_FINDINGS`:补偿拉取和详情读取可用,finding 是回调证据文件未持久化。后续仍必须完成 WREAD1 审批可读性与误审批防护门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存,不能直接放行镜像实现。后续审批相关开发必须先从本规约拆分 Issue CSV,再进入技术方案和代码实现。 --- @@ -355,7 +355,7 @@ WF8-3、WF8-4、WF8-5 实现前必须基于本设计给技术方案;实现后 - 采购单附件、合同正文、报价、供应商资料、发票、银行回单、代账资料和其他高敏附件不进入企业微信原生审批或企业微信附件;企业微信只做提醒、deeplink 和免登录回流。 - 按域镜像是默认规则:企微主办 HR/考勤域镜像到 OA;OA 主办采购、合同、项目、财务和报销域不反向全量镜像到企微。 - WFDG 后,审批相关页面和接口必须区分 `OA 主办`、`企微镜像` 和 `OA 应急接管`;企微镜像不得被误用为 OA 日常新建入口,OA 应急接管单据必须带 `EMERGENCY` 并进入恢复回写队列。 -- WAPI/WRRA/WOUA-FIX/WAPC1/WAPC2/WPROC1/WEGOV1 后,审批相关运行时迁移必须先读 [企微优先开发路线图](./企微优先开发路线图.md) 和 [企微 API 能力目录](./企微API能力目录.md),按 `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` 的顺序拆单功能 Issue CSV;WOUA-FIX 只收口了用户一致性测试账号差异和处理决策,WRV1/WRA1/WMSG1 只验证入口、OAuth/绑定、脱敏消息、deeplink、通讯录、人事助手、打卡只读主链路和真实消息回流。WAPC1 只固化审批配置准备清单;WAPC2 只读模板详情和低风险 `sp_no` 审批详情;WAPC2FLIVE 只生成 OA-POC 低风险测试样件并自动复跑只读 POC;WCBK1 只证明真实审批状态回调可验签、可解密、可脱敏留证;WEGOV1 只修正混合主办、自建留存和测试治理口径。补偿拉取、可读性门禁、自建留存模型和最小历史留存未明确前,不得直接开发企微审批镜像或恢复回写。 +- WAPI/WRRA/WOUA-FIX/WAPC1/WAPC2/WPROC1/WEGOV1 后,审批相关运行时迁移必须先读 [企微优先开发路线图](./企微优先开发路线图.md) 和 [企微 API 能力目录](./企微API能力目录.md),按 `wecom_hr_master_sync_v1` -> `runtime_first_wecom_enablement` -> `WOUA-FIX / WECOM-RUNTIME-READY-V1` -> `WAPC1 审批配置准备` -> `WAPC2 请假/补卡只读 POC` -> `WAPC2F 自动生成 POC 样件` -> `WAPC2FLIVE live 创建与 WAPC2 自动复跑` -> `WCBK1 回调只读 POC` -> `WEGOV1 企微主办治理与自建留存路线修正` -> `WACP3/WACP3R 补偿拉取 POC` -> `WREAD1 审批可读性与误审批防护门禁` -> `WADM1 自建留存/镜像数据模型设计` -> `WARCH1 最小自建历史留存实现` -> `wecom_attendance_approval_mirror_v1` -> `oa_hr_emergency_mode_v1` -> `wecom_recovery_writeback_v1` 的顺序拆单功能 Issue CSV;WOUA-FIX 只收口了用户一致性测试账号差异和处理决策,WRV1/WRA1/WMSG1 只验证入口、OAuth/绑定、脱敏消息、deeplink、通讯录、人事助手、打卡只读主链路和真实消息回流。WAPC1 只固化审批配置准备清单;WAPC2 只读模板详情和低风险 `sp_no` 审批详情;WAPC2FLIVE 只生成 OA-POC 低风险测试样件并自动复跑只读 POC;WCBK1 只证明真实审批状态回调可验签、可解密、可脱敏留证;WACP3R 只证明补偿拉取和详情读取可用,并发现回调证据文件未持久化;WEGOV1 只修正混合主办、自建留存和测试治理口径。可读性门禁、自建留存模型和最小历史留存未明确前,不得直接开发企微审批镜像或恢复回写。 - WRV1/WRA1 runner `npm run check:wecom-runtime-ready` 中的审批模板、测试 `sp_no` 和真实回调检查只允许输出 `NEEDS_CONFIG`;这类缺口不阻断运行优先主链路的 `PASS_WITH_CONFIG_GAPS`,但必须阻断 `wecom_attendance_approval_mirror_v1`、应急恢复回写和 RuleOps。`WECOM_CHECKIN_SYNC_ENABLED` 只控制正式考勤同步批次,不阻断 QA-only 打卡只读能力探测。 - WMSG1 已证明企业微信应用消息可达和 Deeplink 可进入 OA 通知页;该证据只清除通知链路,不清除审批模板、测试 `sp_no` 或真实回调前置。WAPC1 固化配置准备清单后,WAPC2 先提供请假/补卡模板详情和低风险审批详情只读 POC;WPROC1 后优先用 WAPC2F 自动生成 POC 样件,不默认要求人工手动创建模板或测试单。人工介入限于写入批准、密钥/回调配置、企微后台无法 API 化配置、真机确认和风险拍板。 - 后续企微审批同步的 POC 必须输出 `CAN_REUSE_NOW`、`NEEDS_CONFIG`、`NEEDS_API_POC`、`KEEP_OA_PRIMARY`、`NOT_SUPPORTED_BY_API`,缺模板、回调、Secret 或权限时记录 `SKIP/BLOCKED_BY_EXTERNAL_CONFIG`。 @@ -416,7 +416,7 @@ WAPC2F 是 WAPC2 后的自动化优先补缺阶段,目标是尽量用 QA-only - `WCBK1 回调只读 POC`:已新增只读 `GET/POST /api/wecom/approval/callback` 和 `npm run check:wecom-approval-callback-poc`。公网 synthetic 验签、解密和解析通过后,部署环境完成回调配置并达到 `PASS_CALLBACK_URL_VERIFIED`;`SMOKE101` 随后处理现有 OA-POC 补卡测试单触发真实事件,复跑结论 `PASS_CALLBACK_EVENT_CONFIRMED`,报告只保存脱敏事件证据。 - `WEGOV1 企微主办治理与自建留存路线修正`:固定企微主办域、OA 主办域、OA 留存域和 OA 应急域;明确企业微信没有完整 sandbox 假设,默认使用受控测试域和自动化 runner。 -- `WACP3 补偿拉取 POC`:已新增 `check:wecom-approval-compensation-poc` 和 `getapprovalinfo` 只读封装;公网复跑为 `PARTIAL_COMPENSATION_NEEDS_CONFIG`,缺 `WECOM_APPROVAL_LEAVE_TEMPLATE_ID` 和 `WECOM_APPROVAL_MISSED_PUNCH_TEMPLATE_ID`,尚未拉取 OA-POC 审批详情。补齐模板 ID 后需复跑证明可按时间窗口获取审批单号,并调用 `getapprovaldetail` 拉取详情。 +- `WACP3 补偿拉取 POC`:已新增 `check:wecom-approval-compensation-poc` 和 `getapprovalinfo` 只读封装;WACP3R 公网复跑为 `PASS_WITH_FINDINGS`,已按 `SMOKE002` creator 自动发现请假/补卡 OA-POC 模板并拉取审批详情。finding 为回调证据文件未持久化,需在 WADM1/WARCH1 的自建留存模型中解决。 - `WREAD1 审批可读性与误审批防护门禁`:真机确认审批消息卡片、审批列表和详情页是否足够清楚;若快捷同意/驳回存在高误操作风险,则要求模板调整或该模板回退 OA 主办。 - `WADM1 自建留存/镜像数据模型设计`:先设计字段、状态机、幂等键、索引、隐私保留、审计和迁移回滚方案。 - `WARCH1 最小自建历史留存实现`:先只读保存企微审批、打卡和人事关键快照,保证企微不可用时可查看历史,再进入完整镜像增强。 diff --git a/docs/需求-请假考勤修正规约.md b/docs/需求-请假考勤修正规约.md index 5d181468..28685aed 100644 --- a/docs/需求-请假考勤修正规约.md +++ b/docs/需求-请假考勤修正规约.md @@ -7,7 +7,7 @@ **相关事实源**:[需求 - 统一审批中心规约](./需求-统一审批中心规约.md)、[需求 - 企业微信基础设施规约](./需求-企业微信基础设施规约.md) **体验总依据**:[产品设计规则基线](./产品设计规则.md) -本规约细化请假、补卡、外出、加班与考勤修正的产品要求。WFOC 起,企业微信作为 HR/考勤员工日常审批和打卡规则主操作端;OA 负责按域镜像、应急接管、恢复回写、查询导出和审计。WEGOV1 后进一步明确:企微成熟 HR/考勤功能优先上线,OA 不重造企业微信完整打卡/考勤/HR 产品,但必须做自建历史留存、审计、入口、消息和应急兜底。WAPC2 后,请假和补卡先通过 QA-only runner 只读验证模板详情与低风险 `sp_no` 审批详情;WAPC2FLIVE 已生成 OA-POC 样件并复跑通过;WCBK1 已完成真实回调 URL 验证和一条测试审批事件确认。后续还必须先完成 WACP3 补偿拉取 POC、WREAD1 可读性与误审批防护门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存,这不代表审批镜像已实现。PC 和移动页面体验以产品设计规则基线为依据,不重复定义通用审批链和移动导航规则。 +本规约细化请假、补卡、外出、加班与考勤修正的产品要求。WFOC 起,企业微信作为 HR/考勤员工日常审批和打卡规则主操作端;OA 负责按域镜像、应急接管、恢复回写、查询导出和审计。WEGOV1 后进一步明确:企微成熟 HR/考勤功能优先上线,OA 不重造企业微信完整打卡/考勤/HR 产品,但必须做自建历史留存、审计、入口、消息和应急兜底。WAPC2 后,请假和补卡先通过 QA-only runner 只读验证模板详情与低风险 `sp_no` 审批详情;WAPC2FLIVE 已生成 OA-POC 样件并复跑通过;WCBK1 已完成真实回调 URL 验证和一条测试审批事件确认;WACP3R 已自动发现模板并证明补偿拉取和详情读取可用。后续还必须先完成 WREAD1 可读性与误审批防护门禁、WADM1 自建留存/镜像数据模型设计和 WARCH1 最小历史留存,这不代表审批镜像已实现。PC 和移动页面体验以产品设计规则基线为依据,不重复定义通用审批链和移动导航规则。 --- @@ -49,7 +49,7 @@ REQAUD 复核后,ATTV1 已完成统一入口实现,当前运行时完成度 | 请假对团队状态/日历的影响 | `DONE` | 已批准请假可作为团队状态和日历依据。 | | 企业微信打卡作为原始采集 | `DONE` | 由企业微信侧承载定位、人脸、Wi-Fi、设备和防作弊能力;OA 不重造。 | | 企业微信打卡 API 同步 | `PARTIAL` | 已新增同步批次和企微打卡摘要表;有已授权调用打卡 API 的自建应用 Secret 和企微权限时同步,缺配置时记录 `SKIP`。`WECOM_CHECKIN_SECRET` 可作为单独考勤同步应用的显式覆盖;未配置时复用已授权工作台应用的 `WECOM_AGENT_SECRET`。 | -| 企微 HR/考勤审批镜像 | `POC_CHAIN_PARTIAL_READY` | WAPC2 已新增请假/补卡模板详情和低风险 `sp_no` 审批详情只读 POC;WAPC2FLIVE 已完成自动样件与 WAPC2 自动复跑;WCBK1 已完成真实回调 URL 验证和一条测试审批事件确认。后续 `wecom_attendance_approval_mirror_v1` 仍需外出/加班 POC、WACP3 补偿拉取 POC、WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型和 WARCH1 最小历史留存。 | +| 企微 HR/考勤审批镜像 | `POC_CHAIN_PARTIAL_READY` | WAPC2 已新增请假/补卡模板详情和低风险 `sp_no` 审批详情只读 POC;WAPC2FLIVE 已完成自动样件与 WAPC2 自动复跑;WCBK1 已完成真实回调 URL 验证和一条测试审批事件确认;WACP3R 已证明请假/补卡补偿拉取和详情读取可用,finding 为回调证据文件未持久化。后续 `wecom_attendance_approval_mirror_v1` 仍需外出/加班 POC 或处理决策、WREAD1 可读性门禁、WADM1 自建留存/镜像数据模型和 WARCH1 最小历史留存。 | | 员工补卡申请审批 | `DONE_AS_OA_FALLBACK` | 当前 OA 能提交补卡修正;WFOC 后正常入口迁往企微,OA 仅在应急模式开放并进入恢复回写。 | | 外出申请审批 | `DONE_AS_OA_FALLBACK` | 当前 OA 能提交外出修正;WFOC 后正常入口迁往企微,OA 仅在应急模式开放并进入恢复回写。 | | 加班申请审批 | `DONE_AS_OA_FALLBACK` | 当前 OA 能提交加班修正;WFOC 后正常入口迁往企微,OA 仅在应急模式开放并进入恢复回写。 | @@ -226,11 +226,11 @@ WFOC 后,正常审批规则优先以企业微信审批模板和打卡/假期 - 当前 A0.6:`WAPC2 请假/补卡只读 POC` 已实现 runner;缺模板 ID 或低风险 `sp_no` 时保持 `PARTIAL_APPROVAL_POC_NEEDS_CONFIG`。 - 已完成 A0.7/A0.8/A0.9:`WAPC2F`、`WAPC2FLIVE`、`WAPC2 自动复跑` 和 `WCBK1 回调只读 POC` 已证明请假/补卡 OA-POC 样件、只读审批详情、真实回调 URL、验签/解密和一条真实事件脱敏留证。 - 当前 A0.10:`WEGOV1 企微主办治理与自建留存路线修正`,固定企微主办域、OA 主办域、OA 留存域、OA 应急域、受控测试域和自动化/人工边界。 -- 后续 A0.11:`WACP3 补偿拉取 POC`,证明按时间窗口获取审批单号并用 `getapprovaldetail` 拉详情,能与 WCBK1 回调事件对账。 +- 已完成 A0.11:`WACP3/WACP3R 补偿拉取 POC`,已证明按时间窗口获取审批单号并用 `getapprovaldetail` 拉详情;当前 finding 是 WCBK1 回调证据文件未持久化,需在 WADM1/WARCH1 的自建留存模型中解决。 - 后续 A0.12:`WREAD1 审批可读性与误审批防护门禁`,真机确认请假、补卡、外出、加班在企业微信消息、列表和详情页中是否看得清,快捷同意/驳回是否容易误点。 - 后续 A0.13:`WADM1 自建留存/镜像数据模型设计`,先设计字段、状态机、幂等键、索引、隐私保留和迁移回滚。 - 后续 A0.14:`WARCH1 最小自建历史留存实现`,只读保存企微审批、打卡和人事关键快照,先满足企微不可用时可查看历史。 -- 后续 A1:`wecom_attendance_approval_mirror_v1`,同步企微请假、补卡、外出、加班审批、附件、历史和状态回调;该命名承接旧口径 `wecom_native_approval_mirror_v1`。WAPC2FLIVE 已生成请假/补卡 OA-POC 模板和低风险 `sp_no` 样例;正式开发前仍必须补齐外出/加班样例或处理决策、补偿拉取、可读性门禁、自建留存模型、最小历史留存和必要打卡细项 POC。 +- 后续 A1:`wecom_attendance_approval_mirror_v1`,同步企微请假、补卡、外出、加班审批、附件、历史和状态回调;该命名承接旧口径 `wecom_native_approval_mirror_v1`。WAPC2FLIVE 已生成请假/补卡 OA-POC 模板和低风险 `sp_no` 样例,WACP3R 已证明请假/补卡补偿拉取;正式开发前仍必须补齐外出/加班样例或处理决策、可读性门禁、自建留存模型、最小历史留存和必要打卡细项 POC。 - 后续 A2:企微打卡规则、排班、记录、日报、月报按域镜像,覆盖 Secret/API 权限、短窗口同步、错误码和脱敏证据。 - 后续 A3:`oa_hr_emergency_mode_v1`,管理员人工接管、应急提交、应急审批和恢复队列。 - 后续 A4:`wecom_recovery_writeback_v1`,企微恢复后 dry-run、自动回写、失败重试和冲突清单。 diff --git a/issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv b/issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv new file mode 100644 index 00000000..35ae1f0b --- /dev/null +++ b/issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv @@ -0,0 +1,6 @@ +ID,Title,Description,Acceptance,Test_Method,Tools,Dev_Status,Review1_Status,Regression_Status,Files,Dependencies,Notes +"WACP3R-0","配置复跑合同与边界冻结","建立 WACP3R 合同;本轮不要求人工查模板 ID,改为按测试申请人 SMOKE002 自动只读发现 OA-POC 请假/补卡模板 ID,再复跑 WACP3;不改 Prisma schema、不改前端、不新建企微模板或审批单、不写 OA/企微业务数据。","1) CSV 校验通过;2) 固定 Secret 来源为 WECOM_AGENT_SECRET;3) 不尝试其他 Secret、无 fallback;4) 自动发现只按 SMOKE002 creator 和时间窗口读取低风险 OA-POC 样例;5) 不把完整模板 ID 写入仓库、Issue、文档或聊天。","受影响流程:WACP3 PARTIAL -> 自动发现模板 ID -> WACP3 只读复跑;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv;node scripts/qa/check-process-contract.mjs --issue issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv --profile wecom --json。","python3|node|manual","DONE","DONE","DONE","issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv","[]","固定 Secret 来源:WECOM_AGENT_SECRET;不尝试其他 Secret、无 fallback;不得使用 WECOM_CONTACT_SECRET、WECOM_CHECKIN_SECRET、WECOM_HR_ASSISTANT_SECRET 试错。回滚/清理:删除本合同和事实源回写;本轮无数据库迁移、无 OA/企微写入。" +"WACP3R-1","自动发现模板 ID 能力","扩展 WACP3 QA-only runner,新增 --discover-template-ids 和 --discover-applicant-employee-no=SMOKE002;runner 只读查询 OA 绑定,按企微 creator 拉取审批单号,拉详情后从 OA-POC 请假/补卡名称识别模板 ID,并仅在内存中用于本次复跑。","1) 支持 CLI 自动发现参数;2) OA 侧查询使用 BEGIN READ ONLY;3) 企微侧只调用 getapprovalinfo/getapprovaldetail;4) 报告只输出模板 ID 前缀、sp_no 前缀、计数和状态,不输出完整 template_id、sp_no、userid、token、secret、表单值、附件、评论或原始 payload;5) 仍支持原 --template 手工覆盖路径。","受影响流程:SMOKE002 测试审批 -> 自动发现模板 ID -> 模板过滤补偿拉取;验证步骤:cd server && node --check src/scripts/check-wecom-approval-compensation-poc.js;cd server && node --check src/services/integrations/wecomApproval.js;cd server && npx vitest run tests/unit/scripts/check-wecom-approval-compensation-poc.test.js --reporter=verbose。","node|vitest","DONE","DONE","DONE","server/src/scripts/check-wecom-approval-compensation-poc.js|server/src/services/integrations/wecomApproval.js|server/tests/unit/scripts/check-wecom-approval-compensation-poc.test.js","[""WACP3R-0""]","已本地实现并通过 focused 单测;/tmp/hyb-oa-wacp3-template.env 不再作为必需输入。回滚/清理:移除自动发现参数和相关测试;保留原手工 --template 路径。" +"WACP3R-2","本地门禁","执行合同、process gate、语法、Prisma、focused 单测、文档/skill 和 diff 门禁,确认自动发现路径不影响原 WACP3 行为。","1) validate_issues_csv 通过;2) process baseline 和 issue profile 通过;3) node --check 通过;4) Prisma validate 通过;5) focused vitest 通过;6) 文档审计、skill 校验和 git diff --check 通过。","受影响流程:WACP3R 本地质量门禁;验证步骤:node scripts/qa/check-process-contract.mjs --baseline --json;node scripts/qa/check-process-contract.mjs --issue issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv --profile wecom --json;cd server && npm run prisma:validate;cd server && npx vitest run tests/unit/scripts/check-wecom-approval-compensation-poc.test.js tests/unit/scripts/check-wecom-approval-poc.test.js tests/unit/scripts/check-wecom-approval-callback-poc.test.js --reporter=verbose;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;git diff --check。","node|npm|vitest|python3","DONE","DONE","DONE","N/A","[""WACP3R-1""]","已通过 validate_issues_csv、process baseline、issue profile、node --check、Prisma validate、focused vitest 和 git diff --check;最终文档审计与 skill 校验在提交前复跑。回滚/清理:撤回自动发现代码和本轮事实源回写;本轮无数据库迁移、无 OA/企微写入。" +"WACP3R-3","SYNC_ENV=0 部署与自动发现复跑","本地门禁通过后,以 SYNC_ENV=0 部署,不同步本地 .env;远端执行 WACP3 runner,使用 --discover-template-ids --discover-applicant-employee-no=SMOKE002 和 2026-05-19 起始窗口。","1) SYNC_ENV=0 部署通过;2) /ready 正常;3) 远端执行 npm run check:wecom-approval-compensation-poc -- --live --format=json --start-time=2026-05-19T00:00:00+08:00 --discover-template-ids --discover-applicant-employee-no=SMOKE002;4) 报告为 PASS_COMPENSATION_POC、PASS_WITH_FINDINGS 或真实 SKIP/BLOCKED_BY_EXTERNAL_CONFIG;5) 不无过滤扩大到真实高风险业务单据。","受影响流程:企微审批补偿拉取 -> 自动发现模板 -> 审批详情读取 -> 回调证据脱敏比对;验证步骤:SYNC_ENV=0 bash deploy/trialrun/deploy.sh;远端 npm run check:wecom-approval-compensation-poc -- --live --format=json --start-time=2026-05-19T00:00:00+08:00 --discover-template-ids --discover-applicant-employee-no=SMOKE002;curl -fsS https://oa.hyinda.com/ready。","bash|ssh|curl|npm","DONE","DONE","DONE","external","[""WACP3R-2""]","已以 SYNC_ENV=0 部署并复检 /ready;远端报告 /app/artifacts/qa-flow/wecom-approval-compensation-poc-20260519T115944Z/summary.json 为 PASS_WITH_FINDINGS。templateDiscovery=OK,按 SMOKE002 creator 自动发现请假/补卡模板;请假/补卡各拉到 1 条详情;finding 为 callback_missing_for_pulled_detail,因为回调证据文件未持久化。未修改远端 env,未写 OA/企微数据。回滚/清理:沿用部署回滚流程;本轮无远端 env 修改、无 OA/企微写入可清理。" +"WACP3R-4","事实源回写、状态回填与中文提交","按公网复跑真实结论回写 WACP3R Issue、路线图、API 能力目录、试运行报告、文档索引、事实源矩阵和项目 skill,完成中文提交。","1) 文档记录 WACP3R 真实结论和报告路径;2) 不保存完整模板 ID 或原始企微 payload;3) 文档审计、skill 校验和 git diff --check 通过;4) 中文 commit 为 WACP3R 自动发现并复跑审批补偿拉取。","受影响流程:后续 WREAD1/WADM1/WARCH1 准入判断;验证步骤: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;git diff --check;git commit -m 'WACP3R 自动发现并复跑审批补偿拉取'。","node|python3|git","DONE","DONE","DONE","docs|.agents/skills/hyb-oa-delivery/SKILL.md|issues/2026-05-19_19-42-22-wecom-approval-compensation-config-rerun-v1.csv","[""WACP3R-3""]","事实源已回写为 PASS_WITH_FINDINGS,未把 PARTIAL/SKIP 伪造成 PASS;不保存完整 template_id、sp_no、userid、表单值、附件、评论或原始 payload。下一阶段进入 WREAD1 问答;回滚/清理:git revert 本提交;无远端 env 修改。" diff --git a/server/src/scripts/check-wecom-approval-compensation-poc.js b/server/src/scripts/check-wecom-approval-compensation-poc.js index 7cdc3f49..0ea6631b 100644 --- a/server/src/scripts/check-wecom-approval-compensation-poc.js +++ b/server/src/scripts/check-wecom-approval-compensation-poc.js @@ -3,6 +3,7 @@ require("dotenv/config"); const fs = require("node:fs"); const path = require("node:path"); +const { Pool } = require("pg"); const { getConfig } = require("../config"); const { @@ -18,6 +19,7 @@ const DEFAULT_REPORT_ROOT = path.resolve(__dirname, "../../../artifacts/qa-flow" const DEFAULT_WINDOW_HOURS = 72; const DEFAULT_PAGE_SIZE = 100; const DEFAULT_MAX_PAGES = 10; +const DEFAULT_DISCOVERY_APPLICANT_EMPLOYEE_NO = "SMOKE002"; const REPORT_PRIVACY = "approval counts/status summaries/masked sp_no/template/userid prefixes only; no phone/email/token/secret/full userid/full template_id/full sp_no/form values/attachments/comments/raw payload"; @@ -41,6 +43,9 @@ Options: --end-time= 窗口结束时间,默认当前时间。 --template=leave: 指定请假模板 ID,用于 template_id filter。 --template=missed_punch: 指定补卡模板 ID,用于 template_id filter。 + --discover-template-ids 缺模板 ID 时,按申请人只读发现 OA-POC 模板 ID。 + --discover-applicant-employee-no= + 自动发现使用的 OA 申请人员工号,默认 SMOKE002。 --size=<1..100> 单页审批单号数量,默认 100。 --help 显示帮助。 @@ -99,6 +104,8 @@ function parseArgs(argv) { startTime: "", endTime: "", templates: {}, + discoverTemplateIds: false, + discoverApplicantEmployeeNo: DEFAULT_DISCOVERY_APPLICANT_EMPLOYEE_NO, size: DEFAULT_PAGE_SIZE, maxPages: DEFAULT_MAX_PAGES, help: false, @@ -139,6 +146,13 @@ function parseArgs(argv) { } else if (arg.startsWith("--template=")) { const pair = parseTargetPair(arg.slice("--template=".length), "--template"); options.templates[pair.target] = pair.value; + } else if (arg === "--discover-template-ids") { + options.discoverTemplateIds = true; + } else if (arg === "--discover-applicant-employee-no") { + options.discoverApplicantEmployeeNo = toSafeString(argv[index + 1], 80); + index += 1; + } else if (arg.startsWith("--discover-applicant-employee-no=")) { + options.discoverApplicantEmployeeNo = toSafeString(arg.slice("--discover-applicant-employee-no=".length), 80); } else if (arg === "--size") { options.size = Number(argv[index + 1] || options.size); index += 1; @@ -155,6 +169,9 @@ function parseArgs(argv) { if (!Number.isFinite(options.size) || options.size < 1 || options.size > 100) { throw new Error("--size must be between 1 and 100"); } + if (!options.discoverApplicantEmployeeNo) { + throw new Error("--discover-applicant-employee-no requires non-empty value"); + } options.size = Math.floor(options.size); return options; } @@ -230,6 +247,259 @@ function buildSecretCheck(config) { }; } +function isOaActive(row) { + return row?.status === "active" && !row?.archived; +} + +function sanitizeDiscoveryActor(row) { + if (!row) return null; + return { + employeeNo: row.employeeNo, + status: row.status, + archived: Boolean(row.archived), + hasWecomBinding: Boolean(row.wecomExternalUserId), + wecomUserIdPrefix: row.wecomExternalUserId ? maskApprovalIdentifier(row.wecomExternalUserId) : null, + }; +} + +async function queryApplicantActorRowReadOnly(employeeNo) { + if (!process.env.DATABASE_URL) { + throw new Error("Missing DATABASE_URL"); + } + const pool = new Pool({ connectionString: process.env.DATABASE_URL }); + const client = await pool.connect(); + try { + await client.query("BEGIN READ ONLY"); + const result = await client.query(` + SELECT + e.id::text, + e.employee_no, + e.status::text, + (e.archived_at IS NOT NULL) AS archived, + w.external_user_id AS wecom_external_user_id + FROM employees e + LEFT JOIN wecom_identity_bindings w ON w.employee_id = e.id + WHERE e.employee_no = $1 + LIMIT 1 + `, [employeeNo]); + await client.query("COMMIT"); + const row = result.rows[0]; + if (!row) return null; + return { + id: row.id, + employeeNo: toSafeString(row.employee_no, 80), + status: toSafeString(row.status, 40), + archived: Boolean(row.archived), + wecomExternalUserId: toSafeString(row.wecom_external_user_id, 160), + }; + } catch (error) { + try { + await client.query("ROLLBACK"); + } catch { + // Preserve the original read-only error. + } + throw error; + } finally { + client.release(); + await pool.end(); + } +} + +function inferTargetFromApprovalDetail(detailResult) { + const text = [ + detailResult?.spName, + detailResult?.summary?.spName, + ].filter(Boolean).join(" "); + if (/补卡|missed[_ -]?punch/i.test(text)) return "missed_punch"; + if (/请假|leave/i.test(text)) return "leave"; + return null; +} + +function buildSkippedDiscoveryCheck(reason) { + return { + id: "approval_template_auto_discovery", + status: "SKIPPED", + reason, + applicantEmployeeNo: null, + applicant: null, + pageCount: 0, + spNoCount: 0, + detailCount: 0, + discovered: {}, + }; +} + +async function discoverTemplateIds({ + config, + inputs, + timeWindow, + options, + fetchApprovalInfoListImpl, + fetchApprovalDetailImpl, + queryApplicantActorImpl, +}) { + const missingTargets = inputs.filter((item) => !item.templateId); + if (!options.discoverTemplateIds) { + return buildSkippedDiscoveryCheck("discover_template_ids_not_requested"); + } + if (!options.live) { + return { + ...buildSkippedDiscoveryCheck("live_required_for_template_discovery"), + status: "NEEDS_CONFIG", + }; + } + if (!missingTargets.length) { + return buildSkippedDiscoveryCheck("all_template_ids_already_configured"); + } + + let applicant; + try { + applicant = await queryApplicantActorImpl(options.discoverApplicantEmployeeNo); + } catch (error) { + return { + id: "approval_template_auto_discovery", + status: "NEEDS_CONFIG", + reason: "applicant_lookup_failed", + message: safeMessage(error?.message || error), + applicantEmployeeNo: options.discoverApplicantEmployeeNo, + applicant: null, + pageCount: 0, + spNoCount: 0, + detailCount: 0, + discovered: {}, + }; + } + + const actorGaps = []; + if (!applicant) actorGaps.push("applicant_missing"); + if (applicant && !isOaActive(applicant)) actorGaps.push("applicant_inactive"); + if (applicant && !applicant.wecomExternalUserId) actorGaps.push("applicant_missing_wecom_binding"); + if (actorGaps.length) { + return { + id: "approval_template_auto_discovery", + status: "NEEDS_CONFIG", + reason: "applicant_not_ready", + applicantEmployeeNo: options.discoverApplicantEmployeeNo, + applicant: sanitizeDiscoveryActor(applicant), + gaps: actorGaps, + pageCount: 0, + spNoCount: 0, + detailCount: 0, + discovered: {}, + }; + } + + const pages = []; + const spNos = []; + let cursor = ""; + let pageIndex = 0; + do { + pageIndex += 1; + const result = await fetchApprovalInfoListImpl({ + config, + startTime: timeWindow.startTime, + endTime: timeWindow.endTime, + size: options.size, + nextCursor: cursor, + filters: [{ key: "creator", value: applicant.wecomExternalUserId }], + }); + pages.push({ + page: pageIndex, + status: result.ok ? "OK" : "BLOCKED", + reason: result.ok ? null : result.code, + message: result.message ? safeMessage(result.message) : null, + source: result.tokenSource || "WECOM_AGENT_SECRET", + response: summarizeApiResponse(result.response), + spNoCount: result.spNos?.length || 0, + spNoPrefixes: (result.spNos || []).map(maskApprovalIdentifier), + nextCursorPresent: Boolean(result.nextCursor), + }); + if (!result.ok) { + return { + id: "approval_template_auto_discovery", + status: "BLOCKED", + reason: result.code || "wecom_approval_info_failed", + message: result.message ? safeMessage(result.message) : null, + applicantEmployeeNo: options.discoverApplicantEmployeeNo, + applicant: sanitizeDiscoveryActor(applicant), + pageCount: pages.length, + spNoCount: 0, + detailCount: 0, + pages, + discovered: {}, + }; + } + spNos.push(...(result.spNos || [])); + const nextCursor = toSafeString(result.nextCursor, 160); + cursor = nextCursor && nextCursor !== cursor ? nextCursor : ""; + } while (cursor && pageIndex < options.maxPages); + + const discovered = {}; + const details = []; + for (const spNo of Array.from(new Set(spNos))) { + const detailResult = await fetchApprovalDetailImpl({ config, spNo }); + const target = detailResult.ok ? inferTargetFromApprovalDetail(detailResult) : null; + const templateId = target ? toSafeString(detailResult.templateId, 160) : ""; + details.push({ + status: detailResult.ok ? "OK" : "BLOCKED", + reason: detailResult.ok ? null : detailResult.code || "wecom_approval_detail_failed", + spNoPrefix: maskApprovalIdentifier(spNo), + templateIdPrefix: maskApprovalIdentifier(templateId), + target, + }); + if (target && templateId && !discovered[target]) { + discovered[target] = templateId; + } + } + + const missingAfterDiscovery = missingTargets + .map((item) => item.key) + .filter((key) => !discovered[key]); + + return { + id: "approval_template_auto_discovery", + status: missingAfterDiscovery.length ? "PARTIAL" : "OK", + reason: missingAfterDiscovery.length ? "template_id_not_found_for_all_targets" : null, + applicantEmployeeNo: options.discoverApplicantEmployeeNo, + applicant: sanitizeDiscoveryActor(applicant), + filter: { + key: "creator", + useridPrefix: maskApprovalIdentifier(applicant.wecomExternalUserId), + }, + pageCount: pages.length, + spNoCount: Array.from(new Set(spNos)).length, + detailCount: details.length, + pages, + details, + discoveredTemplatePrefixes: Object.fromEntries( + Object.entries(discovered).map(([key, value]) => [key, maskApprovalIdentifier(value)]), + ), + discovered, + }; +} + +function applyDiscoveredTemplateIds(inputs, discoveryCheck) { + const discovered = discoveryCheck?.discovered || {}; + return inputs.map((input) => { + if (input.templateId || !discovered[input.key]) return input; + return { + ...input, + templateId: discovered[input.key], + templateIdPrefix: maskApprovalIdentifier(discovered[input.key]), + templateSource: `auto_discovery:${discoveryCheck.applicantEmployeeNo}`, + templateMissingEnv: [], + }; + }); +} + +function sanitizeDiscoveryCheck(discoveryCheck) { + if (!discoveryCheck || typeof discoveryCheck !== "object") return discoveryCheck; + return { + ...discoveryCheck, + discovered: undefined, + }; +} + function summarizeApiResponse(response) { if (!response || typeof response !== "object") return null; const summary = {}; @@ -569,13 +839,6 @@ function collectConfigGaps(targetChecks, verificationGaps, evidenceCheck, compar reason: "no_existing_oa_poc_approval_in_window", }); } - if (!verificationGaps.length && pulledCount > 0 && evidenceCheck.status !== "OK") { - gaps.push({ - id: "callback_evidence_missing", - status: "NEEDS_CONFIG", - reason: "no_wcbk1_callback_evidence_available_for_compare", - }); - } return gaps; } @@ -623,13 +886,23 @@ async function executeCompensationPoc(options, deps = {}) { const timeWindow = buildTimeWindow(options, generatedAt); const inputs = buildInputs(options, env); const secretCheck = buildSecretCheck(config); - const targetChecks = await runTargetChecks({ + const discoveryCheck = await discoverTemplateIds({ config, inputs, timeWindow, options, fetchApprovalInfoListImpl: deps.fetchApprovalInfoListImpl || fetchWecomApprovalInfoList, fetchApprovalDetailImpl: deps.fetchApprovalDetailImpl || fetchWecomApprovalDetail, + queryApplicantActorImpl: deps.queryApplicantActorImpl || queryApplicantActorRowReadOnly, + }); + const resolvedInputs = applyDiscoveredTemplateIds(inputs, discoveryCheck); + const targetChecks = await runTargetChecks({ + config, + inputs: resolvedInputs, + timeWindow, + options, + fetchApprovalInfoListImpl: deps.fetchApprovalInfoListImpl || fetchWecomApprovalInfoList, + fetchApprovalDetailImpl: deps.fetchApprovalDetailImpl || fetchWecomApprovalDetail, }); const evidenceCheck = await buildEvidenceCheck({ config, @@ -642,6 +915,12 @@ async function executeCompensationPoc(options, deps = {}) { reason: "run_with_--live_for_public_readonly_gate", }]; const mainBlockers = collectMainBlockers(secretCheck, targetChecks); + if (discoveryCheck.status === "BLOCKED") { + mainBlockers.push({ + id: discoveryCheck.id, + reason: discoveryCheck.reason || "approval_template_auto_discovery_blocked", + }); + } const configGaps = collectConfigGaps(targetChecks, verificationGaps, evidenceCheck, compareCheck); const conclusion = evaluateConclusion({ mainBlockers, configGaps, compareCheck }); @@ -656,6 +935,7 @@ async function executeCompensationPoc(options, deps = {}) { targets: APPROVAL_POC_TARGETS.map((item) => item.key), writeBehavior: "read-only only; no OA writes, no WeCom writes, no template creation, no approval submission", liveRead: Boolean(options.live), + autoDiscovery: Boolean(options.discoverTemplateIds), deepMirror: "not_started", nextStage: "WREAD1", }, @@ -668,9 +948,11 @@ async function executeCompensationPoc(options, deps = {}) { }])), pageSize: options.size, maxPages: options.maxPages, + discoveryApplicantEmployeeNo: options.discoverTemplateIds ? options.discoverApplicantEmployeeNo : null, }, checks: { secretMatrix: secretCheck, + templateDiscovery: sanitizeDiscoveryCheck(discoveryCheck), targets: targetChecks, callbackEvidence: { ...evidenceCheck, @@ -734,6 +1016,7 @@ module.exports = { buildSecretCheck, buildTimeWindow, compareCallbackEvidence, + discoverTemplateIds, evaluateConclusion, executeCompensationPoc, parseArgs, diff --git a/server/src/services/integrations/wecomApproval.js b/server/src/services/integrations/wecomApproval.js index 6b9c62cd..20109767 100644 --- a/server/src/services/integrations/wecomApproval.js +++ b/server/src/services/integrations/wecomApproval.js @@ -98,6 +98,7 @@ function summarizeApprovalPayload(payload) { return { spNoPrefix: maskApprovalIdentifier(info.sp_no ?? payload?.sp_no), templateIdPrefix: maskApprovalIdentifier(info.template_id), + spName: toSafeString(info.sp_name ?? info.spName, 120) || null, spStatus: info.sp_status == null ? null : toSafeString(info.sp_status, 40), applyFieldCount: contents.length, applyFieldTypeCounts: countBy(contents, controlType), @@ -358,6 +359,8 @@ async function fetchWecomApprovalDetail({ message: null, tokenSource: token.tokenSource, response: sanitizeApprovalApiResponse(result.payload), + templateId: toSafeString(result.payload?.info?.template_id ?? result.payload?.info?.templateId, 160), + spName: toSafeString(result.payload?.info?.sp_name ?? result.payload?.info?.spName, 120), summary: summarizeApprovalPayload(result.payload), }; } catch (error) { diff --git a/server/tests/unit/scripts/check-wecom-approval-compensation-poc.test.js b/server/tests/unit/scripts/check-wecom-approval-compensation-poc.test.js index ea646c36..6032120a 100644 --- a/server/tests/unit/scripts/check-wecom-approval-compensation-poc.test.js +++ b/server/tests/unit/scripts/check-wecom-approval-compensation-poc.test.js @@ -89,11 +89,15 @@ describe("check-wecom-approval-compensation-poc", () => { "--size=50", "--template=leave:tpl-leave", "--template=missed_punch:tpl-missed", + "--discover-template-ids", + "--discover-applicant-employee-no=SMOKE002", ]); expect(options.live).toBe(true); expect(options.format).toBe("json"); expect(options.size).toBe(50); + expect(options.discoverTemplateIds).toBe(true); + expect(options.discoverApplicantEmployeeNo).toBe("SMOKE002"); expect(options.templates).toEqual({ leave: "tpl-leave", missed_punch: "tpl-missed", @@ -218,6 +222,120 @@ describe("check-wecom-approval-compensation-poc", () => { expect(report.checks.targets.every((item) => item.status === "DRY_RUN_READY")).toBe(true); }); + it("auto-discovers missing template IDs by applicant creator without leaking full identifiers", async () => { + const discoveredLeaveTemplateId = "tpllv-auto-discovered-leave-sensitive"; + const discoveredMissedTemplateId = "tplmp-auto-discovered-missed-sensitive"; + const fetchApprovalInfoListImpl = vi.fn(async ({ filters }) => { + if (filters[0].key === "creator") { + return { + ok: true, + tokenSource: "WECOM_AGENT_SECRET", + response: { + errcode: 0, + spNoCount: 2, + spNoPrefixes: [maskApprovalIdentifier("sp-discovery-leave"), maskApprovalIdentifier("sp-discovery-missed")], + }, + spNos: ["sp-discovery-leave", "sp-discovery-missed"], + nextCursor: "", + }; + } + return { + ok: true, + tokenSource: "WECOM_AGENT_SECRET", + response: { + errcode: 0, + spNoCount: 1, + spNoPrefixes: [maskApprovalIdentifier(`${filters[0].value}-sp`)], + }, + spNos: [`${filters[0].value}-sp`], + nextCursor: "", + }; + }); + const fetchApprovalDetailImpl = vi.fn(async ({ spNo }) => { + if (spNo === "sp-discovery-leave") { + return { + ok: true, + tokenSource: "WECOM_AGENT_SECRET", + templateId: discoveredLeaveTemplateId, + spName: "OA-POC-请假-2026-05-19", + summary: detailSummary(spNo, { templateIdPrefix: maskApprovalIdentifier(discoveredLeaveTemplateId) }), + response: { errcode: 0, spStatus: "2" }, + }; + } + if (spNo === "sp-discovery-missed") { + return { + ok: true, + tokenSource: "WECOM_AGENT_SECRET", + templateId: discoveredMissedTemplateId, + spName: "OA-POC-补卡-2026-05-19", + summary: detailSummary(spNo, { templateIdPrefix: maskApprovalIdentifier(discoveredMissedTemplateId) }), + response: { errcode: 0, spStatus: "2" }, + }; + } + return { + ok: true, + tokenSource: "WECOM_AGENT_SECRET", + summary: detailSummary(spNo, { + templateIdPrefix: spNo.startsWith(discoveredLeaveTemplateId) + ? maskApprovalIdentifier(discoveredLeaveTemplateId) + : maskApprovalIdentifier(discoveredMissedTemplateId), + }), + response: { errcode: 0, spStatus: "2" }, + }; + }); + + const report = await executeCompensationPoc(baseOptions({ + templates: {}, + discoverTemplateIds: true, + discoverApplicantEmployeeNo: "SMOKE002", + }), { + config: baseConfig(), + env: {}, + generatedAt: "2026-05-20T00:00:00.000Z", + queryApplicantActorImpl: vi.fn(async () => ({ + employeeNo: "SMOKE002", + status: "active", + archived: false, + wecomExternalUserId: SENSITIVE_USER_ID, + })), + fetchApprovalInfoListImpl, + fetchApprovalDetailImpl, + readCallbackEvidenceImpl: vi.fn(async () => [ + { + callbackKind: "approval_status_change", + spStatus: "2", + statusLabel: "已通过", + spNoPrefix: maskApprovalIdentifier(`${discoveredLeaveTemplateId}-sp`), + }, + { + callbackKind: "approval_status_change", + spStatus: "2", + statusLabel: "已通过", + spNoPrefix: maskApprovalIdentifier(`${discoveredMissedTemplateId}-sp`), + }, + ]), + }); + + expect(report.status).toBe("PASS_COMPENSATION_POC"); + expect(fetchApprovalInfoListImpl.mock.calls[0][0].filters).toEqual([ + { key: "creator", value: SENSITIVE_USER_ID }, + ]); + expect(fetchApprovalInfoListImpl.mock.calls[1][0].filters).toEqual([ + { key: "template_id", value: discoveredLeaveTemplateId }, + ]); + expect(fetchApprovalInfoListImpl.mock.calls[2][0].filters).toEqual([ + { key: "template_id", value: discoveredMissedTemplateId }, + ]); + const serialized = JSON.stringify(report); + expect(serialized).not.toContain(discoveredLeaveTemplateId); + expect(serialized).not.toContain(discoveredMissedTemplateId); + expect(serialized).not.toContain(SENSITIVE_USER_ID); + expect(report.checks.templateDiscovery.discoveredTemplatePrefixes).toEqual({ + leave: maskApprovalIdentifier(discoveredLeaveTemplateId), + missed_punch: maskApprovalIdentifier(discoveredMissedTemplateId), + }); + }); + it("pulls approval numbers and details, then passes when callback evidence matches", async () => { const fetchApprovalInfoListImpl = vi.fn(async ({ filters }) => ({ ok: true, @@ -310,6 +428,34 @@ describe("check-wecom-approval-compensation-poc", () => { expect(report.checks.callbackCompare.findings.map((item) => item.id)).toContain("callback_status_mismatch"); }); + it("treats missing callback evidence after successful detail pull as findings", async () => { + const report = await executeCompensationPoc(baseOptions({ + templates: { leave: SENSITIVE_TEMPLATE_ID, missed_punch: "tpl-missed-punch" }, + }), { + config: baseConfig(), + env: {}, + generatedAt: "2026-05-20T00:00:00.000Z", + fetchApprovalInfoListImpl: vi.fn(async () => ({ + ok: true, + tokenSource: "WECOM_AGENT_SECRET", + response: { errcode: 0, spNoCount: 1 }, + spNos: [SENSITIVE_SP_NO], + nextCursor: "", + })), + fetchApprovalDetailImpl: vi.fn(async ({ spNo }) => ({ + ok: true, + tokenSource: "WECOM_AGENT_SECRET", + summary: detailSummary(spNo, { spStatus: "2" }), + response: { errcode: 0, spStatus: "2" }, + })), + readCallbackEvidenceImpl: vi.fn(async () => []), + }); + + expect(report.status).toBe("PASS_WITH_FINDINGS"); + expect(report.configGaps.map((item) => item.id)).not.toContain("callback_evidence_missing"); + expect(report.checks.callbackCompare.findings.map((item) => item.id)).toContain("callback_missing_for_pulled_detail"); + }); + it("classifies WeCom API errors as BLOCKED_BY_EXTERNAL_CONFIG", async () => { const report = await executeCompensationPoc(baseOptions({ templates: { leave: SENSITIVE_TEMPLATE_ID },