归档 Wave3 前端体验任务(05-28-frontend-ux-wave3-business-mobile)

这个提交包含在:
2026-05-29 08:12:35 +08:00
父节点 246969a058
当前提交 1e1e0fecd6
共修改 42 个文件,包含 2 行新增和 2 行删除
@@ -0,0 +1,4 @@
{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend validation entrypoint."}
{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Required frontend build, visual and mobile/detail checks."}
{"file": ".trellis/spec/hyb-oa/index.md", "reason": "hyb-oa spec entrypoint for governance, fact-source routing and frontend acceptance boundaries."}
{"file": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/wave3-gap-audit.md", "reason": "Scope and expected checks for Wave3 refresh."}
@@ -0,0 +1,4 @@
{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend task entrypoint and project-specific spec routing."}
{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Wave0-2 shell/header baseline plus detail/mobile surface rules."}
{"file": ".trellis/spec/hyb-oa/index.md", "reason": "hyb-oa spec entrypoint, including product fact-source routing and frontend authority."}
{"file": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/wave3-gap-audit.md", "reason": "Current Wave3 gap audit and page scope decisions."}
@@ -0,0 +1,69 @@
# Implementation Plan
## Current Decision
This task is a Wave3 refresh after the newer Wave0-2 baseline, not a blank Wave3 rebuild.
## Recommended Implementation Order
1. PC detail surfaces:
- `WorkflowTaskDetailPage`
- `ProjectDetailPage`
- `ContractsRegistryPage`
2. Mobile key surfaces:
- `MobileApprovalsPage`
- `MobileNotificationsPage`
- `MobileReimbursementsPage`
- `MobileReimbursementDetailPage`
- `MobilePurchaseRequestDetailPage` only for deeplink/detail consistency
3. Test baseline:
- update focused Wave3 Playwright spec
- run typecheck/build/design rules/trellis gates
4. Deployment:
- only after user approval
- run trialrun deploy and public checks
## Guardrails
- No backend, schema, permission or workflow-state changes.
- Do not remove existing business actions.
- Do not add a new contract detail route in this task.
- For mobile pages, no desktop tables, no horizontal overflow and no sticky action overlap.
## Completed Implementation
2026-05-29:
- Refreshed PC workflow task detail with a next-action command panel, clearer title/subtitle and evidence-oriented side meta.
- Refreshed PC project detail with a current project command panel covering next action, closure, risk and evidence counts.
- Refreshed PC contract registry with lifecycle summary metrics, expiring-contract command area and ledger row styling.
- Refreshed mobile approvals, notifications, reimbursements, reimbursement detail and purchase detail with mobile focus summaries.
- Cleaned residual forbidden UI copy in Sidebar and Portal home so the UI design rule scan has zero findings.
- Extended `client/tests/e2e/pc-detail-mobile-visual-wave3.spec.ts` to cover project detail, contract registry, mobile reimbursement detail and mobile purchase detail.
## Local Verification
- `cd client && npm run build` passed on 2026-05-29.
- `cd client && npx playwright test tests/e2e/pc-detail-mobile-visual-wave3.spec.ts --workers=1 --reporter=list` passed: 2 tests.
- `node scripts/qa/check-ui-design-rules.mjs` passed with 0 findings.
- `python3 ./.trellis/scripts/task.py validate 05-28-frontend-ux-wave3-business-mobile` passed.
- `node scripts/qa/check-trellis-governance.mjs` passed.
- `git diff --check` passed.
## Public Deployment Verification
2026-05-29 deployment and public verification were completed after explicit user approval.
- Commit deployed: `2b5fd6b 重构 Wave3 详情与移动体验(05-28-frontend-ux-wave3-business-mobile)`.
- Deploy command: `SYNC_ENV=0 LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash deploy/trialrun/deploy.sh`.
- Deploy script passed env contract, remote build, migration check, config seed, trialrun seed, `/ready`, external dependency smoke, runtime smoke and public bundle copy scan.
- Deploy note: rsync reported one non-fatal leftover historical `artifacts/qa-flow/...` directory that could not be deleted because it was non-empty.
- Public readiness passed: `run-live-smoke-readiness.sh` wrote report `research/postdeploy-20260529-wave3-public/live-smoke-readiness/`.
- Readiness note: pending OCR was skipped because the local script environment did not include `DATABASE_URL`; live OCR sample execution itself passed with the expected duplicate/same-invoice style sample result.
- OAOPS1 passed: `run-oa-real-use-daily.sh` wrote report `research/postdeploy-20260529-wave3-public/oa-real-use-daily/` with status `PASS_OA_REAL_USE_DAILY_READY`.
- OAOPS1 steps passed: public ready, live smoke env, live readiness, OA-only smoke readiness, feature flags, authenticated read-only probe, mobile entry matrix, WeCom rendering matrix, WeCom entry and report privacy smoke.
- Public automation stayed read-only: no business writes, file uploads, exports, WeCom writes, payment execution or database reset.
## Spec Update Decision
No `.trellis/spec/` update is needed for this task. The deployed change did not add or change API signatures, schema, env keys, permission rules, Enterprise WeChat write behavior or deployment command contracts; the existing `deployment-trialrun.md`, `docs-and-evidence.md` and `security-privacy.md` specs already cover the evidence and privacy handling used here.
@@ -0,0 +1,174 @@
# 前端体验 Wave3 业务详情与移动关键页
## Goal
在已部署的 Wave0-2 全局体验基线之后,复审并补齐 Wave3 业务详情页和移动关键页,让用户从列表、通知、企业微信或移动首页进入具体业务后,仍然看到统一、简洁、可办理的 OA 工作界面。
## What I Already Know
- 用户要求继续推进全站前端体验改进。
- Wave0-2 已完成并部署:全局壳、导航、Topbar、页头基线、登录、工作台、审批中心、报销列表/详情和通知中心已按新基线整改。
- 历史任务 `.trellis/tasks/archive/2026-05/05-27-pc-detail-mobile-visual-wave3/` 已做过一轮 Wave3,但发生在最新 Wave0-2 新基线之前。
- 当前不应重复从零改造,而应做“Wave3 复审与补齐”。
- `frontend-design` 是视觉与交互设计裁决来源。
- 面向用户可测试的页面改动,只有部署和公网检查通过后才可告知用户测试。
## Scope
本任务实施 Wave3 刷新,不改后端业务模型:
- PC 业务详情/详情相邻页面:
- `/workflow/tasks/:taskId`
- `/projects/:projectId`
- `/contracts-registry`
- 移动关键页:
- `/mobile`
- `/mobile/approvals`
- `/mobile/approvals/:taskId`
- `/mobile/notifications`
- `/mobile/reimbursements`
- `/mobile/reimbursements/:reimbursementId`
- `/mobile/purchase-requests/:purchaseRequestId` 作为通知/移动深链一致性补充目标
- 测试与证据:
- 更新或扩展 `client/tests/e2e/pc-detail-mobile-visual-wave3.spec.ts`
- 覆盖 PC 详情、移动列表/详情、企业微信 WebView 关键视口
## Product Direction
- Tone:精密、克制、面向办理的 quiet command surface。
- PC 详情页优先回答:当前是什么状态、我下一步做什么、动作有什么后果、证据在哪里。
- 移动页优先回答:从消息/首页进入后,我是否能少步骤查看、补材料、审批或回到列表。
- 合同和项目相关页面强调:摘要、生命周期、负责人、风险/归档位置,不上传或暴露涉密正文。
## Requirements
### R1. PC 详情页一致性
- 复用 Wave0-2 的全局壳、页头和 detail surface 规则。
- 审批详情强化当前节点、申请摘要、可执行动作、依据/附件、处理历史。
- 项目详情强化项目状态、下一步动作、执行摘要、风险/交付/归档分组,减少局部卡片噪音。
- 合同台账强化生命周期、到期预警、项目关联和导出边界,不新增合同正文存储能力。
### R2. 移动关键路径
- 移动审批列表/详情保持离线、草稿、同步和 sticky action 现有能力;只优化信息层级和操作分组。
- 移动报销列表/详情突出状态、金额、发票/附件完整性和当前可做动作。
- 移动通知保持“事件收件箱”定位,点击应直达业务详情、审批任务或给出可解释提示。
- 企业微信 WebView 场景不得出现 PC 表格、横向滚动、按钮文字挤压或底部操作遮挡内容。
### R3. 文案与操作降噪
- 删除或收纳解释系统实现的文案。
- 保留业务下一步、风险、不可逆操作、敏感附件和导出边界提示。
- 不可用动作要解释原因;高风险动作继续保留确认。
### R4. 验证和发布
- 本地必须通过 typecheck/build 和 focused Playwright。
- 移动/企微相关改动至少覆盖 390x844,并尽量覆盖现有企业微信多视口矩阵。
- 若部署给用户测试,必须跑部署脚本和公网 readiness/只读巡检。
## Implementation Plan
### Step 1. Gap-driven edits
- 不全量重写大页面。
- 优先改页面首屏、状态摘要、命令区、移动详情头和空态/错误态。
- 保留所有现有 API 调用、权限判断、确认弹窗和 mutation 行为。
### Step 2. Shared pattern reuse
- PC 使用 `page-header-shell`、`detail-workspace-grid`、`detail-command-panel`、`detail-fact-grid`、`detail-evidence-card`、`detail-action-stack` 等既有类。
- 移动使用 `mobile-focus-card`、`mobile-command-surface`、`mobile-list-card--focus`、`mobile-list-card--unread`、sticky action 既有模式。
### Step 3. Focused test refresh
- 扩展 `pc-detail-mobile-visual-wave3.spec.ts` 的 mock 页面检查。
- 按影响范围补跑移动入口、企业微信渲染、UI 设计规则和 Trellis 治理检查。
## Acceptance Criteria
- [x] Wave3 gap audit 已记录,且明确区别于历史 Wave3。
- [x] PC 审批详情、项目详情、合同台账完成新基线后的体验补齐。
- [x] 移动审批、移动通知、移动报销及移动深链目标完成新基线后的体验补齐。
- [x] 没有改变后端 API、权限模型、审批状态机、数据库 schema、企业微信配置或公网真实数据。
- [x] `cd client && npm run typecheck` 通过。
- [x] `cd client && npm run build` 通过。
- [x] Focused Playwright 覆盖 Wave3 页面并通过。
- [x] `node scripts/qa/check-ui-design-rules.mjs` 通过。
- [x] `python3 ./.trellis/scripts/task.py validate 05-28-frontend-ux-wave3-business-mobile` 通过。
- [x] `node scripts/qa/check-trellis-governance.mjs` 和 `git diff --check` 通过。
- [x] 若部署给用户测试,已完成公网部署与公网检查并记录证据。
## Implementation Result
2026-05-29 本地实施完成:
- PC 审批详情新增当前状态/下一步命令区,并保留原审批动作确认、历史和转审能力。
- PC 项目详情新增项目办理焦点,提前展示收口、风险、交付、合同和资料引用边界。
- PC 合同台账改为生命周期台账入口,新增可见合同、生效中、草稿、归档和 30 天到期摘要,不新增合同详情路由或正文上传能力。
- 移动审批、通知、报销列表、报销详情和采购详情新增首屏办理焦点,保留离线草稿、sticky action、原有权限与 mutation 行为。
- 侧边栏和首页去除 UI 规则命中的口语化文案,保持工作台文案更克制。
本地验证完成;公网部署与公网检查已在用户批准后完成。
## Post-Deploy Evidence
2026-05-29 用户批准后完成公网部署与公网验证:
- 部署提交:`2b5fd6b 重构 Wave3 详情与移动体验(05-28-frontend-ux-wave3-business-mobile)`
- 部署命令:`SYNC_ENV=0 LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash deploy/trialrun/deploy.sh`
- 部署结果:环境契约、远端构建、迁移检查、配置种子、试运行种子、`/ready`、外部依赖 smoke、运行时 smoke、公网页面文案扫描均通过。
- 非阻断部署备注:rsync 曾提示一个历史 `artifacts/qa-flow/...` 目录非空未删除;不影响构建、服务启动或公网检查。
- 公网 readiness:`run-live-smoke-readiness.sh` 结果为 `PASS`,报告目录 `research/postdeploy-20260529-wave3-public/live-smoke-readiness/`。
- readiness 备注:`pending OCR` 因本地未向脚本提供 `DATABASE_URL` 被按规则记录为 `SKIP`;真实 OCR 样票检查通过脚本执行,样票返回重复/同票类结果,符合该样例预期。
- OAOPS1 日常真实使用准备巡检:`run-oa-real-use-daily.sh` 结果为 `PASS_OA_REAL_USE_DAILY_READY`,报告目录 `research/postdeploy-20260529-wave3-public/oa-real-use-daily/`。
- OAOPS1 覆盖:公网 ready、live smoke env、live readiness、OA-only smoke readiness、功能开关、认证只读探针、移动入口矩阵、企业微信移动渲染矩阵、企业微信入口、报告隐私 smoke。
- 自动化边界:本轮公网巡检为只读自动化;没有真实业务写入、附件上传、导出、企业微信写入、真实付款或数据库重置。
## Test Plan
```bash
cd client && npm run typecheck
cd client && npm run build
cd client && npx playwright test tests/e2e/pc-detail-mobile-visual-wave3.spec.ts --workers=1 --reporter=list
node scripts/qa/check-ui-design-rules.mjs
python3 ./.trellis/scripts/task.py validate 05-28-frontend-ux-wave3-business-mobile
node scripts/qa/check-trellis-governance.mjs
git diff --check
```
Deployment gate, only after approval:
```bash
SYNC_ENV=0 LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash deploy/trialrun/deploy.sh
LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-live-smoke-readiness.sh
OAOPS1_REPORT_DIR=.trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-<date>-wave3-public \
LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-oa-real-use-daily.sh
```
## Out Of Scope
- 不新增合同详情路由或合同正文/附件库。
- 不改后端接口、Prisma schema、审批规则、权限、通知投递、企业微信 OAuth、SMTP 或生产配置。
- 不执行真实付款、ERP 写入、企业微信写入、数据库重置或未授权真实业务写入。
- 不恢复差旅主线能力。
- 不把移动端改造成完整 PC 后台。
## Research References
- `research/wave3-gap-audit.md` — 确认历史 Wave3 已存在,本任务应做新基线后的复审补齐。
- `.trellis/tasks/archive/2026-05/05-27-pc-detail-mobile-visual-wave3/` — 历史 Wave3 范围、实现记录和测试基线。
## Technical Notes
- 重点代码区域:
- `client/src/pages/WorkflowTaskDetailPage.tsx`
- `client/src/pages/ProjectDetailPage.tsx`
- `client/src/pages/ContractsRegistryPage.tsx`
- `client/src/pages/MobileApprovalsPage.tsx`
- `client/src/pages/MobileNotificationsPage.tsx`
- `client/src/pages/MobileReimbursementsPage.tsx`
- `client/src/pages/MobileReimbursementDetailPage.tsx`
- `client/src/pages/MobilePurchaseRequestDetailPage.tsx`
- `client/tests/e2e/pc-detail-mobile-visual-wave3.spec.ts`
@@ -0,0 +1,50 @@
{
"checkedAt": "2026-05-29T00:02:40.411Z",
"baseUrl": "https://oa.hyinda.com",
"liveSmokeReady": true,
"liveSmoke": {
"LIVE_SMOKE_ADMIN_IDENTIFIER": true,
"LIVE_SMOKE_ADMIN_PASSWORD": true,
"LIVE_SMOKE_EMPLOYEE_IDENTIFIER": true,
"LIVE_SMOKE_EMPLOYEE_PASSWORD": true
},
"liveSmokeOptional": {
"LIVE_EXPECT_WECOM_STATUS": true,
"LIVE_SMOKE_MANAGER_IDENTIFIER": true,
"LIVE_SMOKE_MANAGER_PASSWORD": true,
"LIVE_SMOKE_FINANCE_IDENTIFIER": true,
"LIVE_SMOKE_FINANCE_PASSWORD": true
},
"liveOcrReady": true,
"liveOcr": {
"userReady": true,
"invoiceSampleReady": true,
"invoiceFileProvided": true,
"invoiceFileReady": true,
"invoiceBatchDirProvided": false,
"invoiceBatchDirReady": false,
"allowDuplicate": true
},
"missing": [],
"publicReady": {
"ok": true,
"status": 200
},
"wecomConfig": {
"ok": true,
"status": 200,
"statusText": "ready",
"entryEnabled": true,
"oauthEnabled": true,
"defaultReturnTo": "/mobile",
"loginUrl": "/api/auth/wecom/login?returnTo=%2Fmobile"
},
"authCapabilities": {
"ok": true,
"status": 200,
"emailDeliveryReady": true,
"emailDeliveryReasons": [],
"emailLoginCodeEnabled": true,
"passwordResetEnabled": true
}
}
@@ -0,0 +1,7 @@
Running 1 test using 1 worker
[live-ocr] {"alias":"SAMPLE-PDF-001","status":"ocr_failed","durationMs":810,"transport":"ui","timings":{"uploadMs":810,"terminalWaitMs":0},"reasonCategory":"duplicate_or_same_invoice","fieldHits":{"invoiceId":false,"invoiceCodeOrNumber":false,"sellerName":false,"totalAmount":false,"invoiceDate":false}}
✓ 1 tests/e2e/manual/live-invoice-ocr.spec.ts:8:1 › 手工 live 腾讯 OCR 辅助复核:真实 VAT 发票上传后进入可处理状态 (6.4s)
1 passed (10.0s)
@@ -0,0 +1,14 @@
>>> 探活 live /ready: https://oa.hyinda.com/ready
>>> 执行 live smoke Playwright
> [email protected] test:e2e:live
> playwright test tests/e2e/live-smoke.spec.ts
Running 3 tests using 1 worker
✓ 1 tests/e2e/live-smoke.spec.ts:43:3 › live smoke › 公网基础探活与企微配置状态 (3.2s)
✓ 2 tests/e2e/live-smoke.spec.ts:64:3 › live smoke › 管理员只读网页 smoke (12.1s)
✓ 3 tests/e2e/live-smoke.spec.ts:106:3 › live smoke › 员工只读网页 smoke (11.0s)
3 passed (30.0s)
@@ -0,0 +1 @@
[public-bundle-copy] base=https://oa.hyinda.com scanned=91 focused=2 findings=0
@@ -0,0 +1,12 @@
{
"issueId": null,
"baseURL": "https://oa.hyinda.com",
"commit": "2b5fd6b",
"checkedAt": "2026-05-29T00:03:33.176Z",
"status": "PASS",
"mode": "live-smoke-readiness",
"reportDir": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/live-smoke-readiness",
"reportRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/live-smoke-readiness",
"groups": null,
"notes": "公网 /ready、public bundle、pending OCR、live smoke 和真实 OCR 可用性检查;缺少凭据或样票时按脚本规则记录 SKIP。"
}
@@ -0,0 +1,129 @@
{
"mode": "oaops1-authenticated-readonly-probe",
"status": "PASS",
"baseUrl": "https://oa.hyinda.com",
"checkedAt": "2026-05-29T00:07:05.933Z",
"readOnly": true,
"duplicateRoleChecks": "employee/finance/payment/AP are covered by oa-only-smoke-readiness to avoid repeated login throttling",
"roles": {
"admin": {
"status": "PASS",
"reason": null,
"maskedIdentifier": "sm***om"
}
},
"checks": [
{
"id": "portal",
"role": "admin",
"path": "/api/portal/home",
"domain": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "workflow-tasks",
"role": "admin",
"path": "/api/workflow/tasks?page=1&pageSize=5",
"domain": "approval",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 0,
"total": 0
}
},
{
"id": "reimbursements",
"role": "admin",
"path": "/api/reimbursements?page=1&pageSize=5",
"domain": "reimbursement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 33
}
},
{
"id": "reimbursement-summary",
"role": "admin",
"path": "/api/reimbursements/stats/summary",
"domain": "reimbursement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"totalCount": 33,
"avgProcessingDays": 0
}
},
{
"id": "invoice-pool",
"role": "admin",
"path": "/api/invoice-pool?page=1&pageSize=5",
"domain": "invoice_ocr",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 46
}
},
{
"id": "purchase-requests",
"role": "admin",
"path": "/api/purchase-requests?page=1&pageSize=5",
"domain": "procurement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 0,
"total": 0
}
},
{
"id": "contracts-registry",
"role": "admin",
"path": "/api/contracts-registry",
"domain": "contracts",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 6,
"total": null
}
},
{
"id": "projects",
"role": "admin",
"path": "/api/projects?page=1&pageSize=5",
"domain": "projects",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 4,
"total": null
}
},
{
"id": "audit-logs",
"role": "admin",
"path": "/api/audit-logs?page=1&pageSize=5",
"domain": "audit",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 2197
}
}
],
"boundaries": {
"noBusinessWrites": true,
"noExportsByDefault": true,
"noFileUploads": true,
"noWeComWrites": true,
"noRealPaymentExecution": true
}
}
@@ -0,0 +1,129 @@
{
"mode": "oaops1-authenticated-readonly-probe",
"status": "PASS",
"baseUrl": "https://oa.hyinda.com",
"checkedAt": "2026-05-29T00:07:05.933Z",
"readOnly": true,
"duplicateRoleChecks": "employee/finance/payment/AP are covered by oa-only-smoke-readiness to avoid repeated login throttling",
"roles": {
"admin": {
"status": "PASS",
"reason": null,
"maskedIdentifier": "sm***om"
}
},
"checks": [
{
"id": "portal",
"role": "admin",
"path": "/api/portal/home",
"domain": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "workflow-tasks",
"role": "admin",
"path": "/api/workflow/tasks?page=1&pageSize=5",
"domain": "approval",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 0,
"total": 0
}
},
{
"id": "reimbursements",
"role": "admin",
"path": "/api/reimbursements?page=1&pageSize=5",
"domain": "reimbursement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 33
}
},
{
"id": "reimbursement-summary",
"role": "admin",
"path": "/api/reimbursements/stats/summary",
"domain": "reimbursement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"totalCount": 33,
"avgProcessingDays": 0
}
},
{
"id": "invoice-pool",
"role": "admin",
"path": "/api/invoice-pool?page=1&pageSize=5",
"domain": "invoice_ocr",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 46
}
},
{
"id": "purchase-requests",
"role": "admin",
"path": "/api/purchase-requests?page=1&pageSize=5",
"domain": "procurement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 0,
"total": 0
}
},
{
"id": "contracts-registry",
"role": "admin",
"path": "/api/contracts-registry",
"domain": "contracts",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 6,
"total": null
}
},
{
"id": "projects",
"role": "admin",
"path": "/api/projects?page=1&pageSize=5",
"domain": "projects",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 4,
"total": null
}
},
{
"id": "audit-logs",
"role": "admin",
"path": "/api/audit-logs?page=1&pageSize=5",
"domain": "audit",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 2197
}
}
],
"boundaries": {
"noBusinessWrites": true,
"noExportsByDefault": true,
"noFileUploads": true,
"noWeComWrites": true,
"noRealPaymentExecution": true
}
}
@@ -0,0 +1,9 @@
{
"name": "authenticated-readonly-probe",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/authenticated-readonly-probe.log",
"checkedAt": "2026-05-29T00:07:06.007Z"
}
@@ -0,0 +1,64 @@
{
"checkedAt": "2026-05-29T00:05:59.296Z",
"baseUrl": "https://oa.hyinda.com",
"status": "PASS",
"readOnly": true,
"results": [
{
"flagKey": "payment_batch_v1",
"expectedState": "force_on",
"status": "PASS",
"item": {
"flagKey": "payment_batch_v1",
"overrideMode": "force_on",
"rolloutType": "global",
"version": 17,
"envEnabled": true,
"effectiveEnabled": true,
"effectiveReason": "flag_force_on_global"
}
},
{
"flagKey": "erp_sync",
"expectedState": "force_off",
"status": "PASS",
"item": {
"flagKey": "erp_sync",
"overrideMode": "force_off",
"rolloutType": "global",
"version": 2,
"envEnabled": true,
"effectiveEnabled": false,
"effectiveReason": "flag_force_off"
}
},
{
"flagKey": "attendance_v1",
"expectedState": "disabled",
"status": "PASS",
"item": {
"flagKey": "attendance_v1",
"overrideMode": "force_on",
"rolloutType": "global",
"version": 85,
"envEnabled": false,
"effectiveEnabled": false,
"effectiveReason": "env_hard_off"
}
},
{
"flagKey": "attendance_unified_v1",
"expectedState": "enabled",
"status": "PASS",
"item": {
"flagKey": "attendance_unified_v1",
"overrideMode": "force_on",
"rolloutType": "global",
"version": 83,
"envEnabled": true,
"effectiveEnabled": true,
"effectiveReason": "flag_force_on_global"
}
}
]
}
@@ -0,0 +1,9 @@
{
"name": "live-feature-flags",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-feature-flags.log",
"checkedAt": "2026-05-29T00:05:59.428Z"
}
@@ -0,0 +1,45 @@
>>> [live-readiness] 环境与公网入口检查
[live-smoke-env] base=https://oa.hyinda.com
[live-smoke-env] publicReady=true status=200
[live-smoke-env] wecom=ready entry=true oauth=true
[live-smoke-env] authCapabilities=true emailDelivery=true
[live-smoke-env] liveSmokeReady=true
[live-smoke-env] liveOcrReady=true
>>> [live-readiness] /ready: https://oa.hyinda.com
>>> [live-readiness] 公网资源文案扫描
[public-bundle-copy] base=https://oa.hyinda.com scanned=91 focused=2 findings=0
>>> [live-readiness] pending OCR 扫描
[pending-ocr][SKIP] missing DATABASE_URL
>>> [live-readiness] 执行公网 live smoke
>>> 探活 live /ready: https://oa.hyinda.com/ready
>>> 执行 live smoke Playwright
> [email protected] test:e2e:live
> playwright test tests/e2e/live-smoke.spec.ts
Running 3 tests using 1 worker
(node:4141259) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:4141259) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
✓ 1 tests/e2e/live-smoke.spec.ts:43:3 › live smoke › 公网基础探活与企微配置状态 (3.0s)
✓ 2 tests/e2e/live-smoke.spec.ts:64:3 › live smoke › 管理员只读网页 smoke (11.2s)
✓ 3 tests/e2e/live-smoke.spec.ts:106:3 › live smoke › 员工只读网页 smoke (10.6s)
3 passed (28.5s)
>>> [live-readiness] 执行真实 OCR 样本复核
Running 1 test using 1 worker
(node:4142054) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:4142054) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
[live-ocr] {"alias":"SAMPLE-PDF-001","status":"ocr_failed","durationMs":1289,"transport":"ui","timings":{"uploadMs":1289,"terminalWaitMs":0},"reasonCategory":"duplicate_or_same_invoice","fieldHits":{"invoiceId":false,"invoiceCodeOrNumber":false,"sellerName":false,"totalAmount":false,"invoiceDate":false}}
✓ 1 tests/e2e/manual/live-invoice-ocr.spec.ts:8:1 › 手工 live 腾讯 OCR 辅助复核:真实 VAT 发票上传后进入可处理状态 (6.2s)
1 passed (10.1s)
[live-readiness][PASS] readiness 检查完成
[live-readiness] report=.trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-smoke-readiness
@@ -0,0 +1,9 @@
{
"name": "live-readiness",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-readiness.log",
"checkedAt": "2026-05-29T00:04:48.504Z"
}
@@ -0,0 +1,50 @@
{
"checkedAt": "2026-05-29T00:03:56.630Z",
"baseUrl": "https://oa.hyinda.com",
"liveSmokeReady": true,
"liveSmoke": {
"LIVE_SMOKE_ADMIN_IDENTIFIER": true,
"LIVE_SMOKE_ADMIN_PASSWORD": true,
"LIVE_SMOKE_EMPLOYEE_IDENTIFIER": true,
"LIVE_SMOKE_EMPLOYEE_PASSWORD": true
},
"liveSmokeOptional": {
"LIVE_EXPECT_WECOM_STATUS": true,
"LIVE_SMOKE_MANAGER_IDENTIFIER": true,
"LIVE_SMOKE_MANAGER_PASSWORD": true,
"LIVE_SMOKE_FINANCE_IDENTIFIER": true,
"LIVE_SMOKE_FINANCE_PASSWORD": true
},
"liveOcrReady": true,
"liveOcr": {
"userReady": true,
"invoiceSampleReady": true,
"invoiceFileProvided": true,
"invoiceFileReady": true,
"invoiceBatchDirProvided": false,
"invoiceBatchDirReady": false,
"allowDuplicate": true
},
"missing": [],
"publicReady": {
"ok": true,
"status": 200
},
"wecomConfig": {
"ok": true,
"status": 200,
"statusText": "ready",
"entryEnabled": true,
"oauthEnabled": true,
"defaultReturnTo": "/mobile",
"loginUrl": "/api/auth/wecom/login?returnTo=%2Fmobile"
},
"authCapabilities": {
"ok": true,
"status": 200,
"emailDeliveryReady": true,
"emailDeliveryReasons": [],
"emailLoginCodeEnabled": true,
"passwordResetEnabled": true
}
}
@@ -0,0 +1,9 @@
{
"name": "live-smoke-env",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-smoke-env.log",
"checkedAt": "2026-05-29T00:03:56.704Z"
}
@@ -0,0 +1,50 @@
{
"checkedAt": "2026-05-29T00:03:57.167Z",
"baseUrl": "https://oa.hyinda.com",
"liveSmokeReady": true,
"liveSmoke": {
"LIVE_SMOKE_ADMIN_IDENTIFIER": true,
"LIVE_SMOKE_ADMIN_PASSWORD": true,
"LIVE_SMOKE_EMPLOYEE_IDENTIFIER": true,
"LIVE_SMOKE_EMPLOYEE_PASSWORD": true
},
"liveSmokeOptional": {
"LIVE_EXPECT_WECOM_STATUS": true,
"LIVE_SMOKE_MANAGER_IDENTIFIER": true,
"LIVE_SMOKE_MANAGER_PASSWORD": true,
"LIVE_SMOKE_FINANCE_IDENTIFIER": true,
"LIVE_SMOKE_FINANCE_PASSWORD": true
},
"liveOcrReady": true,
"liveOcr": {
"userReady": true,
"invoiceSampleReady": true,
"invoiceFileProvided": true,
"invoiceFileReady": true,
"invoiceBatchDirProvided": false,
"invoiceBatchDirReady": false,
"allowDuplicate": true
},
"missing": [],
"publicReady": {
"ok": true,
"status": 200
},
"wecomConfig": {
"ok": true,
"status": 200,
"statusText": "ready",
"entryEnabled": true,
"oauthEnabled": true,
"defaultReturnTo": "/mobile",
"loginUrl": "/api/auth/wecom/login?returnTo=%2Fmobile"
},
"authCapabilities": {
"ok": true,
"status": 200,
"emailDeliveryReady": true,
"emailDeliveryReasons": [],
"emailLoginCodeEnabled": true,
"passwordResetEnabled": true
}
}
@@ -0,0 +1,7 @@
Running 1 test using 1 worker
[live-ocr] {"alias":"SAMPLE-PDF-001","status":"ocr_failed","durationMs":1289,"transport":"ui","timings":{"uploadMs":1289,"terminalWaitMs":0},"reasonCategory":"duplicate_or_same_invoice","fieldHits":{"invoiceId":false,"invoiceCodeOrNumber":false,"sellerName":false,"totalAmount":false,"invoiceDate":false}}
✓ 1 tests/e2e/manual/live-invoice-ocr.spec.ts:8:1 › 手工 live 腾讯 OCR 辅助复核:真实 VAT 发票上传后进入可处理状态 (6.2s)
1 passed (10.1s)
@@ -0,0 +1,14 @@
>>> 探活 live /ready: https://oa.hyinda.com/ready
>>> 执行 live smoke Playwright
> [email protected] test:e2e:live
> playwright test tests/e2e/live-smoke.spec.ts
Running 3 tests using 1 worker
✓ 1 tests/e2e/live-smoke.spec.ts:43:3 › live smoke › 公网基础探活与企微配置状态 (3.0s)
✓ 2 tests/e2e/live-smoke.spec.ts:64:3 › live smoke › 管理员只读网页 smoke (11.2s)
✓ 3 tests/e2e/live-smoke.spec.ts:106:3 › live smoke › 员工只读网页 smoke (10.6s)
3 passed (28.5s)
@@ -0,0 +1 @@
[public-bundle-copy] base=https://oa.hyinda.com scanned=91 focused=2 findings=0
@@ -0,0 +1,12 @@
{
"issueId": "OAOPS1",
"baseURL": "https://oa.hyinda.com",
"commit": "2b5fd6b",
"checkedAt": "2026-05-29T00:04:48.434Z",
"status": "PASS",
"mode": "live-smoke-readiness",
"reportDir": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-smoke-readiness",
"reportRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-smoke-readiness",
"groups": null,
"notes": "公网 /ready、public bundle、pending OCR、live smoke 和真实 OCR 可用性检查;缺少凭据或样票时按脚本规则记录 SKIP。"
}
@@ -0,0 +1,20 @@
# OAOPS1 每日人工收口清单
## 员工
- 真实报销:上传 PDF 发票,补充必要附件,提交 OA 审批。
- 采购/费用:在 OA 创建申请,关联项目;如涉及合同,关联或补录合同台账。
- 合同:只录入合同摘要、编号、负责人、项目、金额、线下归档位置;涉密合同正文、敏感报价和成本细节不上传公网 OA。
## 审批人
- 从 OA 待办进入详情,确认报销、采购、合同或项目上下文后再审批。
- 退回时写清需要补充的材料,避免线下口头说明替代系统记录。
## 出纳/财务
- 审批通过后创建付款批次,线下银行渠道付款。
- 上传银行回单附件后再在 OA 标记已付款。
- 每日抽查 AP 台账、报销导出、票据状态和付款批次状态。
## 管理员
- 查看本报告 summary.json 和人工问题登记。
- 阻断项当天建修复 Issue CSV 或暂停对应流程;非阻断体验问题进入反馈池。
- 确认 payment_batch_v1=force_on,erp_sync=force_off;图片 OCR、预算、ERP、银行流水导入、真实支付直连继续冻结。
@@ -0,0 +1,10 @@
Running 1 test using 1 worker
(node:4146344) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:4146344) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
✓ 1 tests/e2e/r124-mobile-entry-matrix.spec.ts:486:3 › R124 企业微信移动入口矩阵 › 底部入口、我的二级入口、PDF 上传和草稿删除不回退到 PC 体验 (13.7s)
1 passed (17.2s)
@@ -0,0 +1,9 @@
{
"name": "mobile-entry-matrix",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/mobile-entry-matrix.log",
"checkedAt": "2026-05-29T00:07:29.415Z"
}
@@ -0,0 +1,392 @@
{
"issueId": "OSMOKE1",
"mode": "oa-only-smoke-readiness",
"status": "PASS_OA_ONLY_SMOKE_READY",
"conclusion": "PASS_OA_ONLY_SMOKE_READY",
"baseUrl": "https://oa.hyinda.com",
"checkedAt": "2026-05-29T00:04:53.368Z",
"businessReadOnly": true,
"readOnlyNote": "performs login/readiness probes only; no business data writes and no WeCom writes",
"privacy": "role/masked identifier/status/counts only; no password/token/secret/full email/full phone",
"targets": [
{
"key": "admin",
"expectedRoles": [
"admin",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"admin",
"employee"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "assets",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 7,
"total": null
}
},
{
"id": "users",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 13
}
}
],
"actualRoles": [
"admin",
"employee"
],
"missingRoles": []
},
{
"key": "employee",
"expectedRoles": [
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "my-assets",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 0,
"total": null
}
}
],
"actualRoles": [
"employee"
],
"missingRoles": []
},
{
"key": "manager",
"expectedRoles": [
"manager",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee",
"manager"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "workflow",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 1
}
}
],
"actualRoles": [
"employee",
"manager"
],
"missingRoles": []
},
{
"key": "ceo",
"expectedRoles": [
"ceo",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"ceo",
"employee"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "dashboard",
"status": "PASS",
"httpStatus": 200,
"summary": {
"totalCount": 33,
"paidCount": 8,
"reviewingCount": 3
}
}
],
"actualRoles": [
"ceo",
"employee"
],
"missingRoles": []
},
{
"key": "finance",
"expectedRoles": [
"finance",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee",
"finance"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "payment-batches",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 9,
"total": null
}
},
{
"id": "ap-ledger",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 33
}
}
],
"actualRoles": [
"employee",
"finance"
],
"missingRoles": []
},
{
"key": "finance_mgr",
"expectedRoles": [
"finance",
"finance_mgr",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee",
"finance",
"finance_mgr"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "payment-batches",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 9,
"total": null
}
},
{
"id": "ap-ledger",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 33
}
}
],
"actualRoles": [
"employee",
"finance",
"finance_mgr"
],
"missingRoles": []
},
{
"key": "hr",
"expectedRoles": [
"hr",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee",
"hr"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "wecom-archive",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 9
}
}
],
"actualRoles": [
"employee",
"hr"
],
"missingRoles": []
}
],
"findings": [],
"boundaries": {
"noBusinessWrites": true,
"noWeComWrites": true,
"noPasswordOutput": true,
"noRealEmployeeIdentifiers": true
}
}
[oa-only-smoke-readiness] report=.trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/oa-only-smoke-readiness/summary.json
@@ -0,0 +1,9 @@
{
"name": "oa-only-smoke-readiness",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/oa-only-smoke-readiness.log",
"checkedAt": "2026-05-29T00:04:53.444Z"
}
@@ -0,0 +1,391 @@
{
"issueId": "OSMOKE1",
"mode": "oa-only-smoke-readiness",
"status": "PASS_OA_ONLY_SMOKE_READY",
"conclusion": "PASS_OA_ONLY_SMOKE_READY",
"baseUrl": "https://oa.hyinda.com",
"checkedAt": "2026-05-29T00:04:53.368Z",
"businessReadOnly": true,
"readOnlyNote": "performs login/readiness probes only; no business data writes and no WeCom writes",
"privacy": "role/masked identifier/status/counts only; no password/token/secret/full email/full phone",
"targets": [
{
"key": "admin",
"expectedRoles": [
"admin",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"admin",
"employee"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "assets",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 7,
"total": null
}
},
{
"id": "users",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 13
}
}
],
"actualRoles": [
"admin",
"employee"
],
"missingRoles": []
},
{
"key": "employee",
"expectedRoles": [
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "my-assets",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 0,
"total": null
}
}
],
"actualRoles": [
"employee"
],
"missingRoles": []
},
{
"key": "manager",
"expectedRoles": [
"manager",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee",
"manager"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "workflow",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 1
}
}
],
"actualRoles": [
"employee",
"manager"
],
"missingRoles": []
},
{
"key": "ceo",
"expectedRoles": [
"ceo",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"ceo",
"employee"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "dashboard",
"status": "PASS",
"httpStatus": 200,
"summary": {
"totalCount": 33,
"paidCount": 8,
"reviewingCount": 3
}
}
],
"actualRoles": [
"ceo",
"employee"
],
"missingRoles": []
},
{
"key": "finance",
"expectedRoles": [
"finance",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee",
"finance"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "payment-batches",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 9,
"total": null
}
},
{
"id": "ap-ledger",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 33
}
}
],
"actualRoles": [
"employee",
"finance"
],
"missingRoles": []
},
{
"key": "finance_mgr",
"expectedRoles": [
"finance",
"finance_mgr",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee",
"finance",
"finance_mgr"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "payment-batches",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 9,
"total": null
}
},
{
"id": "ap-ledger",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 33
}
}
],
"actualRoles": [
"employee",
"finance",
"finance_mgr"
],
"missingRoles": []
},
{
"key": "hr",
"expectedRoles": [
"hr",
"employee"
],
"maskedIdentifier": "sm***@***.com",
"login": {
"status": "PASS",
"reason": null,
"code": null
},
"roleMatch": "PASS",
"probes": [
{
"id": "me",
"status": "PASS",
"httpStatus": 200,
"summary": {
"status": "active",
"notificationPushEnabled": true,
"roleCodes": [
"employee",
"hr"
]
}
},
{
"id": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "wecom-archive",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 1,
"total": 9
}
}
],
"actualRoles": [
"employee",
"hr"
],
"missingRoles": []
}
],
"findings": [],
"boundaries": {
"noBusinessWrites": true,
"noWeComWrites": true,
"noPasswordOutput": true,
"noRealEmployeeIdentifiers": true
}
}
@@ -0,0 +1 @@
{"requestId":"e9e0c553-a6c9-47de-92fb-8660c260276e","data":{"ok":true}}
@@ -0,0 +1,9 @@
{
"name": "public-ready",
"status": "PASS",
"kind": "required",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/public-ready.log",
"checkedAt": "2026-05-29T00:03:56.166Z"
}
@@ -0,0 +1,9 @@
{
"name": "report-privacy-smoke",
"status": "PASS",
"kind": "required",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/report-privacy-smoke.log",
"checkedAt": "2026-05-29T00:08:56.332Z"
}
@@ -0,0 +1,294 @@
{
"issueId": "OAOPS1",
"mode": "oa-real-use-daily",
"status": "PASS_OA_REAL_USE_DAILY_READY",
"conclusion": "PASS_OA_REAL_USE_DAILY_READY",
"baseURL": "https://oa.hyinda.com",
"commit": "2b5fd6b",
"checkedAt": "2026-05-29T00:08:56.249Z",
"reportRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily",
"window": {
"durationDays": 7,
"scope": "small-team-all-employees",
"realBusinessDataAllowed": true,
"fixPolicy": "blocking_same_day_issue_contract_nonblocking_feedback_pool"
},
"oaPrimaryDomains": [
"reimbursement_pdf_ocr",
"approval_tasks",
"procurement_expense",
"contracts_registry",
"projects",
"payment_batches",
"bank_receipt_attachments",
"ap_accounting_handoff",
"mobile_wecom_entry",
"audit"
],
"frozenItems": [
"image_ocr",
"complex_bpm",
"budget_control",
"erp_write",
"bank_statement_import",
"real_payment_provider",
"wecom_hr_deep_mirror",
"emergency_takeover",
"recovery_writeback",
"ruleops"
],
"boundaries": {
"defaultReadOnlyAutomation": true,
"manualRealBusinessWritesOnly": true,
"paymentBatchExpected": "force_on",
"erpExpected": "force_off",
"actualPaymentChannel": "offline_bank_channel",
"contractSensitiveFiles": "do_not_upload_confidential_body_sensitive_quote_cost_detail_to_public_oa"
},
"childReports": {
"liveReadiness": {
"status": "PASS",
"reportRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-smoke-readiness/summary.json",
"findingCount": 0,
"openCount": 0
},
"oaOnlySmokeReadiness": {
"status": "PASS_OA_ONLY_SMOKE_READY",
"reportRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/oa-only-smoke-readiness/summary.json",
"findingCount": 0,
"openCount": 0
}
},
"steps": {
"public-ready": {
"name": "public-ready",
"status": "PASS",
"kind": "required",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/public-ready.log",
"checkedAt": "2026-05-29T00:03:56.166Z"
},
"live-smoke-env": {
"name": "live-smoke-env",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-smoke-env.log",
"checkedAt": "2026-05-29T00:03:56.704Z"
},
"live-readiness": {
"name": "live-readiness",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-readiness.log",
"checkedAt": "2026-05-29T00:04:48.504Z"
},
"oa-only-smoke-readiness": {
"name": "oa-only-smoke-readiness",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/oa-only-smoke-readiness.log",
"checkedAt": "2026-05-29T00:04:53.444Z"
},
"live-feature-flags": {
"name": "live-feature-flags",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/live-feature-flags.log",
"checkedAt": "2026-05-29T00:05:59.428Z"
},
"authenticated-readonly-probe": {
"name": "authenticated-readonly-probe",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/authenticated-readonly-probe.log",
"checkedAt": "2026-05-29T00:07:06.007Z"
},
"mobile-entry-matrix": {
"name": "mobile-entry-matrix",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/mobile-entry-matrix.log",
"checkedAt": "2026-05-29T00:07:29.415Z"
},
"wecom-rendering-matrix": {
"name": "wecom-rendering-matrix",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/wecom-rendering-matrix.log",
"checkedAt": "2026-05-29T00:08:40.707Z"
},
"wecom-entry": {
"name": "wecom-entry",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/wecom-entry.log",
"checkedAt": "2026-05-29T00:08:55.969Z"
},
"report-privacy-smoke": {
"name": "report-privacy-smoke",
"status": "PASS",
"kind": "required",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/report-privacy-smoke.log",
"checkedAt": "2026-05-29T00:08:56.141Z"
}
},
"readonlyProbe": {
"mode": "oaops1-authenticated-readonly-probe",
"status": "PASS",
"baseUrl": "https://oa.hyinda.com",
"checkedAt": "2026-05-29T00:07:05.933Z",
"readOnly": true,
"duplicateRoleChecks": "employee/finance/payment/AP are covered by oa-only-smoke-readiness to avoid repeated login throttling",
"roles": {
"admin": {
"status": "PASS",
"reason": null,
"maskedIdentifier": "sm***om"
}
},
"checks": [
{
"id": "portal",
"role": "admin",
"path": "/api/portal/home",
"domain": "portal",
"status": "PASS",
"httpStatus": 200,
"summary": {}
},
{
"id": "workflow-tasks",
"role": "admin",
"path": "/api/workflow/tasks?page=1&pageSize=5",
"domain": "approval",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 0,
"total": 0
}
},
{
"id": "reimbursements",
"role": "admin",
"path": "/api/reimbursements?page=1&pageSize=5",
"domain": "reimbursement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 33
}
},
{
"id": "reimbursement-summary",
"role": "admin",
"path": "/api/reimbursements/stats/summary",
"domain": "reimbursement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"totalCount": 33,
"avgProcessingDays": 0
}
},
{
"id": "invoice-pool",
"role": "admin",
"path": "/api/invoice-pool?page=1&pageSize=5",
"domain": "invoice_ocr",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 46
}
},
{
"id": "purchase-requests",
"role": "admin",
"path": "/api/purchase-requests?page=1&pageSize=5",
"domain": "procurement",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 0,
"total": 0
}
},
{
"id": "contracts-registry",
"role": "admin",
"path": "/api/contracts-registry",
"domain": "contracts",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 6,
"total": null
}
},
{
"id": "projects",
"role": "admin",
"path": "/api/projects?page=1&pageSize=5",
"domain": "projects",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 4,
"total": null
}
},
{
"id": "audit-logs",
"role": "admin",
"path": "/api/audit-logs?page=1&pageSize=5",
"domain": "audit",
"status": "PASS",
"httpStatus": 200,
"summary": {
"itemCount": 5,
"total": 2197
}
}
],
"boundaries": {
"noBusinessWrites": true,
"noExportsByDefault": true,
"noFileUploads": true,
"noWeComWrites": true,
"noRealPaymentExecution": true
}
},
"findingCount": 0,
"findings": [],
"manualGates": {
"dailyCloseout": "管理员每日查看 summary.json 和 manual-gates.md,阻断即修,非阻断入反馈池。",
"day7Closeout": [
"A:接受 PASS_OA_REAL_USE_READY,进入下一轮体验/效率优化。",
"B:接受 PASS_WITH_FINDINGS,但先处理指定 finding。",
"C:暂停真实使用扩展,先做整改。"
]
},
"privacy": "status/count/report-path summaries only; no phone/email/token/Secret/EncodingAESKey/full external ids/full invoice image/full bank receipt/full contract body/raw payload"
}
@@ -0,0 +1,24 @@
[oaops1] loaded masked live smoke env file
>>> [oaops1] public-ready
[oaops1][PASS] public-ready
>>> [oaops1] live-smoke-env
[oaops1][PASS] live-smoke-env
>>> [oaops1] live-readiness
[oaops1][PASS] live-readiness
>>> [oaops1] oa-only-smoke-readiness
[oaops1][PASS] oa-only-smoke-readiness
[oaops1] login cooldown 65s before live-feature-flags
>>> [oaops1] live-feature-flags
[oaops1][PASS] live-feature-flags
[oaops1] login cooldown 65s before authenticated-readonly-probe
>>> [oaops1] authenticated-readonly-probe
[oaops1][PASS] authenticated-readonly-probe
>>> [oaops1] mobile-entry-matrix
[oaops1][PASS] mobile-entry-matrix
>>> [oaops1] wecom-rendering-matrix
[oaops1][PASS] wecom-rendering-matrix
>>> [oaops1] wecom-entry
[oaops1][PASS] wecom-entry
[oaops1][PASS] report-privacy-smoke
[oaops1][PASS] report-privacy-smoke
[oaops1] report=.trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily
@@ -0,0 +1,11 @@
Running 2 tests using 1 worker
(node:4148723) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:4148723) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
✓ 1 tests/e2e/wecom-entry.spec.ts:56:1 › E2E 企微入口:普通浏览器下只提示企业微信工作台打开 (2.9s)
✓ 2 tests/e2e/wecom-entry.spec.ts:66:1 › E2E 企微入口:企业微信场景优先显示企微 CTA,并展示未绑定提示 (2.6s)
2 passed (9.1s)
@@ -0,0 +1,9 @@
{
"name": "wecom-entry",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/wecom-entry.log",
"checkedAt": "2026-05-29T00:08:55.969Z"
}
@@ -0,0 +1,17 @@
Running 8 tests using 1 worker
(node:4147046) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:4147046) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
✓ 1 tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts:588:7 › WCM6 企业微信多手机移动渲染稳定化 › 320 iPhone 企业微信 › 核心移动入口使用 SVG 图标且跨视口不挤压 (7.9s)
✓ 2 tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts:588:7 › WCM6 企业微信多手机移动渲染稳定化 › 360 Android 企业微信 › 核心移动入口使用 SVG 图标且跨视口不挤压 (7.2s)
✓ 3 tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts:588:7 › WCM6 企业微信多手机移动渲染稳定化 › 375 iPhone 企业微信 › 核心移动入口使用 SVG 图标且跨视口不挤压 (7.8s)
✓ 4 tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts:588:7 › WCM6 企业微信多手机移动渲染稳定化 › 390 iPhone12 企业微信 › 核心移动入口使用 SVG 图标且跨视口不挤压 (7.8s)
✓ 5 tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts:588:7 › WCM6 企业微信多手机移动渲染稳定化 › 393 Android 企业微信 › 核心移动入口使用 SVG 图标且跨视口不挤压 (7.7s)
✓ 6 tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts:588:7 › WCM6 企业微信多手机移动渲染稳定化 › 414 iPhone 企业微信 › 核心移动入口使用 SVG 图标且跨视口不挤压 (7.2s)
✓ 7 tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts:588:7 › WCM6 企业微信多手机移动渲染稳定化 › 430 iPhone 企业微信 › 核心移动入口使用 SVG 图标且跨视口不挤压 (7.8s)
✓ 8 tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts:604:5 › WCM6 企业微信多手机移动渲染稳定化 › 390 iPhone12 企业微信 字体失败 › Material Symbols 字体失败时核心移动入口仍稳定 (7.6s)
8 passed (1.1m)
@@ -0,0 +1,9 @@
{
"name": "wecom-rendering-matrix",
"status": "PASS",
"kind": "finding_allowed",
"code": 0,
"detail": "ok",
"logRef": ".trellis/tasks/05-28-frontend-ux-wave3-business-mobile/research/postdeploy-20260529-wave3-public/oa-real-use-daily/wecom-rendering-matrix.log",
"checkedAt": "2026-05-29T00:08:40.707Z"
}
@@ -0,0 +1,51 @@
# Wave3 Gap Audit
## Method
- Reviewed archived task `.trellis/tasks/archive/2026-05/05-27-pc-detail-mobile-visual-wave3/`.
- Reviewed current router and target page files under `client/src/pages/`.
- Compared current state against the newer Wave0-2 global shell/header baseline and `frontend-design` direction.
## Important Finding
Wave3 was not truly blank. A previous task already improved PC reimbursement detail, PC workflow detail, PC notifications and several mobile key pages, and added `client/tests/e2e/pc-detail-mobile-visual-wave3.spec.ts`.
This new task should therefore be a **Wave3 refresh after Wave0-2**, not a full rewrite. The goal is to align existing detail/mobile pages with the latest shell/header/navigation language and close visible gaps.
## Candidate Pages
| Page | Current State | Recommended Action |
| --- | --- | --- |
| `/workflow/tasks/:taskId` | Already uses `EntityOverviewHero`, `detail-workspace-grid`, `SectionPanel`, status metrics and action panel. | Light refresh: stronger title/subtitle, next-action wording, evidence/history hierarchy, loading/error polish. |
| `/projects/:projectId` | Rich business page with `EntityOverviewHero` and many panels, but still mixes `card-std`, local metric grids and long sections. | Moderate refresh: introduce clearer current-state/next-step summary and reduce local card noise. |
| `/contracts-registry` | Contract table/list page exists, no dedicated contract detail route found in router. | Treat as contract ledger/detail-adjacent page; improve header, warning summary and lifecycle command area without adding backend routes. |
| `/mobile` | Uses mobile focus card and task list; already covered by mobile entry tests. | Light refresh only if needed for consistency with new copy and entry hierarchy. |
| `/mobile/approvals` and `/mobile/approvals/:taskId` | Large page; already has mobile list/detail surfaces, offline support and sticky action behavior. | Careful targeted refresh: no large rewrite; improve first-screen summary, command labels and detail action grouping. |
| `/mobile/notifications` | Mobile notification inbox exists with filters and direct link behavior. | Align copy and controls with PC notification inbox; avoid adding complexity. |
| `/mobile/reimbursements` | Mobile list already has focus summary and status tabs. | Improve list summary/action wording only; preserve create/delete behavior. |
| `/mobile/reimbursements/:reimbursementId` | Very large detail page with many editing flows. | Targeted polish around state summary, invoice/attachment sections and sticky actions; no business logic rewrite. |
| `/mobile/purchase-requests/:purchaseRequestId` | Existing mobile purchase detail page; useful for notification/deeplink coverage. | Include as secondary target if time permits; do not expand into full procurement redesign. |
## Proposed Scope Decision
Recommended MVP:
1. PC detail refresh:
- workflow task detail
- project detail
- contract registry as contract ledger/detail-adjacent surface
2. Mobile key refresh:
- mobile approvals list/detail
- mobile notifications
- mobile reimbursements list/detail
- mobile purchase request detail only if it is needed to keep deeplink flows consistent
3. Test baseline refresh:
- update or extend `pc-detail-mobile-visual-wave3.spec.ts`
- run mobile route/design checks where relevant
Out of scope:
- No backend API/schema/permission/status-machine changes.
- No new contract detail route unless a separate task approves the product/API design.
- No full mobile rewrite; use focused improvements that preserve existing offline and sticky action behavior.
@@ -0,0 +1,26 @@
{
"id": "frontend-ux-wave3-business-mobile",
"name": "frontend-ux-wave3-business-mobile",
"title": "前端体验 Wave3 业务详情与移动关键页",
"description": "在 Wave0-2 新全局体验基线后,复审并补齐业务详情页与移动关键页体验。",
"status": "completed",
"dev_type": null,
"scope": "client/frontend-ux-wave3-business-mobile",
"package": null,
"priority": "P2",
"creator": "shunli",
"assignee": "shunli",
"createdAt": "2026-05-28",
"completedAt": "2026-05-29",
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {}
}