修复企微通讯录生产导入兼容性(07-26-internal-ops-recovery-baseline)
这个提交包含在:
@@ -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);
|
||||
```
|
||||
|
||||
在新工单中引用
屏蔽一个用户