完成第二轮降噪部署复检(frontend-simplification-wave2-deploy-verify)
这个提交包含在:
@@ -85,3 +85,79 @@ SYNC_ENV=0 bash deploy/trialrun/deploy.sh
|
|||||||
node deploy/trialrun/validate-env-contract.js
|
node deploy/trialrun/validate-env-contract.js
|
||||||
SYNC_ENV=0 bash deploy/trialrun/deploy.sh
|
SYNC_ENV=0 bash deploy/trialrun/deploy.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Scenario: Public Smoke Navigation Labels
|
||||||
|
|
||||||
|
### 1. Scope / Trigger
|
||||||
|
|
||||||
|
- Trigger: frontend shell, navigation labels, sidebar grouping, Portal/workbench
|
||||||
|
copy, or live smoke assertions change.
|
||||||
|
- Purpose: prevent public deployment from being marked failed only because
|
||||||
|
smoke tests look for stale navigation copy while the page itself is healthy.
|
||||||
|
|
||||||
|
### 2. Signatures
|
||||||
|
|
||||||
|
- Live smoke command:
|
||||||
|
`E2E_MODE=live LIVE_SMOKE_BASE_URL=https://oa.hyinda.com npx playwright test tests/e2e/live-smoke.spec.ts`
|
||||||
|
- Shared assertions: `client/tests/e2e/helpers/smokeAssertions.ts`
|
||||||
|
- Workbench route: `/portal`
|
||||||
|
- Current primary workbench nav label: `工作台`
|
||||||
|
- Historical nav label still allowed in mocks or older fixtures: `Portal`
|
||||||
|
|
||||||
|
### 3. Contracts
|
||||||
|
|
||||||
|
- `assertPortalLoaded(page)` must assert route and page content first:
|
||||||
|
`/portal` URL and the `今日任务` heading.
|
||||||
|
- Navigation-label assertions for the workbench link must accept both `工作台`
|
||||||
|
and `Portal` while older mocks still use English labels.
|
||||||
|
- Smoke tests must not require a copy string that is not a product contract for
|
||||||
|
public availability.
|
||||||
|
- If the product intentionally renames the primary workbench label again, update
|
||||||
|
the shared smoke helper rather than duplicating route-specific assertions in
|
||||||
|
each live smoke test.
|
||||||
|
|
||||||
|
### 4. Validation & Error Matrix
|
||||||
|
|
||||||
|
- Page reaches `/portal`, `今日任务` is visible, but nav label is `工作台` ->
|
||||||
|
smoke should pass.
|
||||||
|
- Page reaches `/portal`, but `今日任务` is missing -> smoke should fail.
|
||||||
|
- Page stays on login, `/403`, error fallback or another route -> smoke should
|
||||||
|
fail.
|
||||||
|
- New shell label appears only in one live smoke test -> move the compatibility
|
||||||
|
logic into `smokeAssertions.ts`.
|
||||||
|
|
||||||
|
### 5. Good/Base/Bad Cases
|
||||||
|
|
||||||
|
- Good: `assertPortalLoaded` checks `/portal`, `今日任务`, and a workbench link
|
||||||
|
matching either `工作台` or `Portal`.
|
||||||
|
- Base: mocked E2E fixtures may still emit `Portal`; live public navigation may
|
||||||
|
emit `工作台`.
|
||||||
|
- Bad: live smoke hard-codes only `Portal` and blocks deployment after a valid
|
||||||
|
Chinese navigation rollout.
|
||||||
|
|
||||||
|
### 6. Tests Required
|
||||||
|
|
||||||
|
- After changing live smoke assertions, run:
|
||||||
|
`cd client && npm run typecheck`
|
||||||
|
- For public deploy verification, run live smoke or the readiness wrapper:
|
||||||
|
`LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-live-smoke-readiness.sh`
|
||||||
|
- When changing the shell or Portal page, include a focused Playwright check
|
||||||
|
that proves the workbench route and heading still load.
|
||||||
|
|
||||||
|
### 7. Wrong vs Correct
|
||||||
|
|
||||||
|
#### Wrong
|
||||||
|
|
||||||
|
```ts
|
||||||
|
await expect(page.getByRole("link", { name: "Portal" }).first()).toBeVisible();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Correct
|
||||||
|
|
||||||
|
```ts
|
||||||
|
await expect(
|
||||||
|
page.getByRole("link", { name: "工作台", exact: true })
|
||||||
|
.or(page.getByRole("link", { name: "Portal", exact: true }))
|
||||||
|
.first(),
|
||||||
|
).toBeVisible();
|
||||||
|
```
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
|
|
||||||
本任务只做已提交前端改动的部署、对比和只读验证;不继续扩大页面重构范围,不写真实业务数据,不覆盖远端 `.env`。
|
本任务只做已提交前端改动的部署、对比和只读验证;不继续扩大页面重构范围,不写真实业务数据,不覆盖远端 `.env`。
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- 部署当前 `main` 中第二轮前端降噪改动到公网试运行环境。
|
||||||
|
- 生成审批中心、报销详情和审批任务详情的第二轮前后截图对比。
|
||||||
|
- 修正部署门禁中暴露的非业务阻断,例如正式文案和测试断言漂移。
|
||||||
|
- 执行部署前本地门禁和部署后公网只读验证矩阵。
|
||||||
|
- 在当前 Trellis task 中保存脱敏摘要和相对报告路径。
|
||||||
|
|
||||||
## What I Already Know
|
## What I Already Know
|
||||||
|
|
||||||
- 用户已经确认第一轮对比效果,并要求“保持这样,作为统一设计规则”。
|
- 用户已经确认第一轮对比效果,并要求“保持这样,作为统一设计规则”。
|
||||||
@@ -46,17 +54,21 @@
|
|||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
- [x] 用户明确批准继续执行部署与第二轮对比。
|
- [x] 用户明确批准继续执行部署与第二轮对比。
|
||||||
- [ ] `prd.md`、`implement.md` 和上下文登记完成,并通过 Trellis task validate。
|
- [x] `prd.md`、`implement.md` 和上下文登记完成,并通过 Trellis task validate。
|
||||||
- [ ] 第二轮前后对比页生成完成,可从 `output/playwright/frontend-simplification-wave2-compare/index.html` 查看。
|
- [x] 第二轮前后对比页生成完成,可从 `output/playwright/frontend-simplification-wave2-compare/index.html` 查看。
|
||||||
- [ ] 部署前本地门禁通过。
|
- [x] 部署前本地门禁通过。
|
||||||
- [ ] `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` 成功,未覆盖远端 `.env`。
|
- [x] `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` 完成远端服务重建,未覆盖远端 `.env`;脚本内置 live smoke 因测试断言漂移退出,修正后标准 live readiness 已复跑通过。
|
||||||
- [ ] 部署后公网 `/ready` 通过。
|
- [x] 部署后公网 `/ready` 通过。
|
||||||
- [ ] live smoke / OCR readiness 通过或有可解释 SKIP/PASS_WITH_FINDINGS。
|
- [x] live smoke / OCR readiness 通过或有可解释 SKIP/PASS_WITH_FINDINGS。
|
||||||
- [ ] 权限矩阵通过。
|
- [x] 权限矩阵通过。
|
||||||
- [ ] PC 只读视觉矩阵无 P1 blocker。
|
- [x] PC 只读视觉矩阵无 P1 blocker。
|
||||||
- [ ] 移动入口和企业微信渲染矩阵通过。
|
- [x] 移动入口和企业微信渲染矩阵通过。
|
||||||
- [ ] 当前任务记录公网验证摘要和报告相对路径。
|
- [x] 当前任务记录公网验证摘要和报告相对路径。
|
||||||
- [ ] Trellis governance 和 `git diff --check` 通过。
|
- [x] Trellis governance 和 `git diff --check` 通过。
|
||||||
|
|
||||||
|
## Result
|
||||||
|
|
||||||
|
`READY_FOR_USER_TEST`
|
||||||
|
|
||||||
## Definition Of Done
|
## Definition Of Done
|
||||||
|
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"checkedAt": "2026-05-29T05:37:24.101Z",
|
||||||
|
"baseUrl": "https://oa.hyinda.com",
|
||||||
|
"liveSmokeReady": true,
|
||||||
|
"liveSmoke": {
|
||||||
|
"adminCredentialReady": true,
|
||||||
|
"employeeCredentialReady": true
|
||||||
|
},
|
||||||
|
"liveSmokeOptional": {
|
||||||
|
"expectedWecomStatusReady": true,
|
||||||
|
"managerCredentialReady": true,
|
||||||
|
"financeCredentialReady": 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
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
Running 1 test using 1 worker
|
||||||
|
|
||||||
|
[live-ocr] {"alias":"SAMPLE-PDF-001","status":"ocr_failed","durationMs":1173,"transport":"ui","timings":{"uploadMs":1173,"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.8s)
|
||||||
|
|
||||||
|
1 passed (10.5s)
|
||||||
+14
@@ -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 › 公网基础探活与企微配置状态 (2.5s)
|
||||||
|
✓ 2 tests/e2e/live-smoke.spec.ts:64:3 › live smoke › 管理员只读网页 smoke (11.4s)
|
||||||
|
✓ 3 tests/e2e/live-smoke.spec.ts:106:3 › live smoke › 员工只读网页 smoke (10.7s)
|
||||||
|
|
||||||
|
3 passed (28.4s)
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
[pending-ocr][SKIP] missing DATABASE_URL
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
[public-bundle-copy] base=https://oa.hyinda.com scanned=91 focused=2 findings=0
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"issueId": "frontend-simplification-wave2-deploy-verify",
|
||||||
|
"baseURL": "https://oa.hyinda.com",
|
||||||
|
"commit": "c08ba72",
|
||||||
|
"checkedAt": "2026-05-29T05:38:17.239Z",
|
||||||
|
"status": "PASS",
|
||||||
|
"mode": "live-smoke-readiness",
|
||||||
|
"reportDir": ".trellis/tasks/05-29-frontend-simplification-wave2-deploy-verify/research/postdeploy-live-smoke-readiness",
|
||||||
|
"reportRef": ".trellis/tasks/05-29-frontend-simplification-wave2-deploy-verify/research/postdeploy-live-smoke-readiness",
|
||||||
|
"groups": null,
|
||||||
|
"notes": "公网 /ready、public bundle、pending OCR、live smoke 和真实 OCR 可用性检查;缺少凭据或样票时按脚本规则记录 SKIP。"
|
||||||
|
}
|
||||||
+2285
文件差异内容过多而无法显示
加载差异
+28
@@ -0,0 +1,28 @@
|
|||||||
|
# OA 权限矩阵脱敏自动验证报告
|
||||||
|
|
||||||
|
生成时间:2026-05-29T05:37:41.962Z
|
||||||
|
结论:PASS_PERMISSION_MATRIX_READY
|
||||||
|
|
||||||
|
## 统计
|
||||||
|
|
||||||
|
- 角色数:7
|
||||||
|
- 正向探针:43
|
||||||
|
- 负向探针:42
|
||||||
|
- 问题数:0
|
||||||
|
|
||||||
|
## 角色结果
|
||||||
|
|
||||||
|
| 角色 | 登录 | 角色匹配 | 探针通过/总数 |
|
||||||
|
| --- | --- | --- | ---: |
|
||||||
|
| employee | PASS | PASS | 17/17 |
|
||||||
|
| manager | PASS | PASS | 13/13 |
|
||||||
|
| finance | PASS | PASS | 14/14 |
|
||||||
|
| finance_mgr | PASS | PASS | 10/10 |
|
||||||
|
| hr | PASS | PASS | 11/11 |
|
||||||
|
| ceo | PASS | PASS | 9/9 |
|
||||||
|
| admin | PASS | PASS | 11/11 |
|
||||||
|
|
||||||
|
## 说明
|
||||||
|
|
||||||
|
- 本报告只输出角色、HTTP 状态、脱敏账号和摘要计数,不输出密码、token、Secret、完整账号、合同正文、票据内容或原始 payload。
|
||||||
|
- 409 表示功能门禁关闭且未泄露数据;对财务/AP/付款等冻结或受控功能可作为可解释拒绝。
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
# Postdeploy Summary
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
`READY_FOR_USER_TEST`
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
- Deployed commit: `c08ba72`
|
||||||
|
- Command: `SYNC_ENV=0 bash deploy/trialrun/deploy.sh`
|
||||||
|
- Remote `.env`: not synced or overwritten.
|
||||||
|
- Remote service rebuild, init, migration status and runtime deployment stages completed.
|
||||||
|
- Note: the deploy script's integrated live smoke initially exited on a stale test assertion that looked for the old `Portal` nav label. The current UI exposes `工作台`; the shared smoke assertion was updated to accept both labels, then live smoke and the standard readiness suite passed.
|
||||||
|
|
||||||
|
## Comparison Evidence
|
||||||
|
|
||||||
|
- Second wave comparison page: `output/playwright/frontend-simplification-wave2-compare/index.html`
|
||||||
|
- Pages compared: approval center, reimbursement detail, workflow task detail.
|
||||||
|
- Data source: Playwright mock business data.
|
||||||
|
- Baseline: before `29cfea2`, after `79f50b0` plus deployment gate copy fix in `c08ba72`.
|
||||||
|
|
||||||
|
## Verification Results
|
||||||
|
|
||||||
|
| Check | Result | Evidence |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Task validate | PASS | command output |
|
||||||
|
| Frontend typecheck | PASS | command output |
|
||||||
|
| Frontend build | PASS | command output |
|
||||||
|
| UI design rules | PASS | command output |
|
||||||
|
| Env contract | PASS | command output |
|
||||||
|
| Public bundle copy scan | PASS | command output and live readiness report |
|
||||||
|
| Live smoke readiness | PASS | `research/postdeploy-live-smoke-readiness/summary.json` |
|
||||||
|
| Permission matrix | PASS_PERMISSION_MATRIX_READY | `research/postdeploy-permission-matrix/summary.json` |
|
||||||
|
| PC readonly visual matrix | PASS_PC_READONLY_VISUAL_READY | `artifacts/qa-flow/oafront3-pc-readonly-visual-20260529-133832/summary.json` |
|
||||||
|
| Mobile entry matrix | PASS | command output |
|
||||||
|
| WeCom rendering matrix | PASS | command output |
|
||||||
|
|
||||||
|
## Non-Blocking Notes
|
||||||
|
|
||||||
|
- `pending OCR` scan reported `SKIP` because the local command did not receive `DATABASE_URL`; live OCR sample still ran through the standard readiness path.
|
||||||
|
- Live OCR sample returned an explainable duplicate/same-invoice category and the readiness suite concluded PASS.
|
||||||
|
- `rsync` printed a non-fatal warning for an old remote QA artifact directory that could not be deleted; deployment continued and postdeploy checks passed.
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
"id": "frontend-simplification-wave2-deploy-verify",
|
"id": "frontend-simplification-wave2-deploy-verify",
|
||||||
"name": "frontend-simplification-wave2-deploy-verify",
|
"name": "frontend-simplification-wave2-deploy-verify",
|
||||||
"title": "部署并复检前端降噪第二轮",
|
"title": "部署并复检前端降噪第二轮",
|
||||||
"description": "",
|
"description": "部署第二轮前端降噪改动,生成审批中心和报销详情对比页,并完成公网只读验证。",
|
||||||
"status": "in_progress",
|
"status": "in_progress",
|
||||||
"dev_type": null,
|
"dev_type": null,
|
||||||
"scope": null,
|
"scope": "frontend-deploy-verify",
|
||||||
"package": null,
|
"package": null,
|
||||||
"priority": "P2",
|
"priority": "P2",
|
||||||
"creator": "shunli",
|
"creator": "shunli",
|
||||||
@@ -20,7 +20,14 @@
|
|||||||
"subtasks": [],
|
"subtasks": [],
|
||||||
"children": [],
|
"children": [],
|
||||||
"parent": null,
|
"parent": null,
|
||||||
"relatedFiles": [],
|
"relatedFiles": [
|
||||||
|
"client/src/pages/PortalHomePage.tsx",
|
||||||
|
"client/tests/e2e/helpers/smokeAssertions.ts",
|
||||||
|
"deploy/trialrun/deploy.sh",
|
||||||
|
"scripts/qa/run-live-smoke-readiness.sh",
|
||||||
|
"scripts/qa/check-oa-permission-matrix.mjs",
|
||||||
|
"scripts/qa/run-oafront3-pc-readonly-visual.sh"
|
||||||
|
],
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"meta": {}
|
"meta": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ type Envelope<T> = {
|
|||||||
|
|
||||||
export async function assertPortalLoaded(page: Page) {
|
export async function assertPortalLoaded(page: Page) {
|
||||||
await expect(page).toHaveURL(/\/portal/);
|
await expect(page).toHaveURL(/\/portal/);
|
||||||
await expect(page.getByRole("link", { name: "Portal" }).first()).toBeVisible();
|
await expect(
|
||||||
|
page.getByRole("link", { name: "工作台", exact: true })
|
||||||
|
.or(page.getByRole("link", { name: "Portal", exact: true }))
|
||||||
|
.first(),
|
||||||
|
).toBeVisible();
|
||||||
await expect(page.getByRole("heading", { name: "今日任务" })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "今日任务" })).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +37,11 @@ export async function assertForbiddenPage(page: Page) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function assertMainNavVisible(page: Page) {
|
export async function assertMainNavVisible(page: Page) {
|
||||||
await expect(page.getByRole("link", { name: "Portal" }).first()).toBeVisible();
|
await expect(
|
||||||
|
page.getByRole("link", { name: "工作台", exact: true })
|
||||||
|
.or(page.getByRole("link", { name: "Portal", exact: true }))
|
||||||
|
.first(),
|
||||||
|
).toBeVisible();
|
||||||
await expect(page.getByRole("link", { name: "团队" }).first()).toBeVisible();
|
await expect(page.getByRole("link", { name: "团队" }).first()).toBeVisible();
|
||||||
await expect(page.getByRole("link", { name: "项目" }).first()).toBeVisible();
|
await expect(page.getByRole("link", { name: "项目" }).first()).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户