From 76df8b6636453fa15b5af63dfc20bbd01a013d93 Mon Sep 17 00:00:00 2001 From: shunli Date: Wed, 27 May 2026 08:07:35 +0800 Subject: [PATCH] =?UTF-8?q?oa-email-code-login=20=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E5=85=AC=E7=BD=91=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .trellis/spec/hyb-oa/deployment-trialrun.md | 70 +++++++++++++++++++ .../05-26-oa-email-code-login/implement.md | 28 ++++++++ .../tasks/05-26-oa-email-code-login/prd.md | 20 +++--- deploy/trialrun/.env.example | 2 + 4 files changed, 112 insertions(+), 8 deletions(-) diff --git a/.trellis/spec/hyb-oa/deployment-trialrun.md b/.trellis/spec/hyb-oa/deployment-trialrun.md index f680a0e3..d5ee59ac 100644 --- a/.trellis/spec/hyb-oa/deployment-trialrun.md +++ b/.trellis/spec/hyb-oa/deployment-trialrun.md @@ -9,9 +9,79 @@ operations require explicit approval and evidence. - Use `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` only when deployment is approved; do not overwrite remote `.env`. +- When `server/src/config.js` reads a new environment key, add the same key to + `deploy/trialrun/.env.example` before deployment; `deploy/trialrun/deploy.sh` + runs `node deploy/trialrun/validate-env-contract.js` at step 0 and must fail + if the example contract drifts. - After deployment, report commit hash, `/ready`, public smoke results and whether the user can test. - Real business writes are manual unless an Issue explicitly authorizes a controlled test write. - Do not execute real payments, import bank statements, connect payment providers or write ERP without a separate approved Issue. + +## Scenario: Deployment Env Contract + +### 1. Scope / Trigger + +- Trigger: any backend config, deployment compose, or trialrun env wiring change. +- Purpose: prevent deploy-time surprises where local code compiles but the + deployment contract rejects the release or silently misses a runtime default. + +### 2. Signatures + +- Command: `node deploy/trialrun/validate-env-contract.js` +- Deployment entry: `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` +- Contract sources: + - `server/src/config.js` + - `deploy/trialrun/.env.example` + - `deploy/trialrun/docker-compose.yml` + +### 3. Contracts + +- Every `process.env.KEY` or `requiredEnv("KEY")` in `server/src/config.js` + must be present in `deploy/trialrun/.env.example`. +- `server`, `worker`, and `init` services must load `./.env` through + `env_file`. +- Compose service-level `environment` overrides are limited to the explicit + allowlist in `validate-env-contract.js`. +- `SYNC_ENV=0` is the default public deploy mode; it does not overwrite remote + `.env`. + +### 4. Validation & Error Matrix + +- Missing key in `.env.example` -> `validate-env-contract.js` exits non-zero. +- Service omits `env_file: ./.env` -> contract exits non-zero. +- Unauthorized compose override -> contract exits non-zero. +- Remote `.env` missing -> deploy step 4 exits before migration. + +### 5. Good/Base/Bad Cases + +- Good: add `EMAIL_LOGIN_CODE_TTL_SECONDS` to `config.js`, document it in + `.env.example`, then run contract validation before deploy. +- Base: code-only feature without env changes still runs the contract gate. +- Bad: add a config key only in `config.js`; deploy fails at step 0. + +### 6. Tests Required + +- Always run `node deploy/trialrun/validate-env-contract.js` after env-related + changes and before public deployment. +- For public deploys, also run or verify `/ready`, runtime smoke, external deps + smoke, public bundle copy scan, and live smoke when credentials exist. + +### 7. Wrong vs Correct + +#### Wrong + +```bash +# Config key exists only in server/src/config.js. +SYNC_ENV=0 bash deploy/trialrun/deploy.sh +``` + +#### Correct + +```bash +# Add the key to deploy/trialrun/.env.example first. +node deploy/trialrun/validate-env-contract.js +SYNC_ENV=0 bash deploy/trialrun/deploy.sh +``` diff --git a/.trellis/tasks/05-26-oa-email-code-login/implement.md b/.trellis/tasks/05-26-oa-email-code-login/implement.md index 952fa910..9542e5f5 100644 --- a/.trellis/tasks/05-26-oa-email-code-login/implement.md +++ b/.trellis/tasks/05-26-oa-email-code-login/implement.md @@ -55,3 +55,31 @@ - Trellis governance 对历史任务 `05-26-oa-auth-layout-wecom-login-ux` 的 jsonl 仍保留 `docs/产品设计规则.md` context warning;这是已提交历史任务的上下文提醒,不影响本任务通过。 - 公网部署和 live smoke 需要本地提交后另行确认。 + +## Deployment And Public Smoke Log + +- 用户已批准执行部署与公网验证。 +- 部署前已完成远端备份: + - DB 备份:`hyb-oa-db-20260527_075800.dump` + - 文件存储备份:`hyb-oa-storage-20260527_075801.tar.gz` + - 远端环境配置副本:`hyb-oa-env-20260527_075800.env` +- 部署命令采用 `SYNC_ENV=0`,未覆盖远端 `.env`。 +- 部署脚本已通过: + - 部署环境契约校验。 + - Docker 前端 production build。 + - Prisma migration deploy,已应用 `20260526211500_email_code_login`。 + - Prisma migration status:schema up to date。 + - `/ready`、external deps smoke、runtime smoke。 + - 公网 live smoke:3 passed。 + - 公网前端资源文案扫描:`findings=0`。 +- 补充公网验证已通过: + - `check-live-smoke-env.mjs --strict`:public ready、企微 ready、live smoke 与 OCR 条件均 ready。 + - 邮箱验证码公网后端探测:不存在账号请求验证码返回通用成功;伪造验证码校验被拒绝,未暴露账号存在性。 + - 公网前端 focused E2E:登录页找回密码/PWA 输入保护、邮箱验证码登录、找回密码流程,3 passed。 + - 公网企业微信入口 E2E:普通浏览器次级入口、企业微信场景主 CTA,2 passed。 + - 公网登录页截图与溢出检查:PC 密码登录、PC 邮箱验证码、移动企微入口均通过。 +- 视觉截图: + - `output/playwright/oa-email-code-login-live/desktop-password-login.png` + - `output/playwright/oa-email-code-login-live/desktop-email-code-login.png` + - `output/playwright/oa-email-code-login-live/mobile-wecom-login.png` +- 远端近期 server 日志摘要:近 5 分钟 error-like 行数为 0。 diff --git a/.trellis/tasks/05-26-oa-email-code-login/prd.md b/.trellis/tasks/05-26-oa-email-code-login/prd.md index 594565f2..70988522 100644 --- a/.trellis/tasks/05-26-oa-email-code-login/prd.md +++ b/.trellis/tasks/05-26-oa-email-code-login/prd.md @@ -57,14 +57,14 @@ ## Acceptance Criteria -- [ ] 普通浏览器登录页可切换密码登录和邮箱验证码登录。 -- [ ] 邮箱验证码请求成功时显示通用提示,不暴露账号是否存在。 -- [ ] 正确验证码可完成登录并进入原 redirect 目标。 -- [ ] 错误、过期或已使用验证码不能登录,并有可理解错误提示。 -- [ ] 企业微信 WebView 登录层级不回退,企微一键进入仍为主入口。 -- [ ] 找回密码验证码和登录验证码数据、接口、审计语义隔离。 -- [ ] 前端不持久化验证码、密码或 token。 -- [ ] 后端单测、前端 typecheck/build、关键 E2E 和设计规则检查通过。 +- [x] 普通浏览器登录页可切换密码登录和邮箱验证码登录。 +- [x] 邮箱验证码请求成功时显示通用提示,不暴露账号是否存在。 +- [x] 正确验证码可完成登录并进入原 redirect 目标。 +- [x] 错误、过期或已使用验证码不能登录,并有可理解错误提示。 +- [x] 企业微信 WebView 登录层级不回退,企微一键进入仍为主入口。 +- [x] 找回密码验证码和登录验证码数据、接口、审计语义隔离。 +- [x] 前端不持久化验证码、密码或 token。 +- [x] 后端单测、前端 typecheck/build、关键 E2E 和设计规则检查通过。 ## Definition of Done @@ -85,6 +85,10 @@ - 不执行真实账号重置、真实业务写入或公网部署。 - 不改变密码找回流程。 +## Post-Approval Scope Extension + +- 用户后续明确批准部署和公网测试;已按 `SYNC_ENV=0` 执行公网部署,不覆盖远端 `.env`,并完成 live smoke、登录专项 E2E、邮箱验证码公网后端探测和视觉截图验证。 + ## Proposed Implementation 1. Backend schema: diff --git a/deploy/trialrun/.env.example b/deploy/trialrun/.env.example index d866bdce..8e1a1c94 100644 --- a/deploy/trialrun/.env.example +++ b/deploy/trialrun/.env.example @@ -37,6 +37,8 @@ FIELD_ENCRYPTION_KEY= # ===== 密码 / 登录安全 ===== PASSWORD_RESET_CODE_TTL_SECONDS=600 DEV_SHOW_PASSWORD_RESET_CODE=false +EMAIL_LOGIN_CODE_TTL_SECONDS=600 +EMAIL_LOGIN_CODE_MAX_ATTEMPTS=5 AUTH_LOGIN_FAIL_WINDOW_SECONDS=900 AUTH_LOGIN_FAIL_MAX_ATTEMPTS=5 AUTH_LOGIN_LOCK_SECONDS=1800