218 lines
12 KiB
Markdown
218 lines
12 KiB
Markdown
# 开发质量与前后端架构规范设计
|
||
|
||
- 功能编号:GOV-010
|
||
- 设计版本:0.1
|
||
- 状态:approved
|
||
- 日期:2026-08-13
|
||
|
||
## 1. 决策摘要
|
||
|
||
采用“规范文档 + 功能模板 + 自动门禁”的可执行治理方案。安全、性能、GitNexus 影响和同步修改进入设计、测试与 Review;实际完成事实进入独立 `development-summary.md`。前端将现有 `openapi-fetch` 请求实现迁移为统一 Axios 封装,继续使用 OpenAPI 生成类型。后端采用业务模块垂直组织、模块内部按需分层,不强制空目录或透传层。
|
||
|
||
## 2. 方案比较
|
||
|
||
### 方案 A:文档、模板与关键门禁结合(采用)
|
||
|
||
优点是关键证据可以自动阻断,架构职责仍保留工程判断空间;既不会让规范沦为建议,也不会因为一个固定目录生成器迫使小模块过度设计。成本是治理脚本和边界校验需要测试,并且后端分层仍需认真 Review。
|
||
|
||
### 方案 B:只更新规范文档
|
||
|
||
实施成本最低,但无法防止缺少开发总结、空安全评估和页面直连 HTTP。随着功能增加,违反约定往往只能在人工 Review 后期发现,不符合项目要求的可追溯和可执行治理目标。
|
||
|
||
### 方案 C:固定目录生成器与全面架构 lint
|
||
|
||
自动化最强,但会要求每个模块凑齐 Controller、Service、DTO、Repository 和 Adapter,容易制造无意义转发、文件碎片和错误抽象。当前业务模块尚未充分展开,固定全部结构为时过早。
|
||
|
||
## 3. 治理证据链
|
||
|
||
```text
|
||
Schema 发布基线
|
||
↓
|
||
governance:start + GitNexus 开发前分析
|
||
↓
|
||
PRD / requirements / design / test-plan
|
||
↓
|
||
测试先行 → 实现 → 完整验证
|
||
↓
|
||
GitNexus detect_changes + 前后对比
|
||
↓
|
||
development-summary
|
||
↓
|
||
代码 Review + 规范 Review
|
||
↓
|
||
governance:finish
|
||
```
|
||
|
||
开发前影响计划必须显式列出 HTTP/OpenAPI、Web API、消息、数据库、缓存、三个服务进程、部署、测试和文档的同步修改结论。开发后变更检测将实际符号和执行流与计划对照,避免只分析主要模块而漏掉消费者。
|
||
|
||
安全和性能采用贯穿式记录,不额外拆成孤立文件:
|
||
|
||
- `design.md` 记录威胁、缓解、残余风险、性能目标和取舍。
|
||
- `test-plan.md` 记录验证方法和风险相称的测试强度。
|
||
- `review/*.md` 记录实现证据、问题、处置和遗留风险。
|
||
- `development-summary.md` 记录实际需求完成、缺陷和验证结果。
|
||
|
||
## 4. 独立开发总结
|
||
|
||
新增 `docs/templates/development-summary-template.md`,并把 `development-summary.md` 加入所有后续功能档案的完成清单。固定章节为:
|
||
|
||
1. 原始开发需求。
|
||
2. 需求与范围变化。
|
||
3. 实际完成需求。
|
||
4. 修复缺陷。
|
||
5. 未完成与延期项。
|
||
6. 关键提交。
|
||
7. 验证证据。
|
||
|
||
自动校验验证标题存在且正文有实质说明。对于没有缺陷或延期项的功能,仍需说明“没有”的依据,不允许删除章节或只填写无解释的占位词。历史已发布档案不因新规则被批量改写;门禁以 GOV-010 生效范围和新建档案为边界,GOV-010 自身也提供该文件。
|
||
|
||
## 5. 后端架构
|
||
|
||
```text
|
||
server/apps/api/src/modules/
|
||
└── market-overview/
|
||
├── market-overview.module.ts
|
||
├── controllers/
|
||
├── services/
|
||
├── dto/
|
||
├── domain/
|
||
├── repositories/
|
||
├── adapters/
|
||
├── types/
|
||
└── utils/
|
||
```
|
||
|
||
业务模块是第一组织边界,目录只在有对应职责时创建。依赖方向为:
|
||
|
||
```text
|
||
Controller → Service / use case → Domain + Repository port
|
||
↑
|
||
Infrastructure Adapter
|
||
```
|
||
|
||
- Controller 处理协议、校验后的输入和响应映射,不包含市场计算或数据访问。
|
||
- Service 编排用例、事务边界和降级,不成为所有逻辑的集中地。
|
||
- Domain 保持纯 TypeScript 规则、口径和模型,不依赖 NestJS 或基础设施 SDK。
|
||
- Repository 是业务所需的持久化端口;Adapter 实现 MySQL、Redis、RocketMQ、免费数据源或 AI Provider。
|
||
- DTO、领域模型和数据库实体分别服务传输、业务和持久化,不互相冒充。
|
||
- 模块间共享只有在重复已经出现、语义稳定且所有者明确后才上移到 `server/libs`。
|
||
|
||
现有健康检查是脚手架基础能力,本功能不为展示目录形式而迁移其后端文件。新的业务模块从本规范开始执行;后续触及健康检查模块时再基于影响分析判断是否垂直归档。
|
||
|
||
## 6. 前端架构与 Axios 数据流
|
||
|
||
```text
|
||
web/src/
|
||
├── utils/
|
||
│ └── request.ts
|
||
├── api/
|
||
│ ├── generated/
|
||
│ │ └── schema.ts
|
||
│ ├── health/
|
||
│ │ └── index.ts
|
||
│ ├── market-overview/
|
||
│ │ └── index.ts
|
||
│ ├── sectors/
|
||
│ │ └── index.ts
|
||
│ └── stocks/
|
||
│ └── index.ts
|
||
└── features/
|
||
└── <business-domain>/
|
||
├── adapters/
|
||
├── components/
|
||
├── composables/
|
||
├── stores/
|
||
└── views/
|
||
```
|
||
|
||
实际数据流为:
|
||
|
||
```text
|
||
NestJS DTO 与 Swagger 元数据
|
||
↓
|
||
server/openapi/openapi.json
|
||
↓ openapi-typescript
|
||
web/src/api/generated/schema.ts
|
||
↓ 类型约束
|
||
api/<业务域>/index.ts
|
||
↓ 调用
|
||
utils/request.ts(Axios)
|
||
↓
|
||
业务 adapter → ViewModel → 页面/组件
|
||
```
|
||
|
||
`request.ts` 创建唯一 Axios 实例,负责 base URL 规范化、超时、通用请求头、取消信号、错误归一化和后续认证扩展。响应拦截器只返回响应数据,API 函数不向功能层泄漏 `AxiosResponse`。错误类型保留稳定的用户安全消息,并可携带不敏感的错误分类和 HTTP 状态供界面决定重试或降级;原始配置、请求头、内网地址和上游正文不进入展示消息。
|
||
|
||
业务 API 文件从生成 Schema 中提取请求与响应类型,并使用封装后的 request。Vue 页面、组件、Store 和 Composable 不得直接导入 Axios、调用浏览器 `fetch` 或拼接业务 URL。DTO 到 ViewModel 的转换保留在功能适配层,使后端传输字段不会扩散到展示组件。
|
||
|
||
## 7. Axios 迁移与依赖评估
|
||
|
||
迁移现有健康请求客户端脚手架,并建立业务 API 样例。当前页面尚未消费健康接口,现有 `client.ts` 只有直接单元测试,Playwright 则从测试进程直接请求后端;因此本次不虚构页面调用方:
|
||
|
||
- 删除 `openapi-fetch` 依赖,新增锁定版本的 `axios`。
|
||
- 以测试先行创建 `web/src/utils/request.ts`,覆盖根地址、超时、数据解包、取消和脱敏错误。
|
||
- 创建 `web/src/api/health/index.ts`,使用生成的 `HealthResponseDto` 类型调用 `/api/v1/health`。
|
||
- 更新旧客户端测试,并为健康业务 API 增加测试;保留 DTO 到 `HealthViewModel` 的适配器,暂不为了展示调用链而把健康状态接入页面。
|
||
- 删除不再使用的 `web/src/api/client.ts` 及对应旧测试。
|
||
- 扩展项目边界校验,拒绝 API 目录外直接使用 Axios/fetch,并拒绝 API 模块绕过统一 request。
|
||
|
||
OpenAPI 文档与 OpenAI 兼容 API 是不同概念:前者是 NestJS 对本项目 HTTP 契约的机器可读描述;后者是未来后端 AI Provider 需要兼容的外部调用协议。本功能只改变浏览器到本项目 API 的 Axios 实现。
|
||
|
||
### Axios 依赖评估
|
||
|
||
- 用途:Axios 1.19.0 作为浏览器到本项目 API 的唯一 HTTP 请求实现,由 `web/src/utils/request.ts` 封装。
|
||
- 来源与维护:npm 包元数据指向官方仓库 `https://github.com/axios/axios.git`,许可证为 MIT;版本写入 `web/package.json` 并由 `pnpm-lock.yaml` 锁定。
|
||
- 替代方案:原生 `fetch` 依赖最少,但拦截器、超时和错误策略需自行维护;旧 `openapi-fetch` 能直接消费 OpenAPI paths 类型,但不符合本项目已确认的 Axios 请求范式。
|
||
- 选择理由:统一拦截器、取消信号和错误归一化能力成熟,能让业务 API 只返回类型化 DTO,同时继续由 `openapi-typescript` 提供契约类型。
|
||
- 成本与风险:增加前端构建体积和一项供应链依赖;以生产构建字节数和 `pnpm audit --prod` 记录实际证据,不以主观估计代替。
|
||
- 退出方式:保留稳定的 `RequestClient` 接口;若后续需要移除 Axios,可在 `utils/request.ts` 内切换到原生 `fetch`,业务域 API 无需改为直接 HTTP 调用。
|
||
|
||
## 8. 安全策略与评估
|
||
|
||
### 资产与信任边界
|
||
|
||
- 浏览器输入和网络响应均不可信;Axios 封装是浏览器 HTTP 错误边界,业务 API 是传输契约边界。
|
||
- OpenAPI 生成文件是可提交的公开契约,不得包含内部消息、实体或密钥。
|
||
- 治理工具读取仓库文档和 Git 状态,不读取生产环境;Schema 门禁仍只允许既定开发库边界。
|
||
|
||
### 主要风险与控制
|
||
|
||
- 错误泄漏:统一转换网络和 HTTP 错误,用户消息不包含 URL、凭据、响应正文或底层异常。
|
||
- 绕过请求策略:边界校验限制 Axios 实例和直接 fetch,减少遗漏超时、认证、错误处理和日志脱敏。
|
||
- 供应链:Axios 使用固定版本并提交锁文件;安装前核对官方包、许可证、维护状态和依赖变化。
|
||
- 注入与浏览器攻击:本功能不渲染远程 HTML、不添加认证 Cookie、不生成动态 SQL;后续涉及这些边界时仍必须分别评估 XSS、CSRF、SSRF 和注入。
|
||
- 伪造治理证据:完成门禁检查必备章节及理由,Review 仍核对内容与 Git diff、测试输出是否一致。
|
||
|
||
残余风险是自动校验无法判断文字结论是否真实,因此保留结构化人工 Review;Axios 响应数据的运行时 Schema 校验不在本次引入,现有健康适配器继续拒绝未知枚举,后续高风险接口按具体功能决定是否引入运行时校验。
|
||
|
||
## 9. 性能目标与评估
|
||
|
||
- Axios 替代 `openapi-fetch` 会增加有限前端依赖体积,但换取项目已确认的统一请求范式、成熟拦截器和取消能力;构建产物记录迁移前后体积并在 Review 中评估变化。
|
||
- 统一请求层不得默认无限重试,避免行情刷新时形成放大流量;本次不加入自动重试。
|
||
- 超时采用有限默认值,业务域可在设计批准后缩短,但不得无上限等待。
|
||
- API 函数返回解包后的 DTO,避免重复转换与组件订阅 Axios 对象;该差异不是性能热点,主要价值是边界稳定。
|
||
- 治理扫描只在开发与发布验证执行,不进入线上请求路径;文件扫描保持线性遍历,当前仓库规模不要求负载测试。
|
||
- 本功能不查询 MySQL、Redis 或行情数据,不改变 Scheduler/Worker 吞吐;这些项不适用于运行时性能验证,边界是后续业务功能必须重新评估。
|
||
|
||
## 10. 自动校验边界
|
||
|
||
适合自动化的规则:必备文件、必填章节、Review 固定结论、前端非法依赖、直接 HTTP 调用和生成契约泄漏。后端目录是否需要某一层、重复是否足以抽取、注释是否真正解释原因等需要语义判断,进入规范 Review,不用脆弱的固定目录规则代替。
|
||
|
||
内容校验以结构为主:确认标题、标题下非空正文、明确的不适用理由格式;不通过搜索“安全”“性能”等零散词语来推定证据完整。校验函数保持纯函数并由 fixture 测试覆盖,`finish.mjs` 只负责编排。
|
||
|
||
## 11. 错误与回退
|
||
|
||
- 门禁失败必须列出具体文件和缺失章节,不能只返回布尔值。
|
||
- Axios 遇到取消请求时保留可识别取消语义,不错误展示为服务故障。
|
||
- 非取消错误转换为项目错误类型;调试细节只允许进入受控开发日志且必须脱敏,本次默认不记录原始错误。
|
||
- 若迁移回归,可用中文回退提交恢复 `openapi-fetch` 客户端、依赖和调用方;规范、模板和校验必须作为一致变更回退,避免规范与基础代码不一致。
|
||
|
||
## 12. 验证与完成标准
|
||
|
||
- 治理单元测试覆盖开发总结和章节校验的通过、缺失和伪占位失败场景。
|
||
- 边界测试覆盖 Axios/fetch 的非法与合法路径、Vue 脚本和路径别名。
|
||
- Web 单元测试覆盖请求 URL、响应解包、网络错误、HTTP 错误和取消。
|
||
- OpenAPI 生成、格式、lint、类型检查、全量测试、构建、Playwright 和源码发布门禁通过。
|
||
- 现有页面在桌面与移动视口完成视觉回归,证明请求基础设施迁移没有造成布局或交互旁路变化。
|
||
- GitNexus 开发后变更检测与前置计划一致,两类 Review 最终结论均为 `passed`。
|