From 2bb804bc9434972669ea4f4ab93f196acb8b012a Mon Sep 17 00:00:00 2001 From: shunli Date: Mon, 9 Feb 2026 17:45:52 +0800 Subject: [PATCH] =?UTF-8?q?chore(issues):=20=E6=9B=B4=E6=96=B0P5=E8=93=9D?= =?UTF-8?q?=E5=9B=BEv3=E7=8A=B6=E6=80=81=E5=BF=AB=E7=85=A7(F14,F30,F42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - F14/F30 标记 DONE(通知基础设施与触发) - 追加 F42 架构文档修订条目并标记 DONE --- issues/2026-02-09_13-39-02-p5-blueprint-v3.csv | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/issues/2026-02-09_13-39-02-p5-blueprint-v3.csv b/issues/2026-02-09_13-39-02-p5-blueprint-v3.csv index b9796cb6..60fd9d74 100644 --- a/issues/2026-02-09_13-39-02-p5-blueprint-v3.csv +++ b/issues/2026-02-09_13-39-02-p5-blueprint-v3.csv @@ -12,7 +12,7 @@ F10,判重例外(override duplicate),"新增 finance_mgr 判重例外接口 F11,OCR失败重试API(次数/频控),"新增 POST /api/invoice-pool/:id/retry-ocr:attempt<=3 且 60 秒频控;超限返回 VALID_006/VALID_007;写 audit_logs","ocr_failed 可重试回到 pending_ocr 并由 job 处理;频控与次数校验正确;mock 模式可回归","cd server && ./scripts/regression-ocr.sh && ./scripts/regression-audit.sh",manual,DONE,DONE,DONE,"server/src/routes/invoicePool.js | server/src/jobs/ocrJob.js | server/prisma/schema.prisma | server/prisma/migrations/* | server/scripts/regression-ocr.sh","[""F1""]","错误码新增需同步 client 错误文案映射" F12,90天未绑定自动归档(unused_timeout),"新增作业:available/ocr_failed 超过 90 天未绑定自动归档为 archived_reason=unused_timeout;并保证不参与判重","作业可重复运行幂等;归档后仍可查询/预览;不影响全局判重历史口径","cd server && ./scripts/regression-ocr.sh",manual,DONE,DONE,DONE,"server/src/jobs/invoiceArchiveJob.js | server/src/app.js | server/README.md","[""F11""]","后续迁移到 pg-boss;当前可先 node-cron 实现" F13,signed-url审计与下载行为记录,"对 signed-url 签发与下载两类事件写 audit_logs(不记录敏感 token 明文)","无权限仍 403;有权限获取 signed-url 与下载时均可在 audit_logs 检索到对应记录","cd server && ./scripts/regression-audit.sh",manual,DONE,DONE,DONE,"server/src/routes/invoicePool.js | server/src/routes/audit.js","[""F1""]","extra 仅保存 invoiceId/actorId/expireAt 等脱敏信息" -F14,站内通知基础设施(DB+API),"新增 notifications 表与 API(list/markRead),用于工作流与系统事件通知","可分页读取;可标记已读;权限隔离正确;最小索引满足试运行","cd server && npm run prisma:migrate:dev && ./scripts/regression-all.sh",manual,TODO,TODO,TODO,"server/prisma/schema.prisma | server/src/routes/notifications.js | server/src/app.js","[""F1""]","只做最小字段:title/body/type/targetId/readAt" +F14,站内通知基础设施(DB+API),"新增 notifications 表与 API(list/markRead),用于工作流与系统事件通知","可分页读取;可标记已读;权限隔离正确;最小索引满足试运行","cd server && npm run prisma:migrate:dev && ./scripts/regression-all.sh",manual,DONE,DONE,DONE,"server/prisma/schema.prisma | server/src/routes/notifications.js | server/src/app.js","[""F1""]","只做最小字段:title/body/type/targetId/readAt" F15,邮件通知(SMTP/Nodemailer),"引入 nodemailer 发送邮件:新待办/审批结果/付款完成/密码重置等;失败降级不阻塞主流程;可配置开关","EMAIL_ENABLED=false 时不发送;开启后可发出测试邮件;失败仅记录 audit/日志不影响业务","manual: 配置 SMTP 并触发一次待办通知/重置密码邮件",manual,TODO,TODO,TODO,"server/src/services/email/* | server/src/config.js | server/package.json","[""F14""]","优先复用成熟 nodemailer;写回滚说明" F16,前端通知入口(Bell),"新增通知列表页/弹层与未读角标;支持标记已读","四角色均可见自己的通知;读写后角标正确;e2e 覆盖核心路径","cd client && npm run test:e2e",manual,TODO,TODO,TODO,"client/src/components/navigation/Topbar.tsx | client/src/pages/NotificationsPage.tsx | client/src/api/notifications.ts","[""F14""]","保持 UI 轻量,不做复杂订阅推送" F17,报表导出(CSV/Excel),"新增报销/票据/审计的导出接口(权限控制),前端提供下载入口","导出字段与权限正确;大数据量时可分页/流式输出;审计记录导出操作","manual: 导出后核对字段;并在 audit_logs 中检索 EXPORT 动作",manual,TODO,TODO,TODO,"server/src/routes/exports.js | client/src/pages/* | server/package.json","[""F6"",""F16""]","推荐 exceljs 或 csv-stringify(二选一并写 Notes:用途/版本/回滚)" @@ -31,7 +31,7 @@ F26,部门API(departments),"补齐部门树/列表与管理接口:GET /api F27,员工API对齐(新增别名 /api/employees),"对齐规格书:在保留 /api/users 的同时新增 /api/employees 别名路由;补齐 GET详情/PATCH更新/POST archive;并保证本人可读自己的详情","/api/employees 与 /api/users 行为一致;system.users 可增改归档;本人可 GET 自己;审计完整","manual: 启动 server;以 admin@hyinda.com/AdminPassword1234 登录拿 accessToken;curl -sS -H 'authorization: Bearer ' 'http://127.0.0.1:3000/api/employees?page=1&pageSize=1' | jq;取 employeeId 后 curl -sS -H 'authorization: Bearer ' 'http://127.0.0.1:3000/api/employees/' | jq;再用普通 employee 登录拿 验证仅可 GET 自己且 GET 他人返回 403 PERM_001",manual,DONE,DONE,DONE,"server/src/routes/users.js | server/src/routes/employees.js | server/src/app.js | server/README.md","[""F26""]","优先复用既有 usersRoutes 实现,避免重复逻辑" F28,票据人工修正与手工归档(invoice-pool patch/archive),"补齐 PATCH /api/invoice-pool/:id(remarks/人工修正关键字段,允许 ocr_failed -> available);补齐 POST /api/invoice-pool/:id/archive(manual,未绑定才允许);写 audit_logs(INVOICE_POOL_EDITED/INVOICE_POOL_ARCHIVED)","服务端鉴权正确(owner/uploader/invoice.manage);人工修正后可参与 bind/判重;手工归档后不影响历史判重口径;审计可检索","cd server && ./scripts/regression-audit.sh",manual,DONE,DONE,DONE,"server/src/routes/invoicePool.js | server/scripts/regression-audit.sh | server/README.md","[""F1""]","extra.changes 仅记录必要字段的前后快照(避免敏感/大字段)" F29,配置只读API(approval-rules/document-sequences),"补齐只读配置接口:GET /api/approval-rules?enabled=true(登录即可);GET /api/document-sequences/reimbursement(system.settings 可选)","两接口返回结构稳定且不暴露敏感;不影响现有 submit 生成单号逻辑","manual: 启动 server;任意登录拿 accessToken;curl -sS -H 'authorization: Bearer ' 'http://127.0.0.1:3000/api/approval-rules?enabled=true' | jq;以 admin 登录拿 ;curl -sS -H 'authorization: Bearer ' 'http://127.0.0.1:3000/api/document-sequences/reimbursement' | jq",manual,DONE,DONE,DONE,"server/src/routes/configRead.js | server/src/app.js | server/README.md","[""F1""]","仅只读;写接口与更复杂可视化后置" -F30,通知触发集成(workflow/pay/auth),"把关键事件写入 notifications 并可选触发邮件:新待办/审批结果/付款完成/密码重置等;失败降级不阻塞主流程","提交后审批人收到通知;审批后 owner/submitter 收到结果;付款后收到通知;EMAIL_ENABLED=false 时仅站内通知;审计/日志可追踪","manual: 走一条 submit->approve->pay 链路并验证 notifications 与(可选)邮件",manual,TODO,TODO,TODO,"server/src/routes/workflow.js | server/src/routes/reimbursements.js | server/src/services/notifications/* | server/src/services/email/*","[""F14""]","先做站内通知,邮件作为可选增强(复用 nodemailer)" +F30,通知触发集成(workflow/pay/auth),"把关键事件写入 notifications 并可选触发邮件:新待办/审批结果/付款完成/密码重置等;失败降级不阻塞主流程","提交后审批人收到通知;审批后 owner/submitter 收到结果;付款后收到通知;EMAIL_ENABLED=false 时仅站内通知;审计/日志可追踪","manual: 走一条 submit->approve->pay 链路并验证 notifications 与(可选)邮件",manual,DONE,DONE,DONE,"server/src/routes/workflow.js | server/src/routes/reimbursements.js | server/src/services/notifications/* | server/src/services/email/*","[""F14""]","先做站内通知,邮件作为可选增强(复用 nodemailer)" F31,Delegation Grants API对齐(新增别名/增强响应),"新增 /api/delegation-grants 别名路由并增强现有 delegation API:响应内嵌 principal/delegate 员工摘要;system.users 可代维护 principal;delegate 资格校验:scope=reimbursement_submit 需 expense.proxy_submit(administration);scope=all 需 expense.approve;支持 includeInactive","/api/delegation-grants 与 /api/delegations 兼容;返回包含员工摘要;无权限阻断;代维护审计完整","manual: 启动 server;以 admin@hyinda.com/AdminPassword1234 登录拿 accessToken;curl -sS -H 'authorization: Bearer ' 'http://127.0.0.1:3000/api/delegation-grants' | jq;curl -sS -X POST -H 'authorization: Bearer ' -H 'content-type: application/json' 'http://127.0.0.1:3000/api/delegation-grants' -d '{delegateEmployeeId:... scope:... validTo:...}';验证 /api/delegations/mine 与 /api/delegation-grants 返回一致且包含 principal/delegate 摘要",manual,DONE,DONE,DONE,"server/src/routes/delegations.js | server/src/app.js | server/README.md","[""F27""]","不破坏既有 /api/delegations 客户端;新增别名优先" F32,前端组织与员工最小运营,"补齐前端最小组织能力:部门列表/创建/归档;在用户管理页支持部门选择与直属上级选择(管理员视角)","admin 可完成部门增改归档(含约束提示);可创建员工并选择部门与直属上级;typecheck/build 通过","cd client && npm run typecheck && npm run build",manual,TODO,TODO,TODO,"client/src/pages/DepartmentsPage.tsx | client/src/pages/UserManagementPage.tsx | client/src/api/departments.ts | client/src/api/employees.ts | client/src/router/index.tsx","[""F26"",""F27""]","单机试运行优先;部门树可简化为层级列表" F33,前端行政代提交/代上传入口,"为 administration 增加 owner 选择入口:报销创建可选 owner;票据上传可选 owner;并基于 delegation-grants 限定可选范围","有授权时可为指定员工创建/提交/上传;无授权时提示并阻断;typecheck/build/e2e 通过","cd client && npm run typecheck && npm run build && npm run test:e2e",manual,TODO,TODO,TODO,"client/src/pages/ReimbursementsPage.tsx | client/src/pages/InvoicePoolPage.tsx | client/src/api/reimbursements.ts | client/src/api/invoicePool.ts | client/src/api/delegations.ts | client/src/api/employees.ts","[""F7"",""F8"",""F31"",""F27""]","为 E2E 增加 data-testid(owner selector / submit/upload)" @@ -43,3 +43,4 @@ F38,首次登录改密与锁定提示(前端),"适配 mustChangePassword 流 F39,弱密码库拦截(Top 10k),"落实规格书:新增弱密码库拦截(Top 10k)并纳入 validatePassword;优先复用成熟库或公开词表;可配置开关","弱密码被拒绝并返回 VALID_001.details.password;正常密码不受影响;不显著增加接口延迟","manual: 用弱密码与强密码分别走创建用户/重置密码/改密流程验证",manual,DONE,DONE,DONE,"server/src/utils/passwordPolicy.js | server/package.json | server/README.md","[""F36""]","选型:zxcvbn@4.4.2;替代:owasp-password-strength-test;回滚:WEAK_PASSWORD_CHECK_ENABLED=false 或移除依赖回退 passwordPolicy" F40,组织/配置回归脚本(org+settings),"新增 server/scripts/regression-org-settings.sh:覆盖费用类型/部门/员工别名/配置只读/委派别名等关键权限与返回结构,并可选挂入 regression-all.sh","脚本可重复执行且全绿;覆盖关键正负例;失败输出可定位","cd server && ./scripts/regression-org-settings.sh",manual,DONE,DONE,DONE,"server/scripts/regression-org-settings.sh | server/scripts/regression-all.sh | server/README.md","[""F3"",""F29"",""F31""]","将上述 manual 验收逐步收敛为可回归门禁" F41,认证安全回归脚本(auth security),"新增 server/scripts/regression-auth-security.sh:覆盖首次登录改密 must_change_password 流程、登录失败锁定 AUTH_002 及弱密码拦截等核心负例","脚本可重复执行且全绿;可通过环境变量缩短锁定窗口以加速回归;失败输出可定位","cd server && ./scripts/regression-auth-security.sh",manual,DONE,DONE,DONE,"server/scripts/regression-auth-security.sh | server/scripts/regression-all.sh | server/README.md","[""F37"",""F39""]","建议脚本支持用 env 覆盖锁定窗口与阈值以加速测试" +F42,架构文档修订(As-Is/To-Be),"修订 docs/architecture.md:分层 As‑Is 与 To‑Be,更新部署视图/时序/ER/状态机,并补对标与演进说明","文档与当前实现一致;To‑Be 明确标注未实现;Mermaid 图可渲染","manual: 打开 docs/architecture.md 检查 As‑Is/To‑Be 标识与 Mermaid 渲染",manual,DONE,DONE,DONE,docs/architecture.md,[],仅文档改动,不涉及代码