From df0bc8ceed5c5d960c002d3a2b01335471564c13 Mon Sep 17 00:00:00 2001 From: xiangning Date: Mon, 20 Jul 2026 08:34:52 +0800 Subject: [PATCH] docs: define react pro integration foundation --- ...react-pro-integration-foundation-design.md | 316 ++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-20-react-pro-integration-foundation-design.md diff --git a/docs/superpowers/specs/2026-07-20-react-pro-integration-foundation-design.md b/docs/superpowers/specs/2026-07-20-react-pro-integration-foundation-design.md new file mode 100644 index 0000000..6c4f390 --- /dev/null +++ b/docs/superpowers/specs/2026-07-20-react-pro-integration-foundation-design.md @@ -0,0 +1,316 @@ +# React Pro 全面对接第一阶段:工程基线与 API 契约设计 + +## 1. 背景 + +BuildFlow 当前有三个与本设计直接相关的代码库: + +- `build-flow.admin`:Ant Design Pro 6、Umi Max 4、React 19、antd 6。当前仍以模板页面为主,仅初步接入登录、当前用户和动态菜单。 +- `build-flow.api`:.NET 10、FastEndpoints,所有业务 HTTP 入口位于 `BuildFlow.Host`。当前 Swagger 暴露 173 个路径,Host 下约有 223 个 Endpoint。 +- `build-flow.web`:旧 Vue/Vben 前端。它不是新前端的代码来源,而是现有用户功能、字段映射和交互行为的验收参考。 + +后端当前动态菜单包含 30 个路由节点,权限接口返回 83 个权限码,业务横跨 Platform、File、RAG、Workflow、Scripting、IM、Monitoring 七个域。全面迁移必须先建立稳定的工程基线、可重复的 API 契约生成方式和统一传输层,否则逐页面迁移会持续产生接口漂移。 + +## 2. 本阶段目标 + +本阶段交付后,React Pro 应具备后续业务模块可直接复用的基础设施: + +1. 前端依赖安装、类型检查、代码检查、单元测试和生产构建都有确定且可重复的命令。 +2. 后端 Swagger 可匿名读取,并能生成提交到仓库的 OpenAPI 快照。 +3. BuildFlow API 类型和普通 HTTP 客户端由 OpenAPI 生成,生成目录禁止手工编辑。 +4. 登录、当前用户、用户菜单、权限码和刷新令牌使用统一的 BuildFlow 传输层。 +5. JSON 信封、纯文本刷新、文件下载、上传、SSE 和 SignalR 有明确且互不干扰的处理边界。 +6. 建立 API 合约测试、传输层单元测试、真实后端冒烟测试和浏览器登录冒烟测试。 +7. 提供可以重复执行的第一阶段 SOP,并作为后续每个业务域的共同验收前置条件。 + +本阶段不实现用户、角色、文件、知识库、工作流等完整业务页面;这些页面在后续阶段依次交付。但本阶段必须把登录后的菜单、用户状态和权限状态加载通,证明基础链路真实可用。 + +## 3. 已确认的现状与问题 + +### 3.1 前端基线 + +- `npm run build` 当前可以生成 `dist`。 +- `npm run lint` 当前失败:根 `tsconfig.json` 把独立的 `cloudflare-worker` 包含进主应用类型检查,同时缺少 `geojson` 类型声明。 +- Jest 当前无法启动:`jest.config.ts` 直接读取 `node_modules/@utoo/pack/package.json`,但该包不是根项目的可靠直接依赖。 +- `CLAUDE.md` 规定使用 npm 和 `package-lock.json`,实际目录却只有 `pnpm-lock.yaml` 和一个不含 package 列表的 `pnpm-workspace.yaml`。 +- `config/oneapi.json` 仍是 Ant Design Pro 示例,仅有 7 条 demo 路径。 +- `src/services/ant-design-pro/` 是生成目录,但登录和菜单代码已被手工改写,违反项目自身的生成代码规则。 +- 当前没有自动刷新 access token 的实现。 + +### 3.2 后端基线 + +- `dotnet build BuildFlow.slnx --no-restore -m:1` 当前通过,0 warning、0 error。 +- 完整测试基线为 769 通过、26 失败。其中 23 个失败与本地 MongoDB 未启动有关,另外 3 个分别来自 RAG 测试依赖注册和 Scripting 断言。 +- `/swagger/v1/swagger.json` 当前被全局 fallback authorization 拦截,匿名请求返回 401;携带 admin token 后可读取 173 条路径和 312 个 schema。 +- `POST /api/auth/login` 成功响应为 `{ code: 0, message: "ok", data: ... }`。 +- 当前运行实例对空登录请求返回 HTTP 500 `internal_error`,而预期应是 HTTP 400 `invalid_param`。 +- `/api/auth/refresh` 使用 HttpOnly `jwt` Cookie,成功时返回 `text/plain` access token,并轮换 refresh token。 + +## 4. 方案选择 + +采用“契约驱动、手写特殊协议适配器”的混合方案: + +- 普通 JSON CRUD 和查询接口:从提交到仓库的 OpenAPI 快照生成类型和请求函数。 +- 认证状态、刷新重放、错误映射:使用手写传输层,因为它们是跨接口策略,不能由生成器正确表达。 +- 文件上传、下载、SSE、SignalR:使用手写适配器,因为这些接口不遵循普通 JSON 信封生命周期。 +- 页面只依赖域适配器,不直接依赖生成函数。后端字段或生成器变化只影响适配器,不扩散到页面。 + +不采用纯手工 service 方案,因为 173 条路径会造成长期类型漂移;不采用全元数据 CRUD 方案,因为文件、聊天、流程设计器和流式 AI 不适合统一 CRUD 抽象。 + +## 5. 目录与所有权 + +目标结构如下: + +```text +build-flow.admin/ + config/ + openapi/ + buildflow.json # 已校验并提交的后端契约快照 + scripts/ + sync-openapi.mjs # 从运行中的后端抓取、校验、规范化快照 + check-openapi.mjs # 检查快照和生成结果是否过期 + src/services/buildflow/ + generated/ # OpenAPI 生成,禁止手工编辑 + transport/ # token、信封、refresh、请求重放 + adapters/ # auth/menu/access 以及后续各业务域适配器 + download.ts # 二进制下载与文件名提取 + upload.ts # 普通/分片上传公共能力 + sse.ts # 流式请求公共能力 + signalr.ts # Hub 连接公共能力 + tests/e2e/ # Playwright 真实浏览器冒烟测试 +``` + +约束: + +- `src/services/ant-design-pro/` 恢复为模板生成目录,不再承载 BuildFlow 业务代码。 +- 只有 `adapters` 可以直接导入 `src/services/buildflow/generated/`;页面只能调用 `adapters` 或特殊协议入口。 +- OpenAPI 同步只更新快照,代码生成只更新 `generated`。两者都由脚本执行,禁止人工修改输出。 +- 后端 HTTP 变更继续只发生在 `BuildFlow.Host`,跨模块协作遵循现有 MediatR CQRS 约束。 + +## 6. 工程基线设计 + +### 6.1 包管理器 + +以 `build-flow.admin/CLAUDE.md` 为项目规则来源,统一使用 npm: + +1. 补齐根项目所有直接使用的依赖,生成并提交 `package-lock.json`。 +2. 删除根目录的 `pnpm-lock.yaml` 和无有效 package 声明的 `pnpm-workspace.yaml`。 +3. CI 和 SOP 统一使用 `npm ci`,不得混用 pnpm 或 yarn。 +4. `cloudflare-worker` 继续作为独立应用维护自己的 `package.json` 和安装命令,不加入根应用类型检查或测试门槛。 + +### 6.2 TypeScript、Biome 和生成目录 + +- 根 `tsconfig.json` 只包含 React Pro 主应用、配置、脚本和测试所需类型,排除 `cloudflare-worker`、`dist`、`.umi`、`.umi-production` 和其他生成目录。 +- 为直接导入的库补齐类型依赖,不使用全局 `declare module '*'` 掩盖真实类型问题。 +- Biome 只检查主应用拥有的源码;独立 Worker 使用自己的检查命令。 +- 保留严格 TypeScript,不通过关闭 `strict`、`noImplicitReturns` 或扩大 `skipLibCheck` 来换取通过。 + +### 6.3 Jest + +- Jest 读取包版本时使用 Node 的模块解析结果,或把构建时直接引用的包声明为直接依赖,不假设 pnpm 的虚拟目录布局。 +- 测试环境统一初始化 `localStorage`、`history`、`fetch` 和必要的浏览器 API。 +- 网络单元测试使用可控 mock,不连接真实后端;真实后端测试单独放在 smoke/e2e 层。 + +### 6.4 版本控制基线 + +`build-flow.admin` 当前没有 `.git` 元数据。实施代码变更前必须: + +1. 初始化本地 Git 仓库,但不创建远程仓库、不推送代码。 +2. 确认 `node_modules`、`dist`、`.umi`、`.umi-production` 和本地环境文件已被忽略。 +3. 把当前用户已有源码作为原样 baseline 提交,不重写、不清理模板内容。 +4. 后续每个阶段使用 Conventional Commits 独立提交,确保能区分用户基线与对接改动。 + +## 7. OpenAPI 契约设计 + +### 7.1 Swagger 可访问性 + +`/swagger/**` 由 Swagger middleware 在 authentication、authorization 和 FastEndpoints 之前处理。只允许开放 API 文档,不放宽 `/api/**` 的默认拒绝策略,也不为业务 Endpoint 增加匿名例外。 + +验收请求: + +```bash +curl -fsS http://localhost:5667/swagger/v1/swagger.json +``` + +必须返回 HTTP 200,根对象包含 `openapi`、`info`、`paths` 和 `components`。 + +### 7.2 快照同步 + +`npm run api:sync` 执行以下步骤: + +1. 从 `BUILDFLOW_API_ORIGIN` 读取 `/swagger/v1/swagger.json`,默认 origin 为 `http://localhost:5667`。 +2. 校验文档类型、版本、已知关键路径和 schema 数量。 +3. 对 JSON 键排序并规范化格式,避免无意义 diff。 +4. 原子替换 `config/openapi/buildflow.json`。 +5. 拒绝 Ant Design Pro demo 路径成为 BuildFlow 契约来源。 + +关键路径至少包含: + +- `/api/auth/login` +- `/api/user/info` +- `/api/menu/all` +- `/api/auth/codes` +- `/api/users` +- `/api/knowledge-bases` +- `/api/workflow-definitions` +- `/api/scripts` +- `/api/monitoring/systems` + +刷新接口被后端有意排除在 Swagger 外,由手写传输层维护并由独立合约测试覆盖。 + +### 7.3 代码生成 + +`npm run api:generate` 只读取本地快照,因此生产构建和 CI 不依赖后端在线。生成结果写入 `src/services/buildflow/generated/`,使用独立命名空间,避免与模板的 `API` 全局命名空间冲突。 + +`npm run api:check` 在临时目录重新生成并比较结果;如果快照或生成代码过期,命令失败。`npm run build` 不应隐式联网或静默重写生成代码。 + +## 8. 请求与认证数据流 + +### 8.1 普通请求 + +```text +page -> domain adapter -> generated function -> BuildFlow transport + -> Authorization + locale + credentials + -> /api endpoint + -> HTTP/status + envelope validation + -> typed business data or normalized error +``` + +统一约定: + +- API 基地址为 `/api`,开发环境由 Umi proxy 转发,生产环境使用同源反向代理。 +- 请求携带 `Authorization: Bearer `、`Accept-Language` 和 Cookie credentials。 +- 只有 `code === 0` 或 `code === "0"` 是成功信封。 +- HTTP 2xx 但业务 code 非 0、HTTP 4xx/5xx、非 JSON 错误都转换为同一种 `BuildFlowRequestError`。 +- 页面不解析原始 response 或信封,也不自行拼接错误提示。 + +### 8.2 登录与初始状态 + +1. 登录调用 `/auth/login`,成功后只持久化 access token;refresh token 由 HttpOnly Cookie 管理。 +2. 登录完成后加载 `/user/info`、`/menu/all` 和 `/auth/codes`。 +3. `getInitialState` 保存当前用户、菜单树和权限码集合。 +4. `access.ts` 提供 `can(code)`、`canAny(codes)`、`canAll(codes)`,并保留模板 `canAdmin` 兼容入口。 +5. 菜单转换器规范化相对路径、图标、隐藏规则和权限信息;页面路由仍必须在编译期 route registry 中存在。 + +### 8.3 刷新与请求重放 + +- 401 时只允许创建一个共享 refresh promise;并发失败请求等待同一个刷新结果。 +- `/auth/login`、`/auth/refresh`、匿名分享接口和已经重放过一次的请求不得再次触发 refresh。 +- refresh 成功后更新 access token,并各自重放原请求一次。 +- refresh 失败时只执行一次清理和登录跳转,保留当前 URL 作为 redirect。 +- 请求取消信号、上传进度和调用方 options 在重放时必须保留。 +- 不得把 refresh token 写入 `localStorage`、日志、错误对象或前端状态。 + +### 8.4 特殊协议 + +- `/auth/refresh`:`text/plain`,不走 JSON 信封解包。 +- 下载和预览:返回 Blob/stream,按 `Content-Disposition` 提取文件名,不走 JSON 解包。 +- SSE:使用 fetch/readable stream,保留取消能力,不进入响应缓冲。 +- SignalR:使用 Hub 自身握手和重连机制,access token 通过 token factory 提供。 +- 上传:支持 `FormData`,不得手工设置 multipart boundary;分片上传复用统一重试和取消策略。 + +## 9. 后端契约修复 + +第一阶段只修改支撑所有前端模块的后端横切契约: + +1. Swagger JSON 和 UI 匿名可读,业务 API 仍默认要求认证。 +2. 登录请求缺字段或字段不合法时返回 HTTP 400,信封 code 为 `invalid_param`。 +3. 用户名或密码错误时返回 HTTP 401,信封 code 为 `unauthorized`,不泄露具体失败字段。 +4. 成功登录返回 HTTP 200、code 0、access token,并设置 HttpOnly `jwt` Cookie。 +5. refresh 成功返回 HTTP 200 `text/plain` access token并轮换 Cookie;失败返回 HTTP 401 错误信封。 +6. `/user/info`、`/menu/all`、`/auth/codes` 的匿名访问均返回 HTTP 401。 + +这些行为必须由 Host 集成测试证明,不能只依赖前端兼容代码。 + +## 10. 测试设计 + +### 10.1 前端单元测试 + +至少覆盖: + +- token 读取、写入和清理。 +- code 0 成功解包,字符串/数字错误码映射。 +- JSON、纯文本、Blob 响应分流。 +- 20 个并发 401 只产生一次 refresh 请求。 +- refresh 成功后的单次重放和 refresh 失败后的单次登出。 +- `currentUser`、menu、access code 字段适配。 +- 相对菜单路径递归规范化。 +- OpenAPI 快照关键路径校验和生成结果过期检查。 + +### 10.2 后端测试 + +新增 Host 合约测试,覆盖第 9 节全部行为。继续执行: + +```bash +dotnet build BuildFlow.slnx --no-restore -m:1 +dotnet test tests/BuildFlow.Architecture.Tests --no-build +dotnet test tests/BuildFlow.Platform.Tests --no-build +``` + +完整 `dotnet test BuildFlow.slnx --no-build -m:1` 也必须执行并记录。依赖 MongoDB 的测试通过测试基础设施启动对应服务,而不是永久跳过。现有 RAG 和 Scripting 的非基础设施失败要进入缺陷清单并在最终全量回归前清零。 + +### 10.3 API 冒烟测试 + +对真实本地后端执行: + +- 匿名 Swagger。 +- 登录成功、参数错误、凭据错误。 +- 当前用户、菜单、权限码。 +- refresh rotation 和旧 refresh token 失效。 +- 未认证访问被拒绝。 + +冒烟脚本不得输出 token、Cookie 或连接串。 + +### 10.4 浏览器 E2E + +Playwright 使用真实后端和测试账号验证: + +1. 打开登录页。 +2. 错误密码显示统一错误且不离开页面。 +3. 正确登录进入用户 home path。 +4. 页面显示真实用户信息和后端菜单。 +5. 刷新页面仍保持会话。 +6. 模拟 access token 失效后只刷新一次并恢复请求。 +7. refresh 失败后跳回登录页并携带 redirect。 + +## 11. SOP 与命令门槛 + +第一阶段结束时,前端应提供以下稳定命令: + +```bash +npm ci +npm run api:sync +npm run api:generate +npm run api:check +npm run lint +npm test -- --runInBand +npx antd lint ./src +npm run build +npm run test:smoke +npm run test:e2e +npm run verify +``` + +`npm run verify` 依次执行不依赖在线服务的契约检查、lint、单元测试和构建。真实 API smoke 与 E2E 由单独命令执行,要求后端和测试基础设施已启动。 + +后端运行端口以 `src/BuildFlow.Host/appsettings.json` 的 5667 为本地默认值。`run-dev.sh`、前端代理和文档必须统一,不再同时声明 5200 与 5667。 + +## 12. 验收标准 + +本阶段只有同时满足以下条件才算完成: + +1. 全新目录执行 `npm ci` 成功,仓库只存在 npm 根锁文件。 +2. React Pro 已建立保留原始现状的 Git baseline,阶段改动使用独立 Conventional Commits。 +3. 前端 `lint`、Jest、antd lint、build 全部退出 0。 +4. 匿名 Swagger 返回 200;OpenAPI 快照和生成代码检查通过。 +5. BuildFlow 业务代码不再手工修改 `src/services/ant-design-pro/`。 +6. 登录、当前用户、30 个菜单节点和 83 个权限码由真实后端成功加载。 +7. 并发 401 单次刷新、单次重放和失败登出均有自动化测试。 +8. 后端 build、Architecture tests、Platform tests 和新增 Host 合约测试全部通过。 +9. API smoke 与 Playwright 登录链路全部通过,且日志不泄露凭据。 +10. 第一阶段 SOP 在一台未使用当前 `node_modules` 的环境中可重复执行。 + +## 13. 后续阶段接口 + +后续每个业务域都复用本阶段的 transport、生成客户端、域适配器模式和测试门槛。业务阶段只能新增域适配器与页面,不得各自实现 token、refresh、信封、下载、SSE 或 SignalR 的第二套基础逻辑。 + +阶段顺序保持为:Platform -> File -> RAG -> Workflow/BuildFlow -> Scripting -> IM -> Monitoring -> 全量回归与发布 SOP。