修复认证验证码投递与登录入口体验 05-27-oa-auth-delivery-wecom-entry-fix
这个提交包含在:
@@ -0,0 +1,4 @@
|
||||
{"file": ".trellis/spec/hyb-oa/backend-fastify-prisma.md", "reason": "Check backend syntax, focused route tests and Prisma validation."}
|
||||
{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Check frontend typecheck, build, Playwright auth flows and screenshot evidence."}
|
||||
{"file": ".trellis/spec/hyb-oa/security-privacy.md", "reason": "Check test output and task notes do not expose SMTP secrets, real verification codes or sensitive accounts."}
|
||||
{"file": ".trellis/spec/hyb-oa/wecom-boundary.md", "reason": "Check ordinary browser WeCom entry is non-clickable while WebView CTA remains available."}
|
||||
@@ -0,0 +1,4 @@
|
||||
{"file": ".trellis/spec/hyb-oa/backend-fastify-prisma.md", "reason": "Auth route and email service changes must follow backend route/service validation rules."}
|
||||
{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Login and forgot-password UI changes must follow auth-page layout, PWA and frontend design contracts."}
|
||||
{"file": ".trellis/spec/hyb-oa/security-privacy.md", "reason": "Auth delivery work must avoid leaking credentials, verification codes, tokens or account-existence signals."}
|
||||
{"file": ".trellis/spec/hyb-oa/wecom-boundary.md", "reason": "Enterprise WeChat login entry behavior must preserve OA/WeCom boundary and avoid unapproved backend OAuth changes."}
|
||||
@@ -0,0 +1,15 @@
|
||||
# Implementation Notes
|
||||
|
||||
## Approach
|
||||
|
||||
- Backend exposes `/api/auth/capabilities` with non-secret email delivery readiness.
|
||||
- Email-login code and forgot-password code requests fail before account lookup when SMTP delivery is not configured, preserving account enumeration protection.
|
||||
- Verification email copy uses Chinese Beijing-time expiry wording instead of ISO UTC timestamps.
|
||||
- Normal browsers show Enterprise WeChat as an informational entry only; Enterprise WeChat WebView keeps one-click login as the primary CTA.
|
||||
- Frontend email-code login and forgot-password pages disable code sending when delivery is not ready.
|
||||
|
||||
## Verification Focus
|
||||
|
||||
- Backend unit coverage for delivery capability, delivery-unavailable behavior and Beijing-time email wording.
|
||||
- Frontend E2E coverage for password visibility, PWA update prompt, email-code login, disabled email delivery state, forgot-password flow and Enterprise WeChat entry hierarchy.
|
||||
- Deployment checks report public auth capability status without printing SMTP values.
|
||||
@@ -0,0 +1,124 @@
|
||||
# 认证验证码投递与企业微信入口修复
|
||||
|
||||
## Goal
|
||||
|
||||
修复部署后认证入口的两个真实问题:邮箱登录验证码和密码重置验证码无法收到;普通浏览器点击企业微信登录会跳转到只能在企业微信内使用的 OAuth 页面并报错。目标是让认证入口行为和真实能力一致,避免用户误判“验证码已发送”或点击错误入口。
|
||||
|
||||
## Scope
|
||||
|
||||
- 本任务覆盖后端认证接口、邮件投递能力探测、认证验证码邮件文案、登录页、找回密码页、普通浏览器企业微信入口提示、部署检查和对应自动化测试。
|
||||
- 本任务不接入 PC 企业微信扫码登录,不修改企业微信后台配置,不在未获批准时继续修改远端 `.env` 或部署代码。
|
||||
|
||||
## What I Already Know
|
||||
|
||||
- 用户反馈:
|
||||
- 邮箱收不到登录验证码和密码重置验证码。
|
||||
- 点击企业微信登录报错,实际需要在企业微信里点击。
|
||||
- 登录验证码和密码重置验证码都通过 `sendNotificationEmailSafe` + SMTP 邮件服务发送。
|
||||
- 公网远端运行时配置显示:
|
||||
- `emailEnabled=false`
|
||||
- `smtpHost=false`
|
||||
- `smtpUser=false`
|
||||
- `smtpPass=false`
|
||||
- `emailFrom=true`
|
||||
- `smtpPort=587`
|
||||
- `smtpSecure=false`
|
||||
- 本地 `~/.hyb-oa/live-smoke.env` 也没有 SMTP 配置可直接同步。
|
||||
- 当前邮箱验证码接口会在账号存在且 active 时创建验证码和审计记录,然后异步调用邮件发送;当邮件服务关闭时,用户仍看到通用成功提示。
|
||||
- 当前普通浏览器下只要 `wecomEntry` ready,就显示“企业微信登录”按钮;点击后进入 `/api/auth/wecom/login` 并跳转企业微信 OAuth。
|
||||
- 当前企业微信入口的 OAuth 设计是企业微信工作台/WebView 入口,不是 PC 浏览器扫码登录。
|
||||
|
||||
## Diagnosis
|
||||
|
||||
- 邮箱问题的直接原因是公网试运行环境未启用或配置 SMTP,两个验证码功能没有可用邮件通道。
|
||||
- 代码体验问题是认证页没有把“邮件服务未启用”和“普通浏览器不支持企业微信 OAuth”转化为清晰交互。
|
||||
- 安全约束:验证码请求仍必须避免账号枚举。不能因为邮箱是否存在而返回不同提示。
|
||||
|
||||
## Discussion Notes
|
||||
|
||||
- 企业邮箱 SMTP 配置复杂度低,前提是企业邮箱已允许客户端 SMTP,且能为专用发件邮箱生成客户端专用密码或授权码。
|
||||
- 推荐使用独立发件邮箱,例如 `oa` 或 `no-reply` 类账号;不要使用个人员工邮箱或管理员真实登录密码。
|
||||
- 试运行环境当前缺 SMTP 配置,因此必须先补远端 `.env` 并重启 server,才能验证真实收信。
|
||||
- PC 企业微信扫码登录是独立能力,不等同于当前“企业微信内 OAuth 免登”。它适合 PC 常用用户,但需要单独配置企业微信授权登录回调域、前端二维码入口和后端扫码回调处理。
|
||||
- 当前修复建议先做 SMTP 投递和普通浏览器企业微信入口防误点;PC 企业微信扫码登录可列为后续 P1,不放进本次故障修复 MVP。
|
||||
|
||||
## Requirements
|
||||
|
||||
- 邮件服务全局未启用或 SMTP 未配置时:
|
||||
- 登录页邮箱验证码发送应提示“邮件服务暂未启用,请联系管理员或使用密码登录”,而不是“验证码将发送”。
|
||||
- 忘记密码页应给出同类提示。
|
||||
- 不暴露输入邮箱是否存在。
|
||||
- 公网/部署检查应能发现邮件验证码依赖的 SMTP 未启用状态,避免再次“功能上线但无法收信”。
|
||||
- 普通浏览器下:
|
||||
- 不提供可点击的企业微信 OAuth 登录按钮。
|
||||
- 显示清晰提示:企业微信一键进入需从企业微信工作台或企业微信内打开 OA。
|
||||
- 不影响企业微信 WebView 下主 CTA。
|
||||
- 企业微信 WebView 下:
|
||||
- 企微一键进入仍为主入口。
|
||||
- 账号密码/邮箱验证码兜底仍可按现有逻辑出现。
|
||||
- 不打印、提交或写入 SMTP 密码、真实邮箱、验证码、token、Secret。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] 公网或本地配置缺 SMTP 时,邮箱验证码和忘记密码不再误提示“验证码已发送”。
|
||||
- [ ] 配置完整时,验证码请求仍返回通用成功,不暴露账号是否存在。
|
||||
- [ ] 普通浏览器不再点击进入企业微信 OAuth 报错页。
|
||||
- [ ] 企业微信 WebView 下企业微信主入口不回退。
|
||||
- [ ] 后端/前端测试覆盖邮件服务未启用提示和普通浏览器企微入口提示。
|
||||
- [ ] 部署/公网检查能报告邮件投递配置是否 ready。
|
||||
- [ ] 需要真实收信验证时,仅在获得 SMTP 凭据和远端配置修改批准后执行。
|
||||
|
||||
## Proposed Implementation
|
||||
|
||||
1. Backend:
|
||||
- 增加一个安全的公开认证能力配置接口,或扩展现有公开 auth config,暴露 `emailDeliveryReady` 这类非敏感布尔值。
|
||||
- 在邮箱验证码和忘记密码请求中,若邮件服务全局未配置,返回统一错误(不依赖邮箱是否存在),让前端能提示服务未启用。
|
||||
2. Frontend:
|
||||
- 登录页邮箱验证码模式根据 `emailDeliveryReady` 禁用发送按钮并显示说明。
|
||||
- 忘记密码页根据 `emailDeliveryReady` 禁用发送或显示服务未启用说明。
|
||||
- 普通浏览器下企业微信区域改为说明性入口,不触发 OAuth;企业微信 WebView 才显示可点击 CTA。
|
||||
3. QA:
|
||||
- 增加/更新 auth 单测覆盖邮件未配置分支。
|
||||
- 更新登录页、忘记密码、企微入口 E2E。
|
||||
- 更新 live smoke/env 检查,输出邮件投递 ready 状态但不打印 SMTP 值。
|
||||
4. Operations:
|
||||
- 若用户提供并批准 SMTP 配置,先备份远端 `.env`,再写入 SMTP 相关键并重启 server。
|
||||
- 配置后执行一次受控真实收信验证,不在日志和记录中保存验证码。
|
||||
|
||||
## Test Plan
|
||||
|
||||
```bash
|
||||
cd server && node --check src/routes/auth.js src/routes/wecomAuth.js src/config.js
|
||||
cd server && npm test -- --run tests/unit/routes/auth.login.test.js
|
||||
cd client && npm run typecheck
|
||||
cd client && npm run build
|
||||
E2E_BASE_URL=http://127.0.0.1:5173 npx playwright test tests/e2e/login-portal-ux.spec.ts tests/e2e/wecom-entry.spec.ts --workers=1 --reporter=list
|
||||
node deploy/trialrun/validate-env-contract.js
|
||||
node scripts/qa/check-live-smoke-env.mjs
|
||||
python3 ./.trellis/scripts/task.py validate 05-27-oa-auth-delivery-wecom-entry-fix
|
||||
node scripts/qa/check-trellis-governance.mjs
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 不在本任务接入 PC 企业微信扫码登录。
|
||||
- 不在未获批准时修改远端 `.env`。
|
||||
- 不在聊天、Trellis、docs 或日志中记录 SMTP 密码、验证码或完整账号。
|
||||
- 不修改企业微信后台配置。
|
||||
|
||||
## Technical Notes
|
||||
|
||||
- Email service: `server/src/services/email/index.js`
|
||||
- Auth routes: `server/src/routes/auth.js`
|
||||
- WeCom auth routes: `server/src/routes/wecomAuth.js`
|
||||
- Login page: `client/src/pages/LoginPage.tsx`
|
||||
- WeCom entry helpers: `client/src/lib/wecomEntry.ts`
|
||||
- Runtime context: `client/src/lib/runtimeContext.ts`
|
||||
- Live env check: `scripts/qa/check-live-smoke-env.mjs`
|
||||
|
||||
## Progress Notes
|
||||
|
||||
- 公网 SMTP 配置已完成一次受控验证:有效企业邮箱可以收到登录验证码和密码重置验证码;邮件被企业邮箱归入免提醒邮件。
|
||||
- 本地代码已补齐认证能力接口、北京时间有效期文案、邮箱验证码入口禁用态和普通浏览器企业微信入口提示。
|
||||
- 截止本记录,代码改动尚未部署到公网;公网 `/api/auth/capabilities` 仍需部署后验证。
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"id": "oa-auth-delivery-wecom-entry-fix",
|
||||
"name": "oa-auth-delivery-wecom-entry-fix",
|
||||
"title": "认证验证码投递与企业微信入口修复",
|
||||
"description": "修复邮箱验证码真实投递能力、验证码有效期展示和普通浏览器企业微信入口误点击问题,并补齐登录页交互验证。",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": "server/client/auth",
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "shunli",
|
||||
"assignee": "shunli",
|
||||
"createdAt": "2026-05-27",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [
|
||||
"server/src/routes/auth.js",
|
||||
"server/src/services/email/index.js",
|
||||
"client/src/pages/LoginPage.tsx",
|
||||
"client/src/pages/ForgotPasswordPage.tsx",
|
||||
"client/src/api/auth.ts",
|
||||
"client/tests/e2e/login-portal-ux.spec.ts",
|
||||
"client/tests/e2e/wecom-entry.spec.ts"
|
||||
],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户