修复企微通讯录生产导入兼容性(07-26-internal-ops-recovery-baseline)
ci-e2e / e2e (push) Waiting to run
ci-minimal / check-minimal (push) Waiting to run

这个提交包含在:
2026-07-27 18:31:04 +08:00
父节点 cf63d3cb1b
当前提交 4886f9b081
共修改 7 个文件,包含 84 行新增和 8 行删除
+25
查看文件
@@ -251,6 +251,9 @@ business role assignment -> separate administrator-audited operation
- CLI: `npm run import:wecom-directory-export -- --input=- --dry-run`.
- Apply: `WECOM_DIRECTORY_EXPORT_APPLY=1 ... --input=- --apply
--actor-employee-no=<employee-no>`.
- Binary stdin reader: `fs.readFileSync(0)`; do not assume
`fs.promises.readFile(0)` accepts a numeric file descriptor on the production
Node runtime.
- User API and frontend employee/user types expose `phone: string | null`;
create/update accepts an omitted or explicit `null` phone.
@@ -266,6 +269,9 @@ business role assignment -> separate administrator-audited operation
supplied valid phone participates in update and unique-conflict checks.
- The XLSX is accepted only from stdin and defaults to dry-run. Apply requires
both `--apply` and `WECOM_DIRECTORY_EXPORT_APPLY=1`, plus an active actor.
- Read the XLSX directly from fd 0 without a temporary file. A runtime that
rejects the stdin read must stop before Prisma sync; do not fall back to
persisting the workbook on the host or in the container.
- CLI output contains counts and categories only. The workbook, full local path,
names, accounts, phones, emails, departments and raw rows must not enter Git,
Trellis artifacts or reports.
@@ -283,6 +289,9 @@ business role assignment -> separate administrator-audited operation
`duplicate_values`; error output contains counts only.
- Existing OA unique-field or binding conflict -> conflict; no automatic merge.
- `--apply` without confirmation env or active actor -> refuse before sync.
- Promise-based stdin fd read returns `ERR_INVALID_ARG_TYPE` on the deployed
Node runtime -> no sync/write; use the fd-compatible reader and rerun dry-run
before requesting apply approval.
- Migration rollback with any `phone IS NULL` row -> stop; do not fill fake
values merely to restore `NOT NULL`.
@@ -293,6 +302,8 @@ business role assignment -> separate administrator-audited operation
only aggregate counts.
- Base: a later export still omits a member phone; the member's existing OA
phone is preserved.
- Base: the local and production Node versions differ; the same binary stdin
workbook parses through `fs.readFileSync(0)` without a temporary file.
- Bad: write an empty string or shared placeholder, use personal email in place
of the required enterprise email for bulk identity, or auto-grant a business
role during import.
@@ -302,6 +313,8 @@ business role assignment -> separate administrator-audited operation
- Prisma validation plus a migration review proving only `DROP NOT NULL`.
- Unit tests for instruction rows/Chinese headers, five-present/one-missing,
malformed phone, missing enterprise email and duplicate account/phone/email.
- Unit regression asserts the CLI stdin helper calls `fs.readFileSync(0)`;
production dry-run must prove aggregate parsing/sync counts before apply.
- Route/service tests for create/update/import `null`, non-empty unique checks,
OAuth missing phone and empty-source preservation of an existing phone.
- Frontend typecheck/build and displays that render a clear empty-phone label.
@@ -323,3 +336,15 @@ phone: source.phone || "00000000000"
phone: source.phone || null
// Existing employee updates omit `phone` entirely when the source is empty.
```
#### Wrong
```js
const workbook = await fs.promises.readFile(0);
```
#### Correct
```js
const workbook = fs.readFileSync(0);
```