From ec367ed3ae356da962d77c30435e0be4f5e95357 Mon Sep 17 00:00:00 2001 From: shunli Date: Sun, 31 May 2026 13:29:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E7=BD=B2=E5=A4=8D?= =?UTF-8?q?=E6=A3=80=E9=93=BE=E8=B7=AF=EF=BC=8805-31-deploy-unified-list-d?= =?UTF-8?q?etail-reimbursement-public-check=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .trellis/spec/hyb-oa/deployment-trialrun.md | 95 ++++++++++++++++++- .../check.jsonl | 5 + .../implement.jsonl | 4 + .../implement.md | 18 ++++ .../prd.md | 61 ++++++++++++ .../research/deployment-evidence.md | 49 ++++++++++ .../task.json | 30 ++++++ deploy/trialrun/deploy.sh | 6 +- server/src/scripts/smoke-trialrun-runtime.js | 18 ++-- 9 files changed, 276 insertions(+), 10 deletions(-) create mode 100644 .trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/check.jsonl create mode 100644 .trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/implement.jsonl create mode 100644 .trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/implement.md create mode 100644 .trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/prd.md create mode 100644 .trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/research/deployment-evidence.md create mode 100644 .trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/task.json diff --git a/.trellis/spec/hyb-oa/deployment-trialrun.md b/.trellis/spec/hyb-oa/deployment-trialrun.md index d349ecc9..cb2013a0 100644 --- a/.trellis/spec/hyb-oa/deployment-trialrun.md +++ b/.trellis/spec/hyb-oa/deployment-trialrun.md @@ -168,5 +168,98 @@ await expect( page.getByRole("link", { name: "工作台", exact: true }) .or(page.getByRole("link", { name: "Portal", exact: true })) .first(), -).toBeVisible(); + ).toBeVisible(); +``` + +## Scenario: Trial Run Runtime Navigation Baseline + +### 1. Scope / Trigger + +- Trigger: changing sidebar grouping, workspace module visibility defaults, + `server/src/services/workspaceSettings.js`, or + `server/src/scripts/smoke-trialrun-runtime.js`. +- Purpose: keep deployment smoke aligned with the current small-team navigation + model instead of blocking deployment on retired menu assumptions. + +### 2. Signatures + +- Runtime smoke command inside deployment: + `docker compose exec -T server node src/scripts/smoke-trialrun-runtime.js` +- Source of truth for sidebar grouping: + `server/src/services/workspaceSettings.js` +- Runtime smoke assertion file: + `server/src/scripts/smoke-trialrun-runtime.js` + +### 3. Contracts + +- Runtime smoke must distinguish primary sidebar entries from collapsed + `更多` entries. +- Core day-to-day ledgers such as `报销`, `采购申请`, `合同台账`, `项目` and + `资产` are expected in `main` when the active role has access. +- Low-frequency entries such as `周报` and `公告` may be enabled but should be + checked in `backup` / `更多`, not forced into `main`. +- `待办` follows the current workspace and role-aware navigation baseline; do + not move it between `main`, `backup` or hidden as part of a deployment-smoke + fix unless a product task explicitly changes that rule. +- Management pages should remain represented by the single `管理` entry unless + a current task explicitly changes the management navigation model. + +### 4. Validation & Error Matrix + +- Core ledger missing from `main` -> runtime smoke fails with + `系统导航 main 缺少 入口`. +- `周报` or `公告` missing from `backup` while enabled -> runtime smoke fails + with `系统导航 backup 缺少 入口`. +- Management children are hidden behind `管理`, but smoke still expects + `workspace`, `people`, `featureFlags` or `auditLogs` in `admin` -> update the + smoke baseline; do not re-expand the sidebar for the smoke. +- `systemSettings` missing from `admin` -> runtime smoke fails because the + management entry is no longer reachable. + +### 5. Good/Base/Bad Cases + +- Good: `main` includes `portal`, `reimbursements`, `purchaseRequests`, + `contractsRegistry`, `projects` and `assets`; `backup` includes + `weeklyReports` and `announcements`; `admin` includes `systemSettings`. +- Base: `待办` is in `main` for a configured admin/owner trial account; smoke + accepts it there because it follows the current workspace baseline. +- Bad: smoke expects `weeklyReports` in `main` after the sidebar rule moved + low-frequency modules to `更多`. +- Bad: smoke expects every management child as a sidebar row after the product + rule consolidated management into one `管理` entry. + +### 6. Tests Required + +- Run `node --check server/src/scripts/smoke-trialrun-runtime.js` after editing + runtime smoke. +- Run `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` for public deployment so the + remote runtime smoke validates the actual workspace and feature-flag state. + +### 7. Wrong vs Correct + +#### Wrong + +```js +const REQUIRED_MAIN_NAV_KEYS = [ + "portal", + "reimbursements", + "weeklyReports", + "announcements", +]; +const REQUIRED_ADMIN_NAV_KEYS = ["workspace", "people", "featureFlags"]; +``` + +#### Correct + +```js +const REQUIRED_MAIN_NAV_KEYS = [ + "portal", + "reimbursements", + "purchaseRequests", + "contractsRegistry", + "projects", + "assets", +]; +const REQUIRED_BACKUP_NAV_KEYS = ["weeklyReports", "announcements"]; +const REQUIRED_ADMIN_NAV_KEYS = ["systemSettings"]; ``` diff --git a/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/check.jsonl b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/check.jsonl new file mode 100644 index 00000000..790adcb1 --- /dev/null +++ b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/check.jsonl @@ -0,0 +1,5 @@ +{"file": ".trellis/spec/hyb-oa/index.md", "reason": "hyb-oa spec entry and task governance read order"} +{"file": ".trellis/spec/hyb-oa/project-governance.md", "reason": "Trellis task, approval, and commit rules for public deployment"} +{"file": ".trellis/spec/hyb-oa/deployment-trialrun.md", "reason": "public deployment command, env contract, smoke, and reporting requirements"} +{"file": ".trellis/spec/hyb-oa/docs-and-evidence.md", "reason": "evidence recording and documentation hygiene for public checks"} +{"file": ".trellis/spec/hyb-oa/security-privacy.md", "reason": "secret and sensitive-data handling during deployment evidence collection"} diff --git a/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/implement.jsonl b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/implement.jsonl new file mode 100644 index 00000000..c014ded3 --- /dev/null +++ b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/implement.jsonl @@ -0,0 +1,4 @@ +{"file": ".trellis/spec/hyb-oa/index.md", "reason": "hyb-oa spec entry and task governance read order"} +{"file": ".trellis/spec/hyb-oa/project-governance.md", "reason": "Trellis task, approval, and commit rules for public deployment"} +{"file": ".trellis/spec/hyb-oa/deployment-trialrun.md", "reason": "public deployment command, env contract, smoke, and reporting requirements"} +{"file": ".trellis/spec/hyb-oa/security-privacy.md", "reason": "secret and sensitive-data handling during deployment evidence collection"} diff --git a/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/implement.md b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/implement.md new file mode 100644 index 00000000..069a1225 --- /dev/null +++ b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/implement.md @@ -0,0 +1,18 @@ +# Implementation Notes + +## Plan + +1. Run local deployment preflight checks and confirm the reimbursement page source no longer contains the old top task-card entry markers. +2. Deploy with `SYNC_ENV=0 bash deploy/trialrun/deploy.sh`, preserving the remote `.env`. +3. If deploy verification is blocked by deployment tooling or smoke assertions that are inconsistent with current specs, fix only those deployment/checking assets. +4. Rerun deployment until the remote env contract, `/ready`, external deps smoke, runtime smoke and public bundle scan pass. +5. Record evidence and residual limitations in this task. + +## Implemented Adjustments + +- `deploy/trialrun/deploy.sh`: added explicit `/dev/null` stdin redirection to remote `docker compose exec -T` checks so the SSH here-doc continues through `/ready`, external deps smoke, runtime smoke and service-status steps. +- `server/src/scripts/smoke-trialrun-runtime.js`: updated navigation smoke expectations to match the current sidebar model: + - core business ledgers in `main`; + - `周报` and `公告` in `backup` / `更多`; + - one `systemSettings` management entry instead of many sidebar management children. +- `.trellis/spec/hyb-oa/deployment-trialrun.md`: recorded the runtime navigation smoke baseline so future deploys do not regress to old menu assumptions. diff --git a/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/prd.md b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/prd.md new file mode 100644 index 00000000..d8ce3751 --- /dev/null +++ b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/prd.md @@ -0,0 +1,61 @@ +# 部署统一列表详情改造并复检报销页 + +## Goal + +将当前 `main` 的统一列表、详情页操作区和报销页改造部署到公网试运行环境,复检用户反馈的“报销页面顶部仍看到三个圆形按钮”是否已由最新版本修正。 + +## What I Already Know + +- 用户已明确批准公网部署。 +- 本地 `main` 最新提交为 `efd6d28`,工作区干净。 +- 本地 `client/src/pages/ReimbursementsPage.tsx` 已不再保留旧的三张顶部快捷任务卡/圆形入口,当前顶部应为常规 `WorkspaceHeader`、`新建报销`、状态筛选和按权限显隐的 `台账工具`。 +- 公网试运行环境属于准生产环境,部署必须保留远端 `.env`,使用 `SYNC_ENV=0 bash deploy/trialrun/deploy.sh`。 + +## Requirements + +- 部署当前 `main` 到 `https://oa.hyinda.com` 对应公网试运行环境。 +- 不覆盖远端环境变量,不执行真实付款、真实业务写入或数据库重置。 +- 部署后验证 `/ready` 可用。 +- 部署后复检公网前端资源已更新到当前提交对应版本。 +- 尽量复检报销页视觉状态:报销页顶部不应再出现旧的三个圆形按钮或三张任务入口。 +- 如果本地缺少 `LIVE_SMOKE_*` 登录凭据,必须明确标注完整登录后页面检查的限制,并使用可用的公开 readiness/bundle 检查补足证据。 + +## Scope + +- 公网试运行部署脚本、部署后 smoke、runtime smoke 基线和本任务证据记录。 +- 允许修复阻塞部署验证完成的部署脚本或 smoke 基线问题。 +- 不改变报销、列表、详情等业务页面实现。 + +## Acceptance Criteria + +- [x] 本地部署前检查通过。 +- [x] `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` 成功完成。 +- [x] 公网 `/ready` 返回健康状态。 +- [x] 公网 bundle 检查通过或给出明确失败原因。 +- [x] 报告部署提交 hash、ready 结果、smoke/复检结果,以及用户是否可以测试。 + +## Out Of Scope + +- 不新增或修改业务代码。 +- 不修改数据库结构和远端 `.env`。 +- 不执行真实付款、银行、ERP 或其他外部写入。 +- 不处理与本次部署无关的 UI 新问题。 + +## Test Plan + +- `node deploy/trialrun/validate-env-contract.js` +- `cd client && npm run build` +- `node --check server/src/scripts/smoke-trialrun-runtime.js` +- `bash -n deploy/trialrun/deploy.sh` +- `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` +- `curl -fsS https://oa.hyinda.com/ready` +- `LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-live-smoke-readiness.sh` +- `node scripts/qa/check-public-bundle-copy.mjs https://oa.hyinda.com` +- Public reimbursement bundle scan for absence of old task-card markers. + +## Technical Notes + +- 部署规范:`.trellis/spec/hyb-oa/deployment-trialrun.md` +- 部署命令:`SYNC_ENV=0 bash deploy/trialrun/deploy.sh` +- 环境契约检查:`node deploy/trialrun/validate-env-contract.js` +- 公网目标:`https://oa.hyinda.com` diff --git a/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/research/deployment-evidence.md b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/research/deployment-evidence.md new file mode 100644 index 00000000..e961f239 --- /dev/null +++ b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/research/deployment-evidence.md @@ -0,0 +1,49 @@ +# Deployment Evidence + +## Deployment + +- Date: 2026-05-31 +- Target: `https://oa.hyinda.com` +- Command: `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` +- App baseline before deployment: `efd6d28` +- Scope note: deployment included the current task's deployment-script/runtime-smoke fixes so the deploy command could complete the intended post-deploy checks. + +## Findings During Deploy + +- First full rerun showed that `docker compose exec -T` could consume the SSH here-doc and skip later deployment steps. Fixed by redirecting the affected remote `exec` commands from `/dev/null`. +- Runtime smoke still assumed the old sidebar model. Updated it to match the current mature Ant Design-style navigation baseline: + - core business ledgers in `main`; + - `周报` and `公告` in `backup` / `更多`; + - management represented by one `管理` entry. + +## Verification + +- `node deploy/trialrun/validate-env-contract.js`: PASS. +- `cd client && npm run build`: PASS before deployment. +- `node --check server/src/scripts/smoke-trialrun-runtime.js`: PASS. +- `bash -n deploy/trialrun/deploy.sh`: PASS. +- `git diff --check`: PASS. +- Final deploy script run: + - env contract: PASS; + - Prisma migration status: up to date; + - `/ready`: PASS; + - external deps smoke: PASS; + - runtime smoke: PASS; + - public bundle copy scan: `scanned=93 focused=2 findings=0`. +- Independent `/ready`: `{"ok":true}`. +- `LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-live-smoke-readiness.sh`: PASS with live browser/OCR checks skipped because local `LIVE_SMOKE_*` credentials and OCR sample were not configured. + +## Reimbursement Page Check + +- Public asset `https://oa.hyinda.com/assets/ReimbursementsPage-DgJ0EYZV.js` is available. +- The public reimbursement bundle contains the new header/action shape: `我的报销`, `新建报销`, status tabs and optional `台账工具`. +- The public reimbursement bundle does not contain old task-card markers: + - `reimbursements-task-card` + - `被驳回待补正` + - `草稿待完善` + - `审批中进度` + +## Residual Limits + +- Full logged-in live smoke and logged-in visual inspection were skipped because this local environment does not have complete `LIVE_SMOKE_*` credentials. +- Public readiness, deployment-in-container smoke, and public bundle checks passed, so the deployed app is available for user testing. diff --git a/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/task.json b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/task.json new file mode 100644 index 00000000..0a613b00 --- /dev/null +++ b/.trellis/tasks/05-31-deploy-unified-list-detail-reimbursement-public-check/task.json @@ -0,0 +1,30 @@ +{ + "id": "deploy-unified-list-detail-reimbursement-public-check", + "name": "deploy-unified-list-detail-reimbursement-public-check", + "title": "部署统一列表详情改造并复检报销页", + "description": "Deploy the unified business list/detail UI changes to the public trial run environment and verify the reimbursement page no longer serves the old top task-card buttons.", + "status": "in_progress", + "dev_type": null, + "scope": "deployment-trialrun", + "package": null, + "priority": "P2", + "creator": "shunli", + "assignee": "shunli", + "createdAt": "2026-05-31", + "completedAt": null, + "branch": null, + "base_branch": "main", + "worktree_path": null, + "commit": null, + "pr_url": null, + "subtasks": [], + "children": [], + "parent": null, + "relatedFiles": [ + "deploy/trialrun/deploy.sh", + "server/src/scripts/smoke-trialrun-runtime.js", + ".trellis/spec/hyb-oa/deployment-trialrun.md" + ], + "notes": "", + "meta": {} +} diff --git a/deploy/trialrun/deploy.sh b/deploy/trialrun/deploy.sh index 0e7f4a9f..83a86c06 100755 --- a/deploy/trialrun/deploy.sh +++ b/deploy/trialrun/deploy.sh @@ -141,7 +141,7 @@ echo ">>> 4.4 执行 init" "${compose_cmd[@]}" run --rm -T --entrypoint sh init -lc 'cd /app/server && npm run prisma:migrate:deploy && npm run seed:config && npm run seed:trialrun' >> 4.5 校验 Prisma migration status" -if ! "${compose_cmd[@]}" exec -T server sh -lc 'cd /app/server && npx prisma migrate status'; then +if ! "${compose_cmd[@]}" exec -T server sh -lc 'cd /app/server && npx prisma migrate status' &2 "${compose_cmd[@]}" logs --tail=200 server || true exit 1 @@ -164,14 +164,14 @@ if [[ "$ready_ok" != "1" ]]; then fi echo ">>> 4.7 执行 external deps smoke" -if ! "${compose_cmd[@]}" exec -T server node src/scripts/smoke-external-deps.js; then +if ! "${compose_cmd[@]}" exec -T server node src/scripts/smoke-external-deps.js &2 "${compose_cmd[@]}" logs --tail=200 server || true exit 1 fi echo ">>> 4.8 执行 runtime smoke" -if ! "${compose_cmd[@]}" exec -T server node src/scripts/smoke-trialrun-runtime.js; then +if ! "${compose_cmd[@]}" exec -T server node src/scripts/smoke-trialrun-runtime.js &2 "${compose_cmd[@]}" logs --tail=200 server || true exit 1 diff --git a/server/src/scripts/smoke-trialrun-runtime.js b/server/src/scripts/smoke-trialrun-runtime.js index fd9703af..68fe8f8a 100644 --- a/server/src/scripts/smoke-trialrun-runtime.js +++ b/server/src/scripts/smoke-trialrun-runtime.js @@ -43,17 +43,19 @@ const REQUIRED_MAIN_NAV_KEYS = [ 'leaveRequests', 'reimbursements', 'assets', - 'weeklyReports', + 'contractsRegistry', + 'purchaseRequests', + 'projects', 'todos', +]; + +const REQUIRED_BACKUP_NAV_KEYS = [ + 'weeklyReports', 'announcements', ]; const REQUIRED_ADMIN_NAV_KEYS = [ - 'workspace', - 'people', 'systemSettings', - 'featureFlags', - 'auditLogs', ]; const REQUIRED_WORKSPACE_VISIBILITY = { @@ -137,14 +139,18 @@ function assertNavigation(navigation) { const mainKeys = new Set((navigation.sections.main ?? []).map((item) => item.key)); const adminKeys = new Set((navigation.sections.admin ?? []).map((item) => item.key)); + const backupKeys = new Set((navigation.sections.backup ?? []).map((item) => item.key)); for (const key of REQUIRED_MAIN_NAV_KEYS) { assertCondition(mainKeys.has(key), `系统导航 main 缺少 ${key} 入口`); } + for (const key of REQUIRED_BACKUP_NAV_KEYS) { + assertCondition(backupKeys.has(key), `系统导航 backup 缺少 ${key} 入口`); + } for (const key of REQUIRED_ADMIN_NAV_KEYS) { assertCondition(adminKeys.has(key), `系统导航 admin 缺少 ${key} 入口`); } - console.log(`[PASS] 导航构建成功,main=${navigation.sections.main.length} admin=${navigation.sections.admin.length}`); + console.log(`[PASS] 导航构建成功,main=${navigation.sections.main.length} backup=${navigation.sections.backup.length} admin=${navigation.sections.admin.length}`); } async function main() {