Compare commits

..
66 Commits
Author SHA1 Message Date
FoXiMao 58026aead3 docs(GOV-012): 完成功能质量与发布追溯档案 2026-08-18 03:04:59 +08:00
FoXiMao f1c412b6a3 docs(GOV-012): 更新纯 Node Schema 基线规范 2026-08-18 03:00:47 +08:00
FoXiMao afd186c8a4 fix(GOV-012): 兼容 MySQL 5.7 视图目录并封存 v0.0.9 基线 2026-08-18 02:57:40 +08:00
FoXiMao 874796ab65 fix(GOV-012): 修复 Schema 定义安全与错误语义 2026-08-18 02:46:50 +08:00
FoXiMao 3d12c83621 fix(GOV-012): 修复目录元数据校验与查询错误脱敏 2026-08-18 02:34:14 +08:00
FoXiMao c11de09fa7 feat(GOV-012): 升级 Schema 基线 format v3 2026-08-18 02:24:54 +08:00
FoXiMao dc8ad7d4b6 feat(GOV-012): 实现完整 SHOW CREATE 结构导出 2026-08-18 02:02:41 +08:00
FoXiMao 7e9d9065bb feat(GOV-012): 实现 Schema 对象目录与视图排序 2026-08-18 01:54:50 +08:00
FoXiMao 54fd92837a docs(GOV-012): 更新安全契约 GitNexus 基线 2026-08-18 01:49:16 +08:00
FoXiMao 8e954a3f5f fix(GOV-012): 拒绝 MariaDB 伪装版本 2026-08-18 01:44:25 +08:00
FoXiMao 06466f388e feat(GOV-012): 建立纯 Node 导出器安全契约 2026-08-18 01:21:29 +08:00
FoXiMao 235163cb61 chore(GOV-012): 忽略 SDD 过程账本 2026-08-18 01:11:41 +08:00
FoXiMao cb2e22c13d chore(GOV-012): 忽略本地功能工作区 2026-08-18 01:10:46 +08:00
FoXiMao 97535b8b3f docs(GOV-012): 更新实施计划 GitNexus 基线 2026-08-18 01:08:00 +08:00
FoXiMao 190fba7a0b docs(GOV-012): 完成纯 Node Schema 导出器实施计划 2026-08-18 01:07:14 +08:00
FoXiMao 0f81677b35 docs(GOV-012): 更新设计阶段 GitNexus 基线 2026-08-18 00:47:16 +08:00
FoXiMao c605935403 docs(GOV-012): 确认纯 Node Schema 导出器设计 2026-08-18 00:46:03 +08:00
FoXiMao 3555b7c222 docs(FEAT-MO-001): 更新 TDX 接入后的 GitNexus 基线 2026-08-18 00:34:08 +08:00
FoXiMao 998c9276d5 docs(FEAT-MO-001): 记录 TDX 双场景开发接入 2026-08-18 00:32:04 +08:00
FoXiMao c0a6f55605 docs(GOV-011): 更新最终 GitNexus 基线 2026-08-17 18:00:49 +08:00
FoXiMao 405b9858f0 docs(GOV-011): 回填 v0.0.9 发布追溯 2026-08-17 18:00:11 +08:00
FoXiMao 88e2fdffc8 chore(GOV-011): 发布 v0.0.9 系列版本约束 2026-08-17 17:58:02 +08:00
FoXiMao 7478a96bdc docs(GOV-011): 完成系列版本验证与审查 2026-08-17 17:50:58 +08:00
FoXiMao cce77aa884 docs(GOV-011): 统一运行时系列版本口径 2026-08-17 17:36:44 +08:00
FoXiMao dc8da80809 fix(GOV-011): 支持 MySQL 5.7 系列健康检查 2026-08-17 17:31:10 +08:00
FoXiMao 54499f0678 fix(GOV-011): 放宽 MySQL 服务端为完整 5.7 系列 2026-08-17 17:28:48 +08:00
FoXiMao c8277ef25a test(GOV-011): 补充 Node 22 系列边界验证 2026-08-17 17:23:29 +08:00
FoXiMao 426870b704 docs(GOV-011): 制定运行时系列版本实施计划 2026-08-17 17:19:38 +08:00
FoXiMao fcfef2d524 docs(GOV-011): 确认系列版本约束设计 2026-08-17 17:01:39 +08:00
FoXiMao 9e85809096 docs(GOV-009): 封存 GOV-009 与 GOV-010 架构基线 2026-08-17 16:27:37 +08:00
FoXiMao 4971077d3b docs(FEAT-DS-001): 更新操作手册后的 GitNexus 基线 2026-08-17 12:25:56 +08:00
FoXiMao 81e5d331ca docs(FEAT-DS-001): 新增 Tailscale TDX 开发操作手册 2026-08-17 12:25:13 +08:00
FoXiMao 4f5588ffcb docs(FEAT-DS-001): 更新规划后的 GitNexus 基线 2026-08-14 03:06:07 +08:00
FoXiMao 551fe5e5e7 docs(FEAT-DS-001): 记录采集器后置与本地数据源方案 2026-08-14 03:05:23 +08:00
FoXiMao a398bc418d docs(GOV-010): 更新最终 GitNexus 基线 2026-08-14 00:01:15 +08:00
FoXiMao 38b731a334 docs(GOV-010): 完善最终验证追踪 2026-08-13 23:58:11 +08:00
FoXiMao f178fb4044 feat(GOV-010): 完成开发质量与架构治理 2026-08-13 23:56:21 +08:00
FoXiMao 61f85e5fa4 docs(GOV-010): 记录开发需求与完成结果 2026-08-13 23:35:50 +08:00
FoXiMao e992edccce fix(GOV-010): 修复 Swagger 传递依赖漏洞 2026-08-13 23:32:46 +08:00
FoXiMao d2c18634ed feat(GOV-010): 建立前端 API 分域边界 2026-08-13 23:14:22 +08:00
FoXiMao 4105336cb2 refactor(GOV-010): 统一封装前端 Axios 请求 2026-08-13 23:02:36 +08:00
FoXiMao 3a22fdeef3 docs(GOV-010): 完善安全性能与架构规范 2026-08-13 22:54:32 +08:00
FoXiMao e12c57222b feat(GOV-010): 强制校验开发质量证据 2026-08-13 22:47:51 +08:00
FoXiMao a8dcd0601b docs(GOV-010): 制定开发质量治理实施计划 2026-08-13 22:37:35 +08:00
FoXiMao 1c1b15e709 docs(GOV-010): 确认开发质量与架构规范设计 2026-08-13 22:20:54 +08:00
FoXiMao bbda26fa41 docs(GOV-009): 更新最终 GitNexus 索引统计 2026-08-13 21:35:45 +08:00
FoXiMao c75665446b fix(GOV-009): 完成仅源码部署最终复审 2026-08-13 21:33:38 +08:00
FoXiMao 47d0e0d248 refactor(GOV-009): 彻底切换为仅源码部署 2026-08-13 21:12:12 +08:00
FoXiMao ab48f06150 docs(GOV-009): 制定仅源码部署实施计划 2026-08-13 20:55:31 +08:00
FoXiMao cfcd7f13d9 docs(GOV-009): 确认仅源码部署设计 2026-08-13 20:46:58 +08:00
FoXiMao f50268b70f docs(GOV-009): 封存脚手架复核材料 2026-08-13 19:55:45 +08:00
FoXiMao 95b8611bd9 fix(GOV-009): 封堵外部脚本边界绕过 2026-08-13 19:49:42 +08:00
FoXiMao cb550e3d5c fix(GOV-009): 完成最终复审整改 2026-08-13 18:51:14 +08:00
FoXiMao 3a8120a33a fix(GOV-009): 完成脚手架审查整改 2026-08-13 18:30:57 +08:00
FoXiMao dcdf634457 fix(GOV-009): 消除前端运行时模板警告 2026-08-13 18:03:35 +08:00
FoXiMao c771a98d4d build(GOV-009): 对齐应用部署与运行入口 2026-08-13 17:56:37 +08:00
FoXiMao 4665336a63 feat(GOV-009): 建立前端 OpenAPI 客户端边界 2026-08-13 17:36:55 +08:00
FoXiMao 420aa22342 feat(GOV-009): 建立后端契约与健康检查 2026-08-13 17:26:51 +08:00
FoXiMao 3fc703de0b feat(GOV-009): 建立 NestJS 三进程基线 2026-08-13 16:59:09 +08:00
FoXiMao 28d54186ad feat(GOV-009): 建立 Vue 前端工程基线 2026-08-13 16:42:25 +08:00
FoXiMao 258a2d21f6 build(GOV-009): 建立 Node 与工作区基线 2026-08-13 15:54:07 +08:00
FoXiMao b3d8e29f52 feat(GOV-009): 支持固定开发库结构基线 2026-08-13 15:43:06 +08:00
FoXiMao c5a6e6a2c0 docs(GOV-009): 更新 GitNexus 图谱统计 2026-08-13 15:26:58 +08:00
FoXiMao 2e4cffeff1 docs(GOV-009): 细化应用脚手架实施计划 2026-08-13 15:25:38 +08:00
FoXiMao c04184a611 docs(GOV-009): 明确应用脚手架设计边界 2026-08-13 15:07:36 +08:00
FoXiMao 19cc5f948d docs(GOV-009): 封存 v0.0.7 开发库基线 2026-08-13 14:56:14 +08:00
218 changed files with 21083 additions and 364 deletions
+4
View File
@@ -3,6 +3,8 @@ node_modules/
dist/ dist/
coverage/ coverage/
*.tsbuildinfo *.tsbuildinfo
playwright-report/
test-results/
# 本地环境与密钥 # 本地环境与密钥
.env .env
@@ -28,3 +30,5 @@ CLAUDE.md
*.log *.log
tmp/ tmp/
work/ work/
.worktrees/
.superpowers/
+4
View File
@@ -0,0 +1,4 @@
engine-strict=true
save-exact=true
strict-peer-dependencies=true
only-built-dependencies[]=esbuild
+11
View File
@@ -0,0 +1,11 @@
# 自动生成或不可变发布产物
AGENTS.md
pnpm-lock.yaml
database/schema-baselines/
# 历史功能档案与人类维护文档不由代码格式器改写,追溯内容保持原样。
docs/
# 已有治理脚本保留原历史格式;其行为由专项测试门禁覆盖。
tools/database/
tools/governance/
+6
View File
@@ -0,0 +1,6 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"semi": true
}
+7 -2
View File
@@ -19,12 +19,17 @@
8. 禁止提交密钥、密码、访问令牌、生产数据、`.env` 和 GitNexus 本地索引;凭据不得写入远程 URL、文档、脚本或命令参数。 8. 禁止提交密钥、密码、访问令牌、生产数据、`.env` 和 GitNexus 本地索引;凭据不得写入远程 URL、文档、脚本或命令参数。
9. 开发完成后必须先通过代码 Review 和开发规范符合性 Review,再进入发布;Review 结论和问题处置必须写入功能档案。 9. 开发完成后必须先通过代码 Review 和开发规范符合性 Review,再进入发布;Review 结论和问题处置必须写入功能档案。
10. 每次提交验证通过后必须立即推送当前分支到项目 Gitea;本次新建标签必须单独推送。推送失败时任务不得标记完成,禁止强推或自动覆盖未知远程提交。 10. 每次提交验证通过后必须立即推送当前分支到项目 Gitea;本次新建标签必须单独推送。推送失败时任务不得标记完成,禁止强推或自动覆盖未知远程提交。
11. Schema 基线只能读取 `APP_ENV=development` 的 `a_share_analysis_dev`,启用时主机必须是开发机回环地址;禁止连接、探测或读取生产数据库。MySQL 未启用时只允许生成可验证的 `not_applicable` 清单,禁止用空 SQL 冒充基线。`governance:start` 还必须确认基线已提交、已推送且远程标签一致。 11. Schema 基线只能读取 `APP_ENV=development` 的 `a_share_analysis_dev`,启用时主机必须命中代码内固定开发白名单(开发机回环地址或 `112.192.20.11`);禁止连接、探测或读取生产数据库。MySQL 未启用时只允许生成可验证的 `not_applicable` 清单,启用但无对象时生成 `captured_empty` 清单,禁止用空 SQL 冒充基线。`governance:start` 还必须确认基线已提交、已推送且远程标签一致。
12. 功能和缺陷修复开发前必须用 GitNexus 评估直接、间接及跨模块影响,并逐项判断 HTTP/OpenAPI、Web API、消息、数据库、Redis、API、Scheduler、Worker、部署、测试和文档是否同步修改;`partial` 结果不得视为无影响。
13. 设计、测试计划和 Review 必须包含安全策略、性能目标、验证证据及残余风险;不适用项必须写明原因与边界。
14. 每个未发布功能必须有独立 `development-summary.md`,明确原始需求、范围变化、实际完成、修复缺陷、延期项、关键提交和验证证据,不得合并到发布说明。
15. 后端以业务模块为一级目录并在模块内按需分层,小模块不凑目录;前端统一由 `web/src/utils/request.ts` 封装 Axios,业务请求只能位于 `web/src/api/<业务域>/index.ts`,OpenAPI 类型继续作为契约来源。
16. 复用代码只有在真实重复和稳定职责出现后才能抽取;新增依赖必须先评估用途、替代、安全、许可证、体积或运行成本、维护和退出方案。
<!-- gitnexus:start --> <!-- gitnexus:start -->
# GitNexus — Code Intelligence # GitNexus — Code Intelligence
This project is indexed by GitNexus as **a-share-analysis** (958 symbols, 1141 relationships, 23 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. This project is indexed by GitNexus as **a-share-analysis** (2429 symbols, 3280 relationships, 63 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
+20
View File
@@ -2,6 +2,26 @@
本项目采用语义化版本。功能级变化请从 `docs/features/` 按功能编号追溯。 本项目采用语义化版本。功能级变化请从 `docs/features/` 按功能编号追溯。
## Unreleased
## 0.0.9 - 2026-08-17
- Node.js 运行时约束明确为完整 22.x,不绑定 minor 或 patch。
- MySQL 客户端、mysqldump、服务端和健康检查统一接受完整 5.7.x,不设置最低补丁版本。
- MySQL 健康详情改为展示服务端实际三段版本,字符集、排序规则、库名和东八区时区继续严格校验。
- 系统架构、开发规范、本地开发和 Ubuntu 源码部署手册统一采用系列版本口径,历史版本证据保持原样。
- 用户确认开发库为空并授权 GOV-011 一次性跳过 v0.0.8 Schema 基线;仓库未伪造基线或增加通用绕过开关。
## 0.0.8 - 2026-08-17
- 新增安全、性能、GitNexus 跨模块影响和独立开发总结的可执行治理门禁。
- 约定后端业务模块内按需分层,以及前端 Axios 统一封装、API 分域和 OpenAPI 类型契约。
- 项目生产交付统一为 Ubuntu 源码部署,移除 Dockerfile、Compose、镜像校验和容器测试入口。
- 本地 Redis、MySQL 5.7.42 与 RocketMQ 5.x 均作为外部服务,项目不再提供自动启动或容器兜底。
- 新增源码发布门禁,校验 Web/Server 构建产物与 systemd、Nginx 配置一致性。
- 完成 Vue 3 Web、NestJS API/Scheduler/Worker、OpenAPI 单向契约和最小权限配置的工程基线确认。
- 补充 Tailscale 访问 Windows TDX 的开发操作文档和采集 PoC 前置档案;本版本不实现常驻采集程序。
## 0.0.7 - 2026-08-13 ## 0.0.7 - 2026-08-13
- 将项目唯一消息队列技术基线由 RabbitMQ 调整为 RocketMQ 5.x。 - 将项目唯一消息队列技术基线由 RabbitMQ 调整为 RocketMQ 5.x。
+6 -7
View File
@@ -9,19 +9,18 @@ A read-only A-share market overview and analysis tool.
## Projects ## Projects
- `web/`: Vue 3 market terminal frontend. - `web/`: Vue 3 market terminal frontend.
- `server/`: NestJS API, scheduler, and workers. Added in a later module. - `server/`: NestJS API、Scheduler 与 Worker 三个独立进程。
- `deploy/`: MySQL 5.7, Redis, and RocketMQ 5.x deployment configuration. Added with the backend module. - `deploy/`: MySQL 5.7、Redis、RocketMQ 5.x 的配置契约,以及 systemd/Nginx 源码部署模板。
- `docs/`: Product and implementation specifications. - `docs/`: Product and implementation specifications.
The first implementation slice is the market overview screen in `web/`. The first implementation slice is the market overview screen in `web/`.
## 环境与部署 ## 环境与部署
- [本地开发环境](docs/deployment/local-development.md):Compose 只启动 Redis,应用从源码运行。 - [本地开发环境](docs/deployment/local-development.md):使用开发机已有 Redis,应用全部从源码运行。
- [Docker Compose 生产部署](docs/deployment/docker-compose-production.md):当前为应用脚手架落地前的配置契约骨架。 - [Ubuntu 源码生产部署](docs/deployment/ubuntu-source-production.md):项目唯一生产部署方式,支持 Ubuntu 22.04/24.04 LTS x86_64。
- [Ubuntu 源码生产部署](docs/deployment/ubuntu-source-production.md):支持 Ubuntu 22.04/24.04 LTS x86_64。
无秘密环境模板位于 `deploy/env/`。生产配置不进入 Git 或发布目录;Node.js 22 LTS、pnpm 10、Nginx 和基础设施由服务器管理员提供。 无秘密环境模板位于 `deploy/env/`。生产配置不进入 Git 或发布目录;Node.js 22.x、pnpm 10.25.0、Nginx 和外部基础设施由服务器管理员提供。项目不安装、启动、停止或删除 Redis、MySQL 和 RocketMQ。
## 开发入口 ## 开发入口
@@ -38,7 +37,7 @@ npm run schema:verify
npm run governance:start -- FEAT-MO-001 market-overview npm run governance:start -- FEAT-MO-001 market-overview
``` ```
Schema 命令只允许处理固定开发库;当前 MySQL 未启用时会为上一发布版本生成可验证的不适用清单,不会连接数据库或创建空 SQL。完整规则见 [开发流程规范](docs/governance/development-workflow.md)。 Schema 命令只允许处理固定开发库;导出器使用 Node.js `mysql2`,本机无需安装 MySQL Server 或 CLI。当前 MySQL 未启用时会为上一发布版本生成可验证的不适用清单,不会连接数据库或创建空 SQL;启用但无对象时生成 format v3 `captured_empty` 清单。完整规则见 [开发流程规范](docs/governance/development-workflow.md)。
## 项目仓库 ## 项目仓库
+1 -1
View File
@@ -1 +1 @@
0.0.7 0.0.9
@@ -0,0 +1,24 @@
{
"format_version": 1,
"status": "not_applicable",
"application_version": "v0.0.7",
"git_commit": "7dc04a267199fb3a11c2ac43c2914ae5e1460cb9",
"source_environment": "development",
"database_name": "a_share_analysis_dev",
"mysql_client_version": "not_enabled",
"mysqldump_client_version": "not_enabled",
"mysql_server_version": "not_enabled",
"charset": "utf8mb4",
"collation": "utf8mb4_general_ci",
"generated_at": "2026-08-13T06:55:43.710Z",
"generator": "schema-baseline/1.0.0",
"reason": "mysql_disabled",
"schema_sha256": "not_applicable",
"objects": {
"tables": false,
"views": false,
"triggers": false,
"routines": false,
"events": false
}
}
@@ -0,0 +1,33 @@
{
"format_version": 3,
"status": "captured_empty",
"application_version": "v0.0.9",
"git_commit": "88e2fdffc8c71dd682405c148a81953a8dcee9d6",
"source_environment": "development",
"database_name": "a_share_analysis_dev",
"charset": "utf8mb4",
"collation": "utf8mb4_general_ci",
"generated_at": "2026-08-17T18:56:33.473Z",
"generator": "schema-baseline/3.0.0",
"reason": "none",
"schema_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"objects": {
"tables": false,
"views": false,
"triggers": false,
"routines": false,
"events": false
},
"object_counts": {
"tables": 0,
"views": 0,
"triggers": 0,
"routines": 0,
"events": 0
},
"exporter_name": "mysql2-show-create",
"exporter_version": "1.0.0",
"database_driver": "mysql2",
"database_driver_version": "3.23.3",
"mysql_server_version": "5.7.42-0ubuntu0.18.04.1"
}
-23
View File
@@ -1,23 +0,0 @@
name: a-share-analysis-development
services:
redis:
image: redis:7.2.5-alpine
container_name: a-share-analysis-dev-redis
command: ["redis-server", "--appendonly", "yes"]
ports:
- "127.0.0.1:6379:6379"
volumes:
- ../../.local/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
networks:
- a-share-analysis-dev
networks:
a-share-analysis-dev:
name: a-share-analysis-dev
-30
View File
@@ -1,30 +0,0 @@
# 应用镜像和启动入口将在 Web/Server 脚手架落地后验证。本文件先固定生产配置边界。
name: a-share-analysis-production
services:
web:
image: ${A_SHARE_WEB_IMAGE:?必须提供不可变 Web 镜像引用}
env_file: ${A_SHARE_WEB_ENV_FILE:-/etc/a-share-analysis/web.env}
ports:
- "127.0.0.1:8080:80"
restart: unless-stopped
api:
image: ${A_SHARE_SERVER_IMAGE:?必须提供不可变 Server 镜像引用}
command: ["node", "dist/apps/api/main.js"]
env_file: ${A_SHARE_API_ENV_FILE:-/etc/a-share-analysis/api.env}
ports:
- "127.0.0.1:3000:3000"
restart: unless-stopped
scheduler:
image: ${A_SHARE_SERVER_IMAGE:?必须提供不可变 Server 镜像引用}
command: ["node", "dist/apps/scheduler/main.js"]
env_file: ${A_SHARE_SCHEDULER_ENV_FILE:-/etc/a-share-analysis/scheduler.env}
restart: unless-stopped
worker:
image: ${A_SHARE_SERVER_IMAGE:?必须提供不可变 Server 镜像引用}
command: ["node", "dist/apps/worker/main.js"]
env_file: ${A_SHARE_WORKER_ENV_FILE:-/etc/a-share-analysis/worker.env}
restart: unless-stopped
+1
View File
@@ -22,6 +22,7 @@ MYSQL_USERNAME=
MYSQL_PASSWORD= MYSQL_PASSWORD=
MYSQL_CHARSET=utf8mb4 MYSQL_CHARSET=utf8mb4
MYSQL_COLLATION=utf8mb4_general_ci MYSQL_COLLATION=utf8mb4_general_ci
MYSQL_TIMEZONE=+08:00
# 第一阶段关闭付费 AI;启用后 BASE_URL、API_KEY 和 MODEL 变为必填。 # 第一阶段关闭付费 AI;启用后 BASE_URL、API_KEY 和 MODEL 变为必填。
AI_ENABLED=false AI_ENABLED=false
+1 -1
View File
@@ -1,5 +1,5 @@
# VITE 变量会进入浏览器,只允许公开配置。 # VITE 变量会进入浏览器,只允许公开配置。
VITE_APP_ENV=development VITE_APP_ENV=development
VITE_APP_TITLE=A-Share Analysis VITE_APP_TITLE=A-Share Analysis
VITE_API_BASE_URL=http://127.0.0.1:3000/api VITE_API_BASE_URL=
VITE_ENABLE_DEVTOOLS=true VITE_ENABLE_DEVTOOLS=true
+1
View File
@@ -21,6 +21,7 @@ MYSQL_USERNAME=
MYSQL_PASSWORD= MYSQL_PASSWORD=
MYSQL_CHARSET=utf8mb4 MYSQL_CHARSET=utf8mb4
MYSQL_COLLATION=utf8mb4_general_ci MYSQL_COLLATION=utf8mb4_general_ci
MYSQL_TIMEZONE=+08:00
ROCKETMQ_ENABLED=false ROCKETMQ_ENABLED=false
ROCKETMQ_NAMESRV_ADDR=127.0.0.1:9876 ROCKETMQ_NAMESRV_ADDR=127.0.0.1:9876
+1
View File
@@ -20,6 +20,7 @@ MYSQL_USERNAME=
MYSQL_PASSWORD= MYSQL_PASSWORD=
MYSQL_CHARSET=utf8mb4 MYSQL_CHARSET=utf8mb4
MYSQL_COLLATION=utf8mb4_general_ci MYSQL_COLLATION=utf8mb4_general_ci
MYSQL_TIMEZONE=+08:00
AI_ENABLED=false AI_ENABLED=false
AI_BASE_URL= AI_BASE_URL=
+1 -1
View File
@@ -1,5 +1,5 @@
# VITE 变量会进入浏览器,只允许公开配置。 # VITE 变量会进入浏览器,只允许公开配置。
VITE_APP_ENV=production VITE_APP_ENV=production
VITE_APP_TITLE=A-Share Analysis VITE_APP_TITLE=A-Share Analysis
VITE_API_BASE_URL=/api VITE_API_BASE_URL=
VITE_ENABLE_DEVTOOLS=false VITE_ENABLE_DEVTOOLS=false
+1
View File
@@ -21,6 +21,7 @@ MYSQL_USERNAME=
MYSQL_PASSWORD= MYSQL_PASSWORD=
MYSQL_CHARSET=utf8mb4 MYSQL_CHARSET=utf8mb4
MYSQL_COLLATION=utf8mb4_general_ci MYSQL_COLLATION=utf8mb4_general_ci
MYSQL_TIMEZONE=+08:00
ROCKETMQ_ENABLED=false ROCKETMQ_ENABLED=false
ROCKETMQ_NAMESRV_ADDR= ROCKETMQ_NAMESRV_ADDR=
+4 -1
View File
@@ -9,11 +9,14 @@ User=a-share
Group=a-share Group=a-share
WorkingDirectory=/opt/a-share-analysis/current WorkingDirectory=/opt/a-share-analysis/current
EnvironmentFile=/etc/a-share-analysis/api.env EnvironmentFile=/etc/a-share-analysis/api.env
ExecStart=/usr/bin/node server/dist/apps/api/main.js ExecStart=/usr/bin/node /opt/a-share-analysis/current/server/dist/apps/api/main.js
ExecStartPre=/usr/bin/test -r /etc/a-share-analysis/api.env
Restart=on-failure Restart=on-failure
RestartSec=5 RestartSec=5
NoNewPrivileges=true NoNewPrivileges=true
PrivateTmp=true PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@@ -9,11 +9,14 @@ User=a-share
Group=a-share Group=a-share
WorkingDirectory=/opt/a-share-analysis/current WorkingDirectory=/opt/a-share-analysis/current
EnvironmentFile=/etc/a-share-analysis/scheduler.env EnvironmentFile=/etc/a-share-analysis/scheduler.env
ExecStart=/usr/bin/node server/dist/apps/scheduler/main.js ExecStart=/usr/bin/node /opt/a-share-analysis/current/server/dist/apps/scheduler/main.js
ExecStartPre=/usr/bin/test -r /etc/a-share-analysis/scheduler.env
Restart=on-failure Restart=on-failure
RestartSec=5 RestartSec=5
NoNewPrivileges=true NoNewPrivileges=true
PrivateTmp=true PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@@ -9,11 +9,14 @@ User=a-share
Group=a-share Group=a-share
WorkingDirectory=/opt/a-share-analysis/current WorkingDirectory=/opt/a-share-analysis/current
EnvironmentFile=/etc/a-share-analysis/worker.env EnvironmentFile=/etc/a-share-analysis/worker.env
ExecStart=/usr/bin/node server/dist/apps/worker/main.js ExecStart=/usr/bin/node /opt/a-share-analysis/current/server/dist/apps/worker/main.js
ExecStartPre=/usr/bin/test -r /etc/a-share-analysis/worker.env
Restart=on-failure Restart=on-failure
RestartSec=5 RestartSec=5
NoNewPrivileges=true NoNewPrivileges=true
PrivateTmp=true PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
+29 -9
View File
@@ -7,7 +7,9 @@
```text ```text
web/ Vue 3 前端 web/ Vue 3 前端
server/ NestJS API、Scheduler 与 Worker server/ NestJS API、Scheduler 与 Worker
contracts/ HTTP 与 RocketMQ 版本化契约 server/openapi/ HTTP OpenAPI 产物
server/libs/http-contracts/ 后端 HTTP DTO
server/libs/message-contracts/ 后端 RocketMQ 版本化契约
deploy/ MySQL、Redis、RocketMQ 5.x 和运行配置 deploy/ MySQL、Redis、RocketMQ 5.x 和运行配置
docs/ 规范、架构、ADR 与功能档案 docs/ 规范、架构、ADR 与功能档案
tools/ 可重复执行的治理和开发工具 tools/ 可重复执行的治理和开发工具
@@ -38,23 +40,41 @@ tools/ 可重复执行的治理和开发工具
- Redis保存最新快照、缓存、锁和限流状态。 - Redis保存最新快照、缓存、锁和限流状态。
- Vue前端只读后端 API,不直接接触外部数据源和密钥。 - Vue前端只读后端 API,不直接接触外部数据源和密钥。
## 3. 数据库技术基线 ## 3. 前后端模块边界
- 数据库服务端固定使用 MySQL 5.7.x,开发、测试和生产环境禁止使用 MySQL 8.x 代替兼容性验证。 后端以业务模块为一级目录,模块内部按实际职责建立 Controller、Service、DTO、Domain、Repository 和 Adapter。小模块不强制凑齐目录,禁止把全部 Controller/Service 堆入全局目录,也禁止无业务逻辑的透传层。领域规则只依赖项目端口,MySQL、Redis、RocketMQ、免费数据源和 AI Provider 由基础设施 Adapter 实现。
前端 HTTP 数据流固定为:
```text
NestJS DTO 与 Swagger 元数据
→ server/openapi/openapi.json
→ openapi-typescript 生成 web/src/api/generated/schema.ts
→ web/src/api/<业务域>/index.ts
→ web/src/utils/request.ts(Axios)
→ 功能 adapter / ViewModel
→ 页面、组件和 Store
```
OpenAPI 负责描述本项目 HTTP 契约,Axios 负责浏览器实际请求。页面、组件、Store 和 Composable 不直接发 HTTP。兼容 OpenAI API 指未来后端 AI Provider 的外部协议,与前端请求库无关。
## 4. 数据库技术基线
- 数据库服务端统一使用 MySQL 5.7.x;开发、测试和生产环境禁止使用 MySQL 5.6.x、8.x、MariaDB 或其他数据库代替兼容性验证,但不锁定 5.7 系列内的补丁版本。
- 数据库与表默认字符集固定为 `utf8mb4`,排序规则固定为 `utf8mb4_general_ci`。 - 数据库与表默认字符集固定为 `utf8mb4`,排序规则固定为 `utf8mb4_general_ci`。
- 数据库初始化、表结构、连接会话、ORM 配置和迁移脚本必须显式声明或验证该字符集与排序规则,不能依赖服务器默认值。 - 数据库初始化、表结构、连接会话、ORM 配置和迁移脚本必须显式声明或验证该字符集与排序规则,不能依赖服务器默认值。
- 正式启用持久化前,必须在真实 MySQL 5.7 环境验证服务端版本、Schema/表排序规则、迁移和关键查询。 - 正式启用持久化前,必须在真实 MySQL 5.7.x 环境验证服务端版本、Schema/表排序规则、迁移和关键查询。
- 第一阶段市场概览只定义 MySQL Repository 接口并使用内存实现,不启动数据库、不建立生产连接;后续启用时不得改变前端 API 和核心分析契约。 - 第一阶段市场概览只定义 MySQL Repository 接口并使用内存实现,不启动数据库、不建立生产连接;后续启用时不得改变前端 API 和核心分析契约。
## 4. 当前实施顺序 ## 5. 当前实施顺序
第一阶段先实现可交互的市场综合概览和稳定数据契约,再接入正式行情采集链路。用户、邀请、权限、会员和支付后置,不进入当前核心架构。 第一阶段先实现可交互的市场综合概览和稳定数据契约,再接入正式行情采集链路。用户、邀请、权限、会员和支付后置,不进入当前核心架构。
## 5. 环境与部署基线 ## 6. 环境与部署基线
- 应用运行环境只定义 `development` 与 `production`;生产环境禁止模拟数据、热更新、调试端口和开发默认值回退。 - 应用运行环境只定义 `development` 与 `production`;生产环境禁止模拟数据、热更新、调试端口和开发默认值回退。
- API、Scheduler、Worker、Web 分别拥有开发和生产模板;同一进程跨环境使用相同变量名,通过启动 Schema 校验条件必填项。 - API、Scheduler、Worker、Web 分别拥有开发和生产模板;同一进程跨环境使用相同变量名,通过启动 Schema 校验条件必填项。
- 本地开发使用 Docker Compose 只启动 Redis,应用进程从源码运行;第一阶段 MySQL 与 RocketMQ 保持关闭。需要联调时可以连接本机独立运行的 RocketMQ 5.x。 - 本地开发直接连接开发机已开机自启的 Redis `127.0.0.1:6379`,应用进程从源码运行;第一阶段 MySQL 与 RocketMQ 保持关闭,需要联调时连接开发者独立维护的外部服务。
- 生产同时支持 Docker Compose 和 Ubuntu 22.04/24.04 LTS x86_64 源码部署,两者共用配置契约和进程边界。 - 生产只支持 Ubuntu 22.04/24.04 LTS x86_64 源码部署,不提供容器运行、构建、测试或部署入口。
- 源码部署由管理员预装 Node.js 22 LTS、pnpm 10、Nginx 和基础设施;项目只验证,不安装或修改系统软件源。 - 源码部署由管理员预装 Node.js 22.x、pnpm 10.25.0、Nginx 和外部基础设施;项目只验证,不安装、启动、停止或删除系统服务。
- 源码部署使用不可变发布目录、`a-share` 用户和 systemd 独立进程配置;生产 env 存放在 `/etc/a-share-analysis/`,不随代码版本切换覆盖。 - 源码部署使用不可变发布目录、`a-share` 用户和 systemd 独立进程配置;生产 env 存放在 `/etc/a-share-analysis/`,不随代码版本切换覆盖。
@@ -1,19 +0,0 @@
# Docker Compose 生产部署
生产 Docker Compose 使用不可变应用镜像和外部 env 文件。当前 `production.yml.example` 是部署契约骨架,应用镜像、健康检查和实际启动命令必须在 Web/Server 脚手架完成后验证,未验证前不得用于线上部署。
## 配置边界
- 从 `deploy/env/production/` 准备四份真实配置,存放在服务器 `/etc/a-share-analysis/` 或其他受控目录。
- Compose 通过外部路径加载,不在 YAML、镜像和 Git 中保存秘密。
- 镜像引用必须包含版本或内容摘要,禁止浮动 `latest`。
- 第一阶段只依赖 Redis;MySQL 和 RocketMQ 5.x 功能开关保持关闭。
- 启用 RocketMQ 时优先连接受运维管理的外部集群或独立基础设施 Compose,不把 NameServer、Broker、Proxy 混入应用发布生命周期。
## 发布与回退
部署前验证镜像对应已推送提交或标签、环境 Schema、健康检查和数据目录。升级只修改不可变镜像引用;失败时恢复上一完整镜像集合和未改变的外部配置。禁止删除 Redis、MySQL 或 RocketMQ CommitLog 数据目录作为应用回退手段。
## 验证
应用脚手架落地后必须补充 `docker compose config`、服务健康检查、日志读取、优雅停止和回退演练证据。本版本不声称生产 Compose 已可运行。
+30 -15
View File
@@ -1,27 +1,42 @@
# 本地开发环境 # 本地开发环境
本地开发使用 Docker Compose 只启动 Redis,Web、API、Scheduler 和 Worker 从源码运行并使用开发环境模板。第一阶段不自动启动 MySQL 和 RocketMQ 5.x。 本地开发由开发机提供 Node.js 22.x、pnpm 10.25.0 和已开机自启的 Redis `127.0.0.1:6379`。Web、API、Scheduler 与 Worker 全部从源码启动;MySQL 5.7.x 和 RocketMQ 5.x 也是外部服务,项目脚本不负责安装、启动、停止或删除任何基础设施。
## 配置 ## 首次准备
从 `deploy/env/development/` 中对应的 `*.env.example` 创建本机 `*.env.local`。真实文件被 Git 忽略,不得写入生产地址或真实密钥。
## Redis
```bash ```bash
docker compose -f deploy/compose/development.yml up -d node --version
docker compose -f deploy/compose/development.yml ps pnpm --version
docker compose -f deploy/compose/development.yml down redis-cli -h 127.0.0.1 -p 6379 ping
pnpm install --frozen-lockfile
pnpm check:runtime
``` ```
Redis 只绑定 `127.0.0.1:6379`,数据写入仓库忽略的 `.local/redis/`。不得把该 Compose 文件用于生产。 Redis 必须返回 `PONG`。如果不可达,应先修复开发机外部服务;测试和应用不会创建替代实例。
## RocketMQ 联调 把 `deploy/env/development/*.env.example` 复制为同目录的 `*.env.local`。四份 local 文件被 Git 忽略:Web 只能含 `VITE_` 公开变量;API、Scheduler、Worker 按最小权限分别读取自己的配置,不共享一份全能 env。
RocketMQ 由开发者在项目 Compose 外独立启动。应用启用前至少需要 NameServer、Broker;采用推荐的 Node.js Proxy 接入时还需要 Proxy。默认端口约定:NameServer `9876`、Broker `10911`、Proxy gRPC `8081`。 固定开发 MySQL 只允许 `a_share_analysis_dev`,主机必须是回环地址或代码内白名单 `112.192.20.11`,服务端必须属于 MySQL 5.7.x 且不限制系列内补丁版本,字符集为 `utf8mb4`、排序规则为 `utf8mb4_general_ci`、会话时区为 `+08:00`。Schema 工具和开发检查禁止连接、探测或读取生产库。
`nc -vz 127.0.0.1 9876` 只能证明 NameServer TCP 可达,不能证明 Topic 路由、Broker 注册或消息收发可用。完整联调必须继续检查 Broker 列表,并执行一次测试 Topic 的生产与消费。开发模板默认 `ROCKETMQ_ENABLED=false`;启用后必须提供可用的 `ROCKETMQ_ENDPOINT`,不得把生产地址写入本地配置或仓库。 ## 启动顺序
## 应用状态 建议分别打开四个终端,依次运行:
Web 和 Server 尚未完成脚手架,因此本版本只交付配置契约和 Redis 开发环境。后续脚手架必须使用 Node.js 22 LTS、pnpm 10 和这些模板,不能在本文档中假装应用已经可启动。 ```bash
pnpm --filter @a-share-analysis/server dev:api
pnpm --filter @a-share-analysis/server dev:scheduler
pnpm --filter @a-share-analysis/server dev:worker
pnpm --filter @a-share-analysis/web dev
```
API 健康端点是 `http://127.0.0.1:3000/api/v1/health`,Web 是 `http://127.0.0.1:5173/`。Scheduler 与 Worker 在 GOV-009 中保持 `ROCKETMQ_ENABLED=false`;没有经过验证的 Node RocketMQ 客户端时,启用配置会直接失败,不使用内存队列伪降级。
## 日常验证与停止
```bash
pnpm check:contracts
pnpm verify
pnpm verify:release
```
应用进程通过各自终端或信号正常停止,外部 Redis/MySQL/RocketMQ 生命周期不由项目管理。RocketMQ 的 TCP 端口可达不等于生产消费链路通过,完整联调仍需验证 Topic 路由和实际生产/消费。
@@ -0,0 +1,441 @@
# Tailscale + SSH 隧道访问 TDX 开发手册
## 1. 用途与适用边界
本手册用于 Mac 本地开发期间,访问家中 Windows 上仅监听回环地址的 TDX HTTP 接口。TDX 是市场概览的正式行情来源;SSH 隧道负责把家庭局域网和外部 Tailscale 两种开发位置统一成同一个 Mac 回环入口。该链路不是生产采集、数据上报或公网部署方案。
```text
Mac 本地程序 / TDX Bridge
-> 127.0.0.1:17710
-> SSH 本地端口转发
-> 家庭局域网或 Tailscale 私有网络
-> 同一台 Windows OpenSSH
-> Windows 127.0.0.1:17709
-> TDX
```
两个场景只切换 SSH 目标别名,TDX Bridge 和上层业务始终访问 `http://127.0.0.1:17710/`。离线样本只允许作为显式开发和自动化测试回退,并必须标记为离线数据;不得伪装为实时 TDX。Windows 离线不得阻塞普通测试或构建。
## 2. 安全边界
- 不在路由器上开放或转发 SSH、RDP、`17709`、`17710` 等端口。
- TDX 继续只监听 Windows `127.0.0.1:17709`,不得改为 `0.0.0.0`。
- SSH 使用独立 Ed25519 密钥,不在脚本、仓库、文档或远程 URL 中保存密码和私钥。
- Mac 转发端口只绑定 `127.0.0.1:17710`,不得绑定局域网或所有网卡。
- 真实返回只用于只读验证。日志和测试报告必须脱敏,不保存家庭网络信息、登录信息或无关原始载荷。
- 开发隧道不连接生产数据库、不承担生产采集,也不证明数据源具备商业展示或再分发授权。
文档中的值均为占位符:
- `<WINDOWS_TAILSCALE_HOST>`:Windows 的 Tailscale MagicDNS 名称或 Tailscale IP。
- `<WINDOWS_SSH_USER>`:用于 SSH 登录的 Windows 用户。
- `<MAC_TAILSCALE_IP>`:Mac 的 Tailscale IP,仅在收紧防火墙来源时使用。
## 3. 首次建立 Tailscale 网络
### 3.1 Mac
1. 从 Tailscale 官方渠道安装客户端。
2. 登录项目使用的同一个 Tailnet。
3. 确认菜单栏中的 Tailscale 状态为已连接。
4. 在终端检查本机和节点列表:
```bash
tailscale ip -4
tailscale status
```
### 3.2 Windows
1. 从 Tailscale 官方渠道安装客户端。
2. 登录与 Mac 相同的 Tailnet。
3. 确认 Windows 节点在 Tailscale 管理后台和 Mac 的 `tailscale status` 中均为在线。
4. 在 Windows PowerShell 中检查地址和状态:
```powershell
tailscale ip -4
tailscale status
```
### 3.3 私网连通验证
在 Mac 执行:
```bash
tailscale ping <WINDOWS_TAILSCALE_HOST>
```
只有 Tailscale ping 成功后再排查 SSH。不要用公网 IP 替换占位符,也不要为排障临时开放路由器端口。
## 4. 配置 Windows OpenSSH Server
以下命令在 Windows 管理员 PowerShell 中执行。
### 4.1 安装并启动服务
```powershell
Get-WindowsCapability -Online | Where-Object Name -Like 'OpenSSH.Server*'
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
Get-Service sshd
```
如果 OpenSSH Server 已安装,`Add-WindowsCapability` 可以跳过。`Get-Service sshd` 应显示服务正在运行且启动类型为自动。
检查端口监听:
```powershell
Get-NetTCPConnection -LocalPort 22 -State Listen
```
### 4.2 确认防火墙规则
OpenSSH 安装通常会创建入站规则。先检查,不要重复创建同名规则:
```powershell
Get-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -ErrorAction SilentlyContinue
```
首次联调可以保留系统创建的 SSH 规则;链路确认后按第 11 节限制为 Tailscale 来源。不得新增公网端口映射。
## 5. 配置 SSH 密钥登录
### 5.1 在 Mac 生成项目专用密钥
```bash
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/tdx_windows -C "tdx-windows-development"
chmod 600 ~/.ssh/tdx_windows
chmod 644 ~/.ssh/tdx_windows.pub
pbcopy < ~/.ssh/tdx_windows.pub
```
私钥 `~/.ssh/tdx_windows` 只保留在 Mac,不发送给 Windows,也不提交仓库。建议为私钥设置口令,并由 macOS 钥匙串或 `ssh-agent` 管理。
### 5.2 Windows 管理员账户
Windows OpenSSH 默认从 `C:\ProgramData\ssh\administrators_authorized_keys` 读取管理员公钥。必须先创建文件,再设置 ACL;否则 `icacls` 会报“系统找不到指定的文件”。
在管理员 PowerShell 中执行,按提示粘贴刚复制的单行公钥:
```powershell
$authorizedKeys = "$env:ProgramData\ssh\administrators_authorized_keys"
New-Item -ItemType Directory -Force -Path (Split-Path $authorizedKeys)
if (-not (Test-Path $authorizedKeys)) {
New-Item -ItemType File -Path $authorizedKeys
}
$publicKey = Read-Host '粘贴 Mac 的单行 SSH 公钥'
if (-not (Get-Content $authorizedKeys | Where-Object { $_ -eq $publicKey })) {
Add-Content -Path $authorizedKeys -Value $publicKey -Encoding ascii
}
icacls $authorizedKeys /inheritance:r
icacls $authorizedKeys /grant "*S-1-5-18:F" "*S-1-5-32-544:F"
Restart-Service sshd
```
`S-1-5-18` 是 SYSTEM,`S-1-5-32-544` 是本地 Administrators 组。使用 SID 可以避免中文 Windows 的组名本地化问题。
### 5.3 Windows 非管理员账户
非管理员账户使用用户目录下的 `authorized_keys`。在该登录用户自己的 PowerShell 中执行:
```powershell
$sshDirectory = "$env:USERPROFILE\.ssh"
$authorizedKeys = "$sshDirectory\authorized_keys"
New-Item -ItemType Directory -Force -Path $sshDirectory
if (-not (Test-Path $authorizedKeys)) {
New-Item -ItemType File -Path $authorizedKeys
}
$publicKey = Read-Host '粘贴 Mac 的单行 SSH 公钥'
if (-not (Get-Content $authorizedKeys | Where-Object { $_ -eq $publicKey })) {
Add-Content -Path $authorizedKeys -Value $publicKey -Encoding ascii
}
icacls $authorizedKeys /inheritance:r
icacls $authorizedKeys /grant "$($env:USERNAME):F"
Restart-Service sshd
```
管理员和非管理员两种方式只选与实际账户匹配的一种。若修改了 `C:\ProgramData\ssh\sshd_config`,先执行 `sshd -t` 校验,再重启服务。
## 6. 配置 Mac SSH 双场景别名
家庭局域网和外部 Tailscale 连接同一台 Windows、同一个账户和同一个 `sshd`,复用同一把项目专用密钥,不创建第二把 SSH 密钥。编辑 Mac 的 `~/.ssh/config`,加入:
```sshconfig
Host tdx-windows-lan tdx-windows-tailnet
User <WINDOWS_SSH_USER>
IdentityFile ~/.ssh/tdx_windows
IdentitiesOnly yes
UseKeychain yes
AddKeysToAgent yes
ServerAliveInterval 30
ServerAliveCountMax 3
ExitOnForwardFailure yes
LocalForward 127.0.0.1:17710 127.0.0.1:17709
Host tdx-windows-lan
HostName <WINDOWS_LAN_HOST>
Host tdx-windows-tailnet
HostName <WINDOWS_TAILSCALE_HOST>
```
真实局域网地址、Tailscale 地址和用户名只保存在本机 SSH 配置,不写入仓库。开发代理需要核对当前配置时使用:
```bash
ssh -G tdx-windows-lan | awk '/^(hostname|user|identityfile|localforward) / {print}'
ssh -G tdx-windows-tailnet | awk '/^(hostname|user|identityfile|localforward) / {print}'
```
然后修正权限:
```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config ~/.ssh/tdx_windows
```
首次连接先验证密钥登录:
先在 Windows 管理员 PowerShell 查看主机公钥指纹:
```powershell
ssh-keygen -lf "$env:ProgramData\ssh\ssh_host_ed25519_key.pub"
```
再在 Mac 连接,并确认首次连接提示的 Ed25519 指纹与 Windows 输出一致:
```bash
ssh -v tdx-windows-tailnet
```
预期可以直接登录,或只要求输入私钥口令。若仍要求 Windows 账户密码,重点检查公钥文件位置、ACL、登录账户是否属于 Administrators,以及 SSH 调试输出中实际使用的密钥。
## 7. 两种场景的选择、启动和停止
### 7.1 选择规则
| 当前场景 | 使用别名 | 前置条件 |
|---|---|---|
| Mac 与 Windows 位于已配置的家庭局域网 | `tdx-windows-lan` | Windows 在线、TDX 已登录、家庭 LAN 的 SSH 22 可达 |
| Mac 在外部网络,或家庭 LAN SSH 不可达 | `tdx-windows-tailnet` | Mac 与 Windows 的 Tailscale 均在线,Tailnet ping 成功 |
两种隧道不能同时启动,因为都会独占 Mac `127.0.0.1:17710`。在家庭网络内优先使用 LAN;若 LAN 前置检查失败,不修改 TDX 监听地址,改用 Tailscale。
### 7.2 家庭局域网模式
前置检查:
```bash
ssh -o BatchMode=yes -o ClearAllForwardings=yes -T tdx-windows-lan exit
```
仓库文档不保存真实地址,家庭路径直接通过 SSH 别名验证。首次连接必须核对局域网地址与已信任的 Tailscale 地址返回相同 Windows 主机密钥指纹。
后台启动和检查:
```bash
ssh -fN -M -S ~/.ssh/tdx-windows-lan-control tdx-windows-lan
ssh -S ~/.ssh/tdx-windows-lan-control -O check tdx-windows-lan
```
停止:
```bash
ssh -S ~/.ssh/tdx-windows-lan-control -O exit tdx-windows-lan
```
Windows 的家庭 SSH 防火墙规则应使用项目专用名称 `A-Share-TDX-SSH-LAN`,只允许家庭子网访问 TCP 22。系统原有的全范围 OpenSSH 入站规则保持禁用,不为 TDX 开放 `17709`。
### 7.3 外部 Tailscale 模式
前置检查:
```bash
tailscale up
tailscale ping <WINDOWS_TAILSCALE_HOST>
```
后台启动和检查:
```bash
ssh -fN -M -S ~/.ssh/tdx-windows-tailnet-control tdx-windows-tailnet
ssh -S ~/.ssh/tdx-windows-tailnet-control -O check tdx-windows-tailnet
```
停止:
```bash
ssh -S ~/.ssh/tdx-windows-tailnet-control -O exit tdx-windows-tailnet
```
如果控制套接字残留但进程已不存在,先确认 `17710` 没有监听,再删除对应场景的单个控制套接字。不要用宽泛的 `pkill ssh`,以免终止其他 SSH 会话。
## 8. 验证 TDX 链路
### 8.1 Windows 本机验证
先确认 TDX 客户端已启动、已登录,接口监听 `127.0.0.1:17709`:
```powershell
Get-NetTCPConnection -LocalAddress 127.0.0.1 -LocalPort 17709 -State Listen
```
端口没有监听时,应先恢复 TDX 客户端;SSH 和 Tailscale 无法替代 TDX 服务本身。
### 8.2 Mac 端口验证
隧道启动后在 Mac 执行:
```bash
nc -vz 127.0.0.1 17710
lsof -nP -iTCP:17710 -sTCP:LISTEN
```
`17710` 的监听进程应为本次 SSH 隧道,不应是其他应用。
### 8.3 只读 HTTP 冒烟
```bash
curl --fail-with-body --silent --show-error \
--connect-timeout 3 \
--max-time 10 \
-H 'Content-Type: application/json' \
-X POST 'http://127.0.0.1:17710/' \
--data '{"id":1,"method":"get_market_data","params":{"stock_list":["600519.SH"],"count":5,"dividend_type":"none","period":"1d"}}'
```
链路验收条件:HTTP 返回成功,且 TDX 业务响应中的错误码表示成功。只验证少量公开行情,不调用交易、账户、自选、写入或大批量接口。
## 9. 外网场景验证
在真正离开家庭网络前,使用 Mac 手机热点或其他外部网络完成一次演练:
1. 确认 Windows 保持开机、联网,Tailscale 和 `sshd` 在线,TDX 已启动并登录。
2. Mac 切换到外部网络后重新连接 Tailscale。
3. 执行 `tailscale ping <WINDOWS_TAILSCALE_HOST>`。
4. 执行 `ssh -N tdx-windows-tailnet` 并保持终端运行。
5. 依次执行 `nc` 和只读 `curl` 冒烟。
6. 停止隧道,确认 `127.0.0.1:17710` 不再监听。
如果外网演练失败,开发和自动化测试可显式切换到离线样本,并明确标记数据来源。不要临时开放公网 SSH、RDP 或 TDX 端口。
## 10. Windows 无人值守准备
当前链路是开发辅助,不承诺生产级 7x24 可用性。为了减少外出后无法联调的概率,可在 Windows 上做以下准备:
- 将虚拟机配置为宿主机启动后自动启动,并确认异常关机后的恢复策略。
- 保持 Tailscale 与 `sshd` 服务自动启动,重启后通过另一台 Tailnet 设备验证在线状态。
- 接通电源时禁用自动睡眠:
```powershell
powercfg /change standby-timeout-ac 0
```
- 明确 TDX 是否需要交互式桌面登录、验证码或人工确认。需要人工登录时,不得把它描述为无人值守服务。
- 安排 Windows 更新和虚拟机重启窗口;更新后重新验证 Tailscale、SSH、TDX 监听和只读请求。
- 不为自动启动把 Windows 密码、TDX 凭据或 SSH 私钥写入仓库和普通脚本。
## 11. 收紧访问范围
链路验证通过后,在 Tailscale 管理后台将访问规则限制为指定开发身份或 Mac 到 Windows SSH 端口。具体策略应以当前 Tailnet 的身份和标签设计为准,不在仓库保存真实账户和地址。
还可在 Windows 中新增一条仅允许 Mac Tailscale IP 访问 SSH 的规则。先确认 Tailscale 网卡名称,再创建规则:
```powershell
Get-NetAdapter | Where-Object InterfaceDescription -Match 'Tailscale'
New-NetFirewallRule `
-DisplayName 'OpenSSH Server - Tailscale Mac Only' `
-Direction Inbound `
-Action Allow `
-Protocol TCP `
-LocalPort 22 `
-RemoteAddress '<MAC_TAILSCALE_IP>' `
-InterfaceAlias 'Tailscale'
```
新规则必须在外网场景实测通过后,才能禁用范围更宽的旧 SSH 规则。若实际网卡别名不是 `Tailscale`,使用 `Get-NetAdapter` 显示的名称,不凭猜测修改。
## 12. 故障排查
### Tailscale ping 不通
- 检查两端是否登录同一个 Tailnet、节点是否过期、Windows 是否睡眠或断网。
- 检查 Tailnet ACL 或设备审批状态。
- 不要先排查 TDX;此时底层私网尚未连通。
### SSH 连接超时或拒绝
- Windows 执行 `Get-Service sshd` 和 `Get-NetTCPConnection -LocalPort 22 -State Listen`。
- 检查 Windows 防火墙和 Tailscale 访问规则。
- Mac 执行 `ssh -vvv tdx-windows-tailnet`,确认目标是 Tailscale 地址而非家庭公网地址。
### SSH 仍要求 Windows 密码
- 确认 `IdentityFile` 指向 `~/.ssh/tdx_windows`,并检查 `ssh -vvv` 是否提供了该密钥。
- 管理员账户确认文件是 `C:\ProgramData\ssh\administrators_authorized_keys`;非管理员账户确认文件是用户目录下的 `.ssh\authorized_keys`。
- 确认公钥为完整单行文本,文件已先创建,ACL 没有继承无关权限。
- 执行 `sshd -t` 检查配置,再执行 `Restart-Service sshd`。
### Mac 的 `17710` 无法监听
- 查看 SSH 前台错误;`ExitOnForwardFailure yes` 会在端口冲突或转发失败时直接退出。
- 执行 `lsof -nP -iTCP:17710 -sTCP:LISTEN` 查找占用者。
- 不要把本地端口改成 `0.0.0.0`;需要换端口时同步修改本机开发配置,并保持回环绑定。
### 端口可连但 HTTP 失败
- 在 Windows 本机确认 TDX `127.0.0.1:17709` 正在监听。
- 确认 TDX 客户端已登录且当前版本仍支持目标方法。
- 使用最小只读请求检查 HTTP 状态、TDX 错误码和响应时间,不把协议错误误判为网络错误。
### 外出后 Windows 不在线
- 无法远程唤醒或恢复交互式 TDX 登录时,显式切回离线样本继续开发,并保持非实时标记。
- 不通过新增公网暴露、共享密码或关闭防火墙绕过问题。
- 待公网部署需求明确后,另立功能实现生产级采集器、心跳、补传和远程运维。
## 13. 日常操作速查
### 13.1 在家开发
```bash
ssh -o BatchMode=yes -o ClearAllForwardings=yes -T tdx-windows-lan exit
ssh -fN -M -S ~/.ssh/tdx-windows-lan-control tdx-windows-lan
ssh -S ~/.ssh/tdx-windows-lan-control -O check tdx-windows-lan
nc -vz 127.0.0.1 17710
```
结束家庭局域网联调:
```bash
ssh -S ~/.ssh/tdx-windows-lan-control -O exit tdx-windows-lan
lsof -nP -iTCP:17710 -sTCP:LISTEN
```
### 13.2 在外开发
```bash
tailscale up
tailscale ping <WINDOWS_TAILSCALE_HOST>
ssh -fN -M -S ~/.ssh/tdx-windows-tailnet-control tdx-windows-tailnet
ssh -S ~/.ssh/tdx-windows-tailnet-control -O check tdx-windows-tailnet
nc -vz 127.0.0.1 17710
```
结束外部联调:
```bash
ssh -S ~/.ssh/tdx-windows-tailnet-control -O exit tdx-windows-tailnet
lsof -nP -iTCP:17710 -sTCP:LISTEN
```
最后一条命令无输出表示本地转发已经停止。切换场景时必须先停止当前隧道,再启动另一场景;不得通过更换 TDX Bridge 地址绕过端口冲突。
## 14. 后续 Provider 接入约束
- 平台配置只能引用 Mac 回环地址 `127.0.0.1:17710`,不得保存家庭网络或 Tailscale 地址。
- TDX 是正式行情来源;离线样本只作为显式开发和测试回退,必须展示来源与陈旧状态,生产环境禁止启用。
- Provider 必须限制请求超时、响应体大小、股票数量和并发,并输出来源、采集时间、交易日期、协议版本、追踪 ID 和陈旧状态。
- TDX 原始字段仅在 Adapter 内转换,上层市场概览、规则分析和 AI 分析只依赖版本化内部契约。
- 隧道中断必须返回明确的不可用或陈旧状态,不能把离线样本伪装成实时行情。
- Windows 采集器、公网接收 API、多目标推送、补传队列和无人值守运维继续延期,实施时单独立项并重新进行安全、性能和合规评估。
+32 -19
View File
@@ -1,37 +1,50 @@
# Ubuntu 源码生产部署 # Ubuntu 源码生产部署
正式支持 Ubuntu 22.04 LTS 与 Ubuntu 24.04 LTS 的 x86_64。服务器管理员预先提供 Node.js 22 LTS、pnpm 10、Nginx,以及 MySQL 5.7、Redis、RocketMQ 5.x 或相应外部服务;项目不负责安装或升级这些软件,也不修改系统软件源。 这是项目唯一生产部署方式,支持 Ubuntu 22.04 LTS 与 Ubuntu 24.04 LTS x86_64。服务器管理员预先提供 Node.js 22.x、pnpm 10.25.0、Nginx,以及外部 MySQL 5.7.x、Redis、RocketMQ 5.x;项目不负责安装、升级、启动、停止、删除或修改这些系统软件与服务。
## 前置验证 ## 构建发布目录
在固定提交的干净工作区执行:
```bash ```bash
uname -m uname -m
node --version node --version
pnpm --version pnpm --version
nginx -v pnpm install --frozen-lockfile
pnpm verify:release
``` ```
架构必须为 `x86_64`,Node.js 必须为 22 LTS,pnpm 必须为 10.x。不满足要求时终止部署。 架构必须为 `x86_64`,Node.js 必须为 22.x,pnpm 必须为 10.25.0。发布门禁会完成测试、Web/Server 构建、双视口浏览器检查,并核对 Web、API、Scheduler、Worker 产物与 systemd/Nginx 模板。
## 目录与配置 每次发布使用 `/opt/a-share-analysis/releases/<版本或提交>/` 新目录。完整传输并验证目录后,再把 `/opt/a-share-analysis/current` 原子切换到目标目录;禁止在 `current` 中原地覆盖文件,也禁止只发布部分进程产物。
- 发布目录:`/opt/a-share-analysis/releases/<版本或提交>/`。 ## 配置与 systemd
- 当前版本:`/opt/a-share-analysis/current` 符号链接。
- 生产配置:`/etc/a-share-analysis/api.env`、`scheduler.env`、`worker.env`、`web.env`。
- 运行用户:非登录系统用户 `a-share`。
真实配置从仓库生产模板生成,但不得放入发布目录。API、Scheduler、Worker 的 systemd 单元分别通过 `EnvironmentFile=` 读取自己的配置;包含秘密的文件建议为 `root:a-share 0640`。 生产配置放在 `/etc/a-share-analysis/api.env`、`scheduler.env`、`worker.env`,建议权限 `root:a-share 0640`;Web 的 `VITE_` 公开变量在构建前注入。三个 systemd 单元通过各自的 `EnvironmentFile=` 只读取本进程需要的键,运行用户为非登录系统用户 `a-share`。
## 构建与启动边界 ```bash
sudo install -m 0644 deploy/systemd/a-share-api.service.example /etc/systemd/system/a-share-api.service
sudo install -m 0644 deploy/systemd/a-share-scheduler.service.example /etc/systemd/system/a-share-scheduler.service
sudo install -m 0644 deploy/systemd/a-share-worker.service.example /etc/systemd/system/a-share-worker.service
sudo install -m 0644 deploy/nginx/a-share-analysis.conf.example /etc/nginx/conf.d/a-share-analysis.conf
sudo systemd-analyze verify /etc/systemd/system/a-share-api.service
sudo systemd-analyze verify /etc/systemd/system/a-share-scheduler.service
sudo systemd-analyze verify /etc/systemd/system/a-share-worker.service
sudo nginx -t
sudo systemctl daemon-reload
sudo systemctl restart a-share-api.service
sudo systemctl restart a-share-scheduler.service
sudo systemctl restart a-share-worker.service
sudo systemctl status a-share-api.service a-share-scheduler.service a-share-worker.service
sudo journalctl -u a-share-api.service -u a-share-scheduler.service -u a-share-worker.service --since '5 minutes ago'
curl --fail http://127.0.0.1:3000/api/v1/health
curl --fail http://127.0.0.1/
```
使用 `pnpm install --frozen-lockfile` 安装锁定依赖,在新发布目录构建 Web 和 Server。Web 静态文件由 Nginx 托管,API、Scheduler、Worker 运行编译后的 JavaScript。禁止 Vite 开发服务器、watch、调试端口和生产运行 TypeScript。 当前工程尚无业务表迁移;后续新增迁移后必须在切换 `current` 前单独执行并记录结果。生产环境禁止 `synchronize: true`,开发流程也禁止用生产数据库做 Schema 基线或连接测试。
当前应用尚未脚手架化,仓库中的 systemd 与 Nginx 文件是路径和权限契约示例,不能冒充已经验证的线上启动文件。后续应用功能必须补充实际构建、启动和健康检查验证。 ## 检查与回退
## 升级、检查与回退 使用 `systemctl status`、`journalctl -u`、HTTP 健康端点和 Nginx 同源访问结果确认发布。任一验证失败时,把 `/opt/a-share-analysis/current` 原子切回上一完整发布目录,重启三个 systemd 服务并重复健康检查。
在新的不可变发布目录完成安装、构建和配置校验后,原子切换 `current`,依次重启 API、Scheduler、Worker 并检查 `systemctl status`、`journalctl` 和 HTTP 健康端点。失败时切回上一完整目录并重启服务;生产配置不随版本切换覆盖。 `/etc/a-share-analysis/*.env` 和外部 Redis、MySQL、RocketMQ 数据不随应用目录切换而覆盖或删除。RocketMQ 的 NameServer、Broker、Proxy 与 CommitLog 由运维独立维护。
项目部署流程禁止连接或读取生产数据库做开发验证。数据库备份属于独立运维职责,应用回退不得删除或覆盖数据。
RocketMQ 由运维独立维护 NameServer、Broker 和需要时的 Proxy。应用发布只读取受控的 RocketMQ Endpoint、Topic 前缀与 Group 配置,不负责创建或升级集群,也不得把 Broker 数据目录放进应用发布目录。
@@ -0,0 +1,55 @@
# 数据源接入架构与 TDX PoC 规划
## 方案结论
当前采用“平台先行、采集器后置”。Mac 本地开发以固定样本回放为默认 Provider;需要验证真实字段时,通过 Tailscale + SSH 隧道访问家中 Windows 的 TDX `127.0.0.1:17709`。不在当前阶段实现 Windows 常驻采集程序、GUI 或公网推送。
```text
固定样本 / Mac TDX 隧道
↓
DataProvider 端口
↓
标准化市场事件 → 市场概览业务
未来公网模式:采集器 → 多目标隔离推送 → 平台接收 API
```
## 方案比较
- 本地样本回放(当前采用):不引入 Windows/公网依赖,测试稳定可重复,适合先开发市场概览;缺点是不能代表实时数据质量。
- Mac 通过 Tailscale SSH 隧道调用 TDX(当前联调):可以验证真实字段,但依赖家中 Windows 在线和人工维护。
- Windows 常驻采集器(延期):未来可选 Node、Python、Go、Rust、Electron、Tauri 或系统服务,必须按部署规模、资源、自动更新和安全能力重新评估。
## 当前组件边界
当前只新增/维护平台侧 Provider 端口和固定样本。样本 Provider 与真实 TDX Provider 使用同一标准化契约,市场概览不感知来源差异。未来采集器应作为独立项目或 workspace,不反向污染 NestJS 业务模块;公网接收 API、目标队列、签名握手和 GUI 另立功能档案。
## Provider 与事件模型
Provider 生成不可变标准化事件,包含 `eventId`、`source`、`capturedAt`、`tradeDate`、`schemaVersion`、`traceId` 和数据新鲜度。TDX 原始字段只能存在于 Adapter 内,规则分析、AI 分析、API 和页面只依赖内部模型。
## 安全策略与评估
- Mac 本地样本和 TDX 隧道均不接触生产配置、生产数据库或公网接收 API。
- 真实 TDX 只读调用使用 SSH 密钥隧道,`17709`、SSH 和 RDP 不做公网端口映射。
- 样本删除凭据、家庭地址和无关原始字段;日志只保存统一错误分类和性能摘要。
- 未来采集器的密钥存储、目标认证、IPC 和自动更新不在当前方案中预设,必须重新安全评估。
- 数据再分发许可属于外部合规风险。PoC 只用于个人开发验证,不宣称获得商业展示或再分发授权。
## 性能目标与评估
- 固定样本回放必须确定性、可重复且不访问网络;Provider 标准化耗时纳入单元测试与基准记录。
- 真实 TDX 请求目标超时 5 秒并记录响应耗时和字段完整性。
- 公网上传并发、队列容量、心跳周期和 GUI 资源目标延期到采集器立项,不在当前阶段作容量承诺。
## 失败恢复
TDX 请求失败返回统一错误分类和陈旧状态;本地平台可切回固定样本继续开发,不能把样本伪装为实时行情。上传重试、补传、熔断和备用免费源切换属于后续公网功能。
## 测试边界
单元测试使用固定 TDX 响应验证 Provider、标准化和错误映射;通过 Tailscale SSH 隧道做真实只读冒烟。Electron/Tauri 安装、托盘、开机启动、操作系统密钥存储、目标队列和公网接收测试延期,不能在当前阶段宣称通过。
## 依赖与退出方案
当前不新增 Electron、Python、Go、Rust 或其他采集器运行时依赖。未来采集器实现前重新比较语言、部署形态、许可证、资源、自动更新和安全边界;只要遵循 Provider/上传契约,采集器可替换而不改市场概览。
@@ -0,0 +1,26 @@
# GitNexus 开发前基线
- 功能编号:FEAT-DS-001
- 记录时间:2026年8月14日 GMT+8 02:38:03
- 分支:main
- 基线提交:a398bc418d39
## 工作区
```text
?? docs/features/FEAT-DS-001-tdx-ingestion-poc/
```
## GitNexus 状态
```text
Repository: /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis
Indexed: 8/14/2026, 2:38:02 AM
Indexed commit: a398bc4
Current commit: a398bc4
Status: ✅ up-to-date
```
## 后续人工分析
在修改代码前,将 GitNexus query、context、impact 的结论写入 `gitnexus/impact-plan.md`。高风险结果必须先获得用户确认。
@@ -0,0 +1,24 @@
# GitNexus 开发前影响计划
- 功能编号:FEAT-DS-001
- 总体风险:LOW(当前仅规划 Provider 边界和本地联调,不新增桌面应用或公网入口)
## 直接与间接影响
- `gitnexus query --repo a-share-analysis "market data ingestion TDX adapter scheduler worker"` 未找到现成行情 Provider,相关现有流程集中在 Scheduler/Worker 启动和运行时配置。
- `gitnexus query --repo a-share-analysis "configuration HTTP API health Redis MySQL RocketMQ"` 表明 API 当前只有健康检查流程,新增接收模块不会修改 `HealthService`。
- 对名称 `health` 的 upstream impact 命中 Web API 目录且风险为 LOW、无上游消费者;由于名称存在歧义,结论仅作为辅助证据,不解释为对 API 全局无影响。
- 当前不新增 `desktop/tdx-agent` 或 `MarketIngestModule`,不会修改现有 Web、API、Scheduler 或 Worker 符号。
- 直接消费者是后续市场概览 Service;未来采集器、RocketMQ Worker、Redis 快照和 MySQL 历史属于延期功能,必须重新执行影响分析。
## 跨模块同步修改
- HTTP/OpenAPI:当前不新增公网握手或上报 DTO;Provider 内部契约不得泄漏到 Web。
- Web API:主平台 Vue 不修改;不存在 Electron renderer。
- 消息契约:本 PoC 不启用 RocketMQ,也不预留伪接收实现。
- 数据库与 Redis:不新增 Schema,不读取生产库;PoC 接收仅做受控确认。
- API:后续 Provider 如进入 API,再对 `ApiModule.register`、OpenAPI 和运行时配置执行影响分析。
- Scheduler/Worker:本 PoC 不修改;后续正式排队功能另立功能档案和影响分析。
- 配置部署:当前不新增 Windows 或公网配置,不改变主平台源码部署政策。
- 测试:使用固定样本和 TDX 隧道冒烟;采集器打包和 Windows 无人值守测试延期。
- 文档:记录延期原因、Provider 边界、安全、性能和未来重新立项条件。
@@ -0,0 +1,17 @@
# 数据源接入架构与 TDX PoC 规划
## 当前计划(不实现采集器)
1. 建立与运行时无关的 `DataProvider`、市场事件和数据新鲜度契约。
2. 用固定样本 Provider 支撑市场概览的规则、AI、混合和对照分析开发。
3. 按 [Tailscale + SSH 隧道访问 TDX 开发手册](../../deployment/tailscale-tdx-development.md) 执行真实 TDX 只读请求,保存脱敏字段报告。
4. 对 TDX 字段缺失、协议错误和陈旧数据做 Provider 层降级,不连接生产数据。
5. 暂不新增 Windows 应用、Electron/Tauri、目标推送、补传队列、公网接收 API、RocketMQ 事件或数据库表。
6. 待公网部署需求确定后,另立采集器功能档案,重新评估 Node、Python、Go、Rust 或系统服务方案。
## 后置功能必须覆盖
- 单次采集、多目标隔离推送。
- production/development 独立地址、密钥、队列、状态和启停;两者地址均可修改。
- production 未配置或停止为正常状态;停止时不删除队列、不转投 development。
- HTTPS/HMAC、重放防护、握手身份、限流、补传、熔断、心跳、无人值守运行和系统更新。
@@ -0,0 +1,12 @@
id: FEAT-DS-001
name: 数据源接入架构与 TDX PoC 规划
slug: tdx-ingestion-poc
status: deferred
owner: project
created_at: 2026-08-14
requirements: requirements.md
prd: prd.md
design: design.md
implementation_plan: implementation-plan.md
traceability_note: 当前只完成数据源边界和本地联调规划;操作步骤见 ../../deployment/tailscale-tdx-development.md;Windows 采集器与公网接入延期到公网部署需求确认后单独立项。
release: unreleased
@@ -0,0 +1,37 @@
# TDX 数据接入 PoC PRD
## 用户问题
TDX 客户端运行在家中 Windows 虚拟机,并且接口只监听 Windows 本机 `127.0.0.1:17709`。公网平台和人在外面的开发设备都不能直接访问该端口,需要验证一套不暴露 TDX、可 7×24 小时运行的数据上报链路。
## 目标
在不提前引入公网部署和 Windows 常驻程序的前提下,先确定 TDX 数据源边界、标准化 Provider 契约和 Mac 本地联调方式。Windows 采集器、托盘 GUI、目标推送和公网接收入口延期,避免在生产部署形态尚未确定时锁定技术栈。
## 范围
- Mac 本地开发使用固定样本回放作为默认数据源,并保留通过 Tailscale SSH 隧道调用家中 Windows TDX 的人工联调方式。
- 只定义与运行时无关的 `DataProvider`、标准化事件和数据新鲜度字段,不实现 Windows 常驻采集程序。
- 记录未来公网模式的单次采集、多目标隔离推送、地址可变和目标启停原则,但不在本功能实现。
- 只读验证指数、单股 K 线、快照、分时和板块接口中实际可用的字段。
- 通过 Tailscale + SSH 隧道从外部 Mac 远程验证家中 Windows TDX;验证结果只用于 Provider 契约,不写入生产链路。
## 非目标
- 不在本功能中开发 Windows 采集应用、Electron/Tauri GUI、开发/生产接收 API、目标队列或公网推送。
- 不在本功能中开发市场概览页面、AI 分析、正式 Worker 消费或生产接入。
- 不开放 TDX `17709`、SSH 或 RDP 到公网。
- 不写入自选、交易、账户或 TDX 状态。
- 不把通达信数据授权问题解释为已解决;商业展示和再分发授权仍需单独确认。
## 成功指标
- 固定样本能够覆盖 Provider 的 K 线、快照、分时、板块和错误映射测试。
- 通过 SSH 隧道完成至少一次真实 TDX 只读请求,并保存脱敏字段报告。
- Provider 契约不依赖 Node、Electron、Python 或具体传输方式;未来采集器可独立替换。
## 风险
- TDX 客户端协议和返回字段可能变化;代理必须保留原始字段版本和来源标识。
- 未来公网部署会增加采集节点、推送认证和再分发风险;延期期间不把这些风险误标为已解决。
- 行情数据的展示、再分发和商业使用权利不由代码许可证自动授予。
@@ -0,0 +1,28 @@
# 数据源接入架构与 TDX PoC 工程需求
## 当前阶段 Provider 边界
- Provider 暴露与采集器语言和传输方式无关的只读接口,统一返回 `source`、`capturedAt`、`tradeDate`、`schemaVersion`、`traceId` 和数据新鲜度。
- 默认开发 Provider 使用仓库内固定样本,不连接生产数据源;真实 TDX Provider 只通过显式本地配置和 Tailscale SSH 隧道联调。
- TDX Provider 限制回环地址、请求超时、响应体大小、股票列表和并发;不得把家庭地址或凭据写入代码。
- Provider 原始响应映射为版本化内部载荷,上层分析不得依赖 TDX 原始字段名称。
## 当前运行与环境
- 平台仅在 Mac 本地源码运行,不要求安装 Windows 采集程序。
- 固定样本支持离线、确定性和可重复测试;真实 TDX 联调依赖家中 Windows 在线,但不能成为日常测试门禁。
- 当前不新增 Electron、Tauri、Python 服务、Go/Rust 程序、公网接收 API、文件补传队列或目标密钥。
- SSH 私钥、TDX 地址、家庭网络信息和开发数据库凭据不得进入仓库、日志、样本或前端构建物。
## 延期的公网采集原则
- 采集器语言、GUI 壳和打包方式不预设为 Node/Electron,待公网部署需求确认后比较 Node、Python、Go、Rust 和系统服务方案。
- 未来采集器只采集一次,production/development 使用独立地址、节点 ID、密钥、队列、上传器、心跳和启停状态。
- production 与 development 地址均可修改且独立测试;任一目标故障或重配不得影响另一目标。
- production 未配置或停止属于正常状态;停止时不删除已有队列、不转投 development。
- 公网模式必须重新设计 HTTPS/HMAC、重放防护、身份握手、限流、补传、熔断、无人值守运行和操作系统密钥存储。
## 可观测性
- Provider 结果标记来源、采集时间、数据时间、陈旧状态和统一错误分类。
- 真实联调报告必须脱敏,不保存完整家庭地址、SSH 信息、供应商凭据或未筛选的原始载荷。
@@ -0,0 +1,23 @@
# 数据源接入架构与 TDX PoC 测试计划
## 当前阶段功能验证
- 固定样本验证 K 线、快照、分时和板块 Provider 载荷映射。
- 通过 Tailscale SSH 隧道验证真实 TDX 只读请求,并保存脱敏字段报告。
- 验证 Provider 在 TDX 错误、超时、空结果和陈旧数据下返回统一错误分类。
- 验证市场概览只依赖内部模型,不直接读取 TDX 原始字段。
## 安全验证
- SSH 私钥、TDX 地址、家庭网络信息和开发数据库凭据不进入仓库、样本、日志或前端构建物。
- TDX 只通过 SSH 隧道访问,`17709` 不开放公网。
- 固定样本不包含供应商凭据和不必要的完整原始载荷。
## 性能验证
- 固定样本下测量 Provider 标准化耗时,确保回放不依赖外部网络。
- 真实 TDX 请求记录响应耗时和字段完整性;不对未来采集器的上传、队列和 GUI 资源作结论。
## 不适用项与边界
不做 Electron/Tauri 窗口、托盘、安装包、生产数据库迁移、RocketMQ 收发和公网接收验证,原因是采集器与公网部署已延期。市场概览页面另按业务功能执行视觉验证。
@@ -0,0 +1,31 @@
# GitNexus 开发前基线
- 功能编号:FEAT-MO-001
- 记录时间:2026年08月18日 00:26:46 CST
- 分支:main
- 基线提交:`c0a6f5560584`
- 创建方式:用户授权跳过 `v0.0.9` Schema 备份后,按 `governance:start` 输出结构手工留痕
## 工作区
```text
(干净)
```
## GitNexus 状态
```text
Repository: /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis
Indexed: 8/17/2026, 6:03:13 PM
Indexed commit: c0a6f55
Current commit: c0a6f55
Status: up-to-date
```
## Schema 门禁例外
失败证据、用户决定、禁止伪造边界和残余风险见 `../schema-baseline-waiver.md`。本记录不表示 `governance:start` 自动门禁通过。
## 后续人工分析
首页设计确认后,在修改任何函数、类或方法前继续执行 GitNexus query、context 和 upstream impact,并将直接、间接、跨模块消费者及高风险处置补充到 `impact-plan.md`。
@@ -0,0 +1,36 @@
# GitNexus 开发前影响计划
- 功能编号:FEAT-MO-001
- 基线提交:`c0a6f5560584`
- 当前阶段:TDX 开发连接设计与首页方案确认
- 当前总体风险:LOW(仅本机 SSH 配置和操作文档);首页业务代码风险待设计确认后按符号补充
## 直接与间接影响
### TDX 双路径开发连接
- 正式行情来源确定为 TDX;家庭局域网和外部 Tailscale 只改变 Mac 到同一 Windows `sshd` 的网络路径。
- TDX Bridge 的稳定入口固定为 Mac 回环地址 `127.0.0.1:17710`,市场概览、规则分析、AI 分析和未来 HTTP 契约不得依赖家庭地址、Tailscale 地址或 TDX 原始字段。
- 当前仓库没有 TDX Provider 或市场概览运行时符号,本阶段只更新操作文档;GitNexus 未识别可执行调用链影响。
- 首页业务设计确认后,必须对 `App.vue`、`createAppRouter`、后端模块装配、HTTP DTO 和新增市场概览符号分别执行 upstream impact。HIGH 或 CRITICAL 结果先告知用户再修改。
## 跨模块同步修改
- HTTP/OpenAPI:当前连接文档不修改;首页正式接入时需要版本化市场概览 DTO 与 OpenAPI 契约。
- Web API 与 adapter:当前不修改;未来页面只能经 `web/src/api/<业务域>/index.ts`、Axios 封装和 ViewModel 消费数据。
- 消息契约、Redis、MySQL、Scheduler、Worker:当前不启用。正式采集链路仍按独立功能立项,不能由 API 请求临时抓取全市场数据。
- 配置部署:真实地址、用户名、密钥和控制套接字只保留在开发机,不进入仓库、环境模板或前端构建物。
- 测试:两种 SSH 路径均需验证到同一 Mac 回环端点;离线样本只作显式开发回退,不得标记为实时 TDX。
- 文档:同步更新 Tailscale/SSH 开发手册,明确家庭局域网与外部 Tailscale 的选择、启动、停止、切换和验证方法。
## 安全、性能与回退
- Windows 的 TDX 继续只监听 `127.0.0.1:17709`,禁止改为局域网或公网监听。
- 家庭 SSH 入站规则只允许家庭子网访问 TCP 22;系统原有全范围 OpenSSH 规则保持禁用。
- 两条 SSH 路径复用同一项目专用 Ed25519 密钥;局域网主机密钥必须与已验证的 Tailscale 主机密钥指纹一致。
- 家庭 LAN 与当前 Tailscale 直连延迟均足以满足开发期分钟级行情;首页不得承诺秒级刷新。
- 回退时停止对应 SSH 控制连接、删除本机 TDX 别名,并删除 Windows 项目专用防火墙规则;不得删除通用 SSH 密钥、Tailscale 账户或 TDX 数据。
## Schema 例外风险
`v0.0.9` Schema 基线缺失会阻断严格自动治理门禁,风险见 `../schema-baseline-waiver.md`。本功能不借该例外修改数据库结构、读取生产数据库或声称发布门禁通过。
@@ -0,0 +1,23 @@
# v0.0.9 Schema 基线一次性例外
- 功能编号:FEAT-MO-001
- 日期:2026-08-18
- 适用范围:仅 FEAT-MO-001 开发启动
## 事实记录
按常规流程执行 `npm run schema:baseline` 时,本机因不存在 MySQL 5.7.x 的 `mysql` 与 `mysqldump` 客户端,在执行 `mysql --version` 前以 `spawnSync mysql ENOENT` 失败。失败发生在客户端前置检查阶段,未连接开发数据库,也未生成基线目录或半成品。
用户确认本次继续跳过数据库备份。该决定只适用于从已发布版本 `v0.0.9` 启动 FEAT-MO-001,不继承 GOV-011 对 `v0.0.8` 的一次性例外,也不建立通用跳过能力。
## 处理决定
- 不伪造 `not_applicable`、`captured_empty`、空 SQL、客户端版本、服务端版本或校验摘要。
- 不修改 Schema 工具或 `governance:start` 增加跳过参数。
- 手工保存与 `governance:start` 同等结构的 GitNexus 开发前基线和影响计划。
- FEAT-MO-001 不得因此连接、探测或读取生产数据库。
- 后续功能需要 Schema 基线时,仍必须提供可验证的 MySQL 5.7.x 客户端,或再次获得用户针对该版本的明确授权。
## 风险与接受
缺少 `v0.0.9` Schema 基线意味着仓库不能证明该发布版本对应的开发库结构,也会使依赖严格 Schema 证据的自动治理门禁无法通过。用户接受本次追溯风险;该例外不表示数据库门禁、发布门禁或未来数据库变更已经通过。
@@ -15,3 +15,4 @@ code_review: review/code-review.md
standards_review: review/standards-review.md standards_review: review/standards-review.md
implementation_commit: 9203fdd implementation_commit: 9203fdd
release: v0.0.5 release: v0.0.5
superseded_by: GOV-009/source-only-deployment-design.md
@@ -0,0 +1,61 @@
# 前后端项目架构复核与论证
- 复核基线:`95b8611bd9bbc282193591e472e2e19c617e5035`
- 状态:实现已验证,用户于 2026-08-17 确认当前架构
## 实际落地结构
```text
repository
├── web/ Vue 3 独立工程
│ └── src/
│ ├── app/ 应用装配、路由和根视图
│ ├── api/generated/ OpenAPI 自动生成类型
│ ├── api/adapters/ 面向页面的稳定数据适配
│ └── styles/ Sass 全局样式与后续 token 入口
├── server/ NestJS 独立工程
│ ├── apps/api/ HTTP 与 OpenAPI 入口
│ ├── apps/scheduler/ 只负责任务触发的无 HTTP 进程
│ ├── apps/worker/ 任务执行的无 HTTP 进程
│ └── libs/
│ ├── config/ 三进程最小权限配置契约
│ ├── http-contracts/ Server DTO
│ ├── message-contracts/ Server 内部 RocketMQ 信封
│ └── infrastructure/ Redis、MySQL、消息与生命周期适配
├── deploy/ systemd、Nginx、env 源码部署模板
└── tools/ 治理、Schema、契约、边界和部署验证
```
## 为什么当前拆分合适
1. **前后端工程分开,但仓库不割裂。** Web 和 Server 有各自 package、构建与类型检查,责任清楚;根 workspace 只做质量编排。个人开发阶段仍能一次安装和验证,避免维护多个仓库与跨仓库版本同步。
2. **不建立根共享 contracts 包。** HTTP 只有一个事实源:Server DTO 生成 OpenAPI,Web 再生成自己的类型。Web 无法直接引用 Server 源码,`.vue` 和 TypeScript 都有自动边界检查。这样比手工同步两份类型或共享内部类更明确。
3. **一个 Server 工程、三个进程入口。** API、Scheduler、Worker 使用相同基础设施与消息契约,但启动、配置和部署彼此独立。当前规模下没有必要拆成三个仓库或三个重复 Nest 工程;未来可独立扩容进程而不复制公共代码。
4. **配置是进程级最小权限。** API 不读取任务消费配置,Scheduler 不读取 MySQL/AI 密钥,Worker 不读取 API 端口。配置先校验和冻结,再通过动态模块注入,测试与生产使用同一装配路径。
5. **基础设施通过 Adapter 隔离。** 业务代码将依赖 MessageBus、Repository 和数据源端口;RocketMQ 客户端尚未验证时明确禁用,避免以临时内存队列形成错误语义。
6. **生产只有一条源码路径。** Ubuntu 源码部署直接使用 Web dist 与三个 Server dist 入口,由 systemd 和 Nginx 管理;源码发布门禁验证这些路径一致,避免维护第二套构建和运行语义。
## 适合下一阶段的扩展方式
- Web 市场概览应建立一个可连续阅读的 `features/market-overview/` 业务目录,内部按页面、数据适配和状态拆分;短线与中长线作为市场概览下的模式,不拆成两个独立应用。
- Server 在 API/Scheduler/Worker 各入口内注册同一市场概览业务能力的不同适配面;共享领域模型和规则计算放入稳定业务库,HTTP DTO、消息 DTO 与数据库实体继续分离。
- 用户体系、订阅和权限暂不加入当前业务模型;未来通过独立功能档案增加,不让其反向污染市场概览核心。
- 当某个业务域出现独立发布节奏、团队所有权或明显扩容边界时,再论证拆包或拆服务;当前提前微服务化只会增加契约、部署和运维成本。
## 已知限制
- 当前 Web 只是工程外壳,没有市场概览 UI、行情图表和分析工作台。
- RocketMQ 只有契约和禁用 Adapter,尚未选择并验证 Node 客户端。
- TypeORM 已固定安全选项,但尚无业务实体和迁移。
- 用户体系和订阅能力按用户决定后置,不在 GOV-009 范围。
- 仅源码部署调整已实现;历史 Docker 验证只作为决策追溯,不再代表当前可用能力。
## 复核结论
现有架构适合“先做市场概览、个人使用为主、未来可扩展订阅”的阶段:边界清晰、运行方式简单、契约可自动校验,也保留 API/Scheduler/Worker 独立扩容路径。它不是不可变终局;完成市场概览真实业务后,仍应根据模块依赖和运行数据再次复核,而不是凭脚手架预判过度拆分。
## 架构确认记录
用户已于 2026-08-17 完成最终确认,同意以本文描述的实际结构作为当前业务开发基线:Vue 3 与 NestJS 工程分离维护,Server 保持 API、Scheduler、Worker 三进程,HTTP 契约沿 Server DTO → OpenAPI → Web 类型单向发布,生产交付仅支持 Ubuntu 源码部署。该确认满足 GOV-009 的最终完成门禁,GOV-009 与 GOV-010 一并归入 `v0.0.8`。
确认不代表架构永久冻结。市场概览全部业务完成后,仍需依据实际模块依赖、运行负载和维护成本再次论证;在此之前不得仅凭预期拆分微服务或共享契约包。
@@ -0,0 +1,113 @@
# 应用工程脚手架基线设计
- 功能编号:GOV-009
- 设计版本:0.1
- 状态:review
- 日期:2026-08-13
## 总体结构
```text
repository
├── web/ Vue 3 独立前端工程
│ ├── src/api/generated/ OpenAPI 生成的类型与客户端
│ ├── src/api/adapters/ DTO 到页面模型的转换
│ ├── src/app/ 路由、状态和应用外壳
│ └── tests/ 组件与浏览器测试
├── server/ NestJS 独立后端工程
│ ├── apps/api/ HTTP 与 OpenAPI 入口
│ ├── apps/scheduler/ 定时触发入口
│ ├── apps/worker/ 任务执行入口
│ └── libs/
│ ├── config/ 进程级配置解析与脱敏
│ ├── http-contracts/ DTO 与 OpenAPI 模型
│ ├── message-contracts/ Server 内部 RocketMQ 事件
│ ├── domain/ 后端业务模型与端口
│ └── infrastructure/ Redis、MySQL、消息适配器
├── deploy/ 环境和部署契约
└── tools/ 治理、Schema 与生成校验
```
根目录只负责编排命令和版本约束,不承载业务运行代码。Web 与 Server 各自拥有依赖、TypeScript 配置和构建产物,可以独立部署;pnpm workspace 只用于一致安装和根命令调度。
## 契约方向
```text
Server DTO + Controller metadata
│
▼
openapi.json
│
▼
Web generated client ──> Web adapter ──> Page model
Scheduler ──> Server message contract ──> Worker
```
HTTP 契约由 Server 单向发布,Web 不导入任何 Server TypeScript 源码。生成客户端只负责传输类型和请求,页面通过 adapter 转换为适合展示的模型,避免后端字段调整直接渗透整个界面。
Server 使用 `@nestjs/swagger` 从 DTO 和 Controller 元数据生成 `openapi.json`;Web 使用 `openapi-typescript` 生成类型,并由 `openapi-fetch` 提供轻量请求客户端。生成过程固定输入与输出路径,检查命令重新生成后要求 Git 无差异,从而发现契约漂移。
RocketMQ 消息契约属于 Server 的进程间协议,只由 Scheduler 与 Worker 使用。数据库实体不会作为 HTTP DTO 或消息载荷直接暴露,避免持久化结构成为跨边界契约。
## Server 进程边界
- API 读取 API、Redis、MySQL 和可选 AI 配置,提供 HTTP 与 OpenAPI。
- Scheduler 读取调度、Redis 和可选 RocketMQ 发送配置,只负责触发任务。
- Worker 读取数据源、Redis、MySQL、可选 RocketMQ 消费和可选 AI 配置,负责执行任务。
- 三个入口复用配置解析和基础设施 adapter,但分别建立 Nest 应用上下文,互不隐式启动。
初始版本的 RocketMQ adapter 只定义接口和明确的 disabled 行为。项目不会选择名称可疑、维护状态不明或不兼容 RocketMQ 5.x Proxy 的 npm 包;真实收发将在客户端验证功能中通过测试 Topic 完成后启用。
## 配置加载
本地启动固定读取 `deploy/env/development/<process>.env.local`;生产运行只依靠 systemd `EnvironmentFile` 注入,不从源码目录寻找生产 env。配置解析采用白名单 Schema,未知键可以保留给其他进程,但当前进程只解析最小集合。
敏感值只用于建立连接,错误对象和日志使用键名而不输出实际值。Web 构建只加载 `web.env.local` 中的 `VITE_` 变量。
## 数据库基线
Schema 工具优先读取 `api.env.local`,不存在时才退回 `api.env.example`。开发数据库主机允许回环地址和代码内固定白名单 `112.192.20.11`,不能由命令行临时追加。其余环境、库名、版本、字符集和排序规则继续严格校验。
当前远程开发库为空。空库仍然是“已启用且已检查”的事实,不应标记为 MySQL 未启用。生成器将保存 format v2 的 `captured_empty` 结构化清单,其中 `object_counts` 全部为零、客户端和服务端版本真实可验证,并对规范化的空结构计算确定性摘要;不创建空 `schema.sql`。验证器继续只读兼容既有 format v1 清单,禁止借格式升级重写历史目录。首次迁移产生对象后,下一发布版本开始生成完整 captured 基线。
Server 数据访问使用 Nest 官方 `@nestjs/typeorm` 集成、TypeORM 和 `mysql2` 驱动。迁移是结构变更的唯一入口,应用启动禁止 `synchronize: true`;Repository 只能通过领域端口进入业务逻辑,不能把 TypeORM 实体直接暴露为 HTTP 或消息契约。
## 错误处理
- Node/pnpm 版本错误在安装或根校验命令开始时失败。
- 必填配置缺失、MySQL 版本错误或字符规则错误时,相应 Server 进程拒绝启动。
- Redis/MySQL 健康检查失败返回不可用状态,但不泄漏目标密码。
- RocketMQ 关闭时报告 disabled;打开但无已验证 adapter 时启动失败,禁止静默退回内存队列。
- OpenAPI 生成文件与 Server 定义不一致时 CI/本地检查失败。
## 测试策略
- 配置 Schema、消息信封、Schema 主机白名单和空库产物使用 Node/Vitest 单元测试。
- API 使用 Nest 测试工具验证健康检查和 OpenAPI。
- Web 使用 Vitest 验证启动外壳和生成客户端边界。
- Playwright 验证 Web 能启动、路由可访问且无阻断错误;GOV-009 不进行业务页面视觉设计。
- 使用真实 Redis 和固定开发 MySQL 执行只读冒烟;RocketMQ 只验证禁用态和既有管理链路,不宣称 Node 消息收发通过。
- Web 与三个 Server 入口执行真实构建验证;源码发布门禁同时核对 systemd 和 Nginx 模板。
- E2E 在启动 API 前只读检查现有本机 Redis;不可达时明确失败,不启动替代基础设施。
## 安全策略与评估
- 配置按 API、Scheduler、Worker 最小权限拆分,生产只由 systemd `EnvironmentFile` 注入;Web 只允许公开的 `VITE_` 变量进入构建产物。
- Schema 工具硬编码开发环境、固定库名和主机白名单,密码只通过子进程环境传递;本功能禁止连接、探测或读取生产数据库。
- Redis/MySQL 健康检查和启动错误只返回脱敏状态;RocketMQ 未验证时明确禁用,不以进程内队列伪降级。
- OpenAPI 契约、Web/Server 源码边界和消息契约隔离由自动门禁验证。残余风险是 RocketMQ Node 客户端和真实行情数据源尚未接入,必须在各自功能中重新做依赖与安全评估。
## 性能目标与评估
- 脚手架目标是保持 Web 和三个 Server 进程可独立构建、启动和扩容;根 workspace 只编排质量命令,不进入生产运行时。
- 健康检查只执行有限的 Redis/MySQL 只读操作,禁止自动重试风暴;Scheduler 与 Worker 采用独立进程,避免任务执行阻塞 HTTP API。
- OpenAPI 和边界扫描只在开发、测试和发布阶段运行,不增加线上请求路径开销。当前尚无行情吞吐、数据库查询或消息积压业务,因此不伪造业务性能指标;后续功能必须按刷新周期、数据量和延迟重新设定基线。
## 回退原则
GOV-009 不迁移业务数据。回退时恢复上一 Git 标签即可移除脚手架;本地 `*.env.local` 和基础设施数据不随 Git 回退。若 Schema 工具变化失败,恢复旧工具后仍保留已发布基线,禁止改写历史目录。
## 实施后架构论证门禁
本文档描述的是实施前目标架构。完成代码、测试、构建和 Review 后,必须根据 GitNexus 实际依赖图、Web/Server 目录、三个 Server 进程、OpenAPI 生成链路和源码部署产物另写 `architecture-review.md`。复核需要说明实际实现与目标的偏差、当前选择优于替代方案的理由、何时应拆分或调整。用户再次确认前不发布 `v0.0.8`,也不把本功能视为彻底完成。
@@ -0,0 +1,56 @@
# GOV-009 应用工程脚手架基线开发总结
- 功能编号:GOV-009
- 发布版本:`v0.0.8`
- 架构确认日期:2026-08-17
## 原始开发需求
用户要求先搭建可支持 A 股市场概览业务的前后端基础:前端采用 Vue 3 与 Dart Sass,后端以独立 NestJS 工程维护,MySQL 固定 5.7、`utf8mb4_general_ci` 与东八区,Redis 作为缓存,RocketMQ 负责异步任务,API、Scheduler、Worker 分进程运行。工程需要开发/生产配置隔离、源码部署、OpenAPI 契约、完整治理留痕,并在全部实施后基于真实结构再次向用户论证。
## 需求与范围变化
- 消息队列从早期 RabbitMQ 方案调整为 RocketMQ 5.x,业务只依赖 `MessageBusAdapter`,未验证 Node 客户端前保持明确禁用。
- 部署从“Docker Compose 与源码并存”逐步收敛为“只支持 Ubuntu 源码部署”,Dockerfile、Compose、镜像门禁和容器兜底全部移除;历史验证事实不改写。
- 前后端不建立根共享 TypeScript 契约包。Server DTO 生成 OpenAPI,Web 生成自己的类型;RocketMQ 消息契约只属于 Server。
- 用户体系、会员订阅、市场概览 UI、行情采集和 AI Provider 均不属于本功能范围,后续以独立功能档案实施。
## 实际完成需求
| 范围 | 状态 | 实际结果 |
|---|---|---|
| Web 工程 | 已完成 | 建立 Vue 3、Vite、Pinia、Vue Router、Element Plus、Dart Sass、Vitest 与 Playwright 基线。 |
| Server 工程 | 已完成 | 建立 NestJS API、Scheduler、Worker 三入口及独立配置、生命周期和构建产物。 |
| 契约边界 | 已完成 | Server DTO → OpenAPI → Web 类型单向生成;Web/Server 源码越界和契约漂移由自动门禁阻断。 |
| 基础设施边界 | 已完成 | 固定 MySQL 5.7.42、Redis 只读健康检查、RocketMQ Adapter/消息信封和禁用语义,不自动管理外部服务。 |
| 环境与部署 | 已完成 | 开发/生产模板按进程最小权限拆分,生产仅支持 Ubuntu、systemd、Nginx 的源码部署。 |
| 质量治理 | 已完成 | 建立运行时、Schema、契约、边界、部署、测试、构建、视觉与 GitNexus 验证链路。 |
| 架构复核 | 已完成 | 依据真实目录和运行入口完成论证,用户于 2026-08-17 确认当前架构基线。 |
## 修复缺陷
实施与 Review 阶段修复了配置注入和三进程生命周期、未跟踪生成契约绕过、Vue 外部脚本越界、Vite 运行时模板警告、源码门禁 Docker 路径绕过、systemd 单元安装名称错误以及 Redis 测试兜底改变外部服务所有权等问题。所有处置均保留在实施计划、QA 和两份 Review 中;当前无未关闭的 Critical 或 Important 问题。
## 未完成与延期项
- 市场概览、短线/中长线模式、行情图表、规则/AI/混合/对照分析尚未实现,归入业务功能开发。
- TDX 常驻采集代理与 RocketMQ Node 客户端尚未落地;当前仅保留接口边界、禁用 Adapter、Tailscale 操作文档和 PoC 前置档案。
- 用户、邀请制、权限、会员和订阅按用户决定后置,不预埋业务实现。
- 完成市场概览真实业务后,需要依据模块依赖、负载与维护成本再次进行架构复核;当前确认不等于永久冻结。
## 关键提交
| 阶段 | 代表提交 | 说明 |
|---|---|---|
| 工程与契约基线 | `b3d8e29` 至 `95b8611` | Schema、workspace、Web、Server 三进程、OpenAPI、边界与 Review 整改。 |
| 仅源码部署 | `cfcd7f1` 至 `c756654` | 确认设计、移除 Docker、修复发布门禁并完成复审。 |
| GitNexus 封存 | `bbda26f` | 更新 GOV-009 最终索引统计。 |
上述提交均使用包含 GOV-009 的中文 Conventional Commit 并已推送项目专用 Gitea。发布封存提交和 `v0.0.8` 标签在本次收尾中分别推送并核对。
## 验证证据
- `qa/test-results.md` 保存运行时、治理、MySQL 5.7、环境、Schema、契约、边界、部署、Web、Server、构建、Playwright、安全扫描和格式证据。
- `qa/visual-qa.md` 与 `screenshots/iterations/` 保存桌面和移动应用外壳证据;GOV-009 不评价尚未实现的市场概览视觉质量。
- `gitnexus/before.md`、`impact-plan.md`、`detected-changes.md`、`after.md` 和 `comparison.md` 保存开发前后影响与实际执行流对比。
- 两份 Review 最终结论均为 `passed`;当前版本没有业务迁移,不访问生产数据库,不创建 RocketMQ Topic,也不写入 Redis 或 MySQL 业务数据。
@@ -0,0 +1,19 @@
# GitNexus 开发后基线
- 记录时间:2026-08-13 GMT+8
- 分支:`main`
- 仅源码实现提交:`47d0e0d248eb9b21cbd12f1625d3bd0e9c266dc9`
- 远端:`origin/main` 已核对为同一 SHA;最终 Review 证据提交将在验证后同步
```text
Repository: a-share-analysis
Indexed commit: 47d0e0d
Current commit: 47d0e0d
Status: up-to-date
Nodes: 1606
Relationships: 2253
Clusters: 48
Execution flows: 50
```
图谱已包含 Web、API、Scheduler、Worker、配置加载、健康检查、OpenAPI、消息信封、Schema、外部 Redis 预检、源码产物/systemd/Nginx 发布验证和治理门禁。旧 Docker 验证符号已删除,GitNexus 本地索引未提交仓库。
@@ -0,0 +1,26 @@
# GitNexus 开发前基线
- 功能编号:GOV-009
- 记录时间:2026年8月13日 GMT+8 15:14:35
- 分支:main
- 基线提交:c04184a6111d
## 工作区
```text
(干净)
```
## GitNexus 状态
```text
Repository: /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis
Indexed: 8/13/2026, 3:14:35 PM
Indexed commit: c04184a
Current commit: c04184a
Status: ✅ up-to-date
```
## 后续人工分析
在修改代码前,将 GitNexus query、context、impact 的结论写入 `gitnexus/impact-plan.md`。高风险结果必须先获得用户确认。
@@ -0,0 +1,31 @@
# GitNexus 前后对比
| 项目 | 开发前 `c04184a6` | 开发后 `95b8611` | 变化 |
| --- | ---: | ---: | ---: |
| 符号 | 958 | 1568 | +610 |
| 关系 | 1141 | 2190 | +1049 |
| 执行流程 | 23 | 47 | +24 |
开发前仓库以治理文档、环境模板和 Schema 工具为主,Web/Server 仍无可运行应用。开发后形成以下新边界:
- Vue 3 Web 可启动、测试、构建,并通过生成的 OpenAPI 类型访问 API。
- NestJS API、Scheduler、Worker 为独立入口和独立配置容器。
- Scheduler/Worker 具备可验证的持续运行与 SIGTERM 优雅关闭生命周期。
- HTTP 契约由 Server DTO 单向发布;RocketMQ 消息信封只存在于 Server。
- Docker Compose 与 Ubuntu 源码部署共用同一配置语义和构建产物。
- Schema 空库、MySQL 5.7.42、契约漂移和 `.vue` 工程边界均有自动门禁。
新增关系数量符合“从占位目录建立应用基线”的预期。后续市场概览功能应在这些边界内增加业务模块,不应把 Web 与 Server 重新耦合。
## 仅源码部署调整对比
| 项目 | 调整设计提交 `cfcd7f1` | 实现与 Review 后 | 变化 |
| --- | ---: | ---: | ---: |
| 符号 | 1589 | 1606 | +17 |
| 关系 | 2211 | 2253 | +42 |
| 执行流程 | 47 | 50 | +3 |
- 删除 Docker 构建、镜像引用和容器生命周期校验符号,新增源码发布校验流程。
- 新增 `checkLocalRedis` 与 `runTestApi`,Playwright 只依赖现有本机 Redis,不拥有基础设施生命周期。
- `verifySourceDeployment` 校验 Web、API、Scheduler、Worker 产物以及 systemd/Nginx;递归阻断任意活动 Dockerfile、`.dockerignore` 和 Compose YAML。
- GitNexus compare 检测风险为 MEDIUM,98 个变更符号、3 个受影响符号,影响集中在部署门禁与 E2E 启动链;未影响业务 API、市场模块、生产数据库或 RocketMQ 消息发送。
@@ -0,0 +1,34 @@
# GitNexus 变更检测
- 对比基线:`c04184a6111da0cfad90d1a265dc3cd3a6d90a9c`
- 实现提交:`95b8611bd9bbc282193591e472e2e19c617e5035`
- 检测命令:`npx gitnexus detect-changes --scope compare --base-ref c04184a6 --repo a-share-analysis`
- 变更范围:110 个文件、452 个符号、45 条执行流程
- 风险:CRITICAL
CRITICAL 来自一次建立完整 Web、API、Scheduler、Worker、契约生成、Schema 和部署验证链路,而不是单个未受控函数。主要流程为三进程配置加载、Schema 生成/验证、OpenAPI 发布、Web 客户端边界和 Docker/源码部署。
Review 整改前对具体符号分别执行上游影响分析:三进程 bootstrap、动态模块、消息信封、空库捕获和 MySQL 健康检查大多为 LOW;`assertMysql57Metadata` 因位于 Schema 发布门禁核心为 CRITICAL。该变更只把服务端补丁版本固定到 5.7.42,历史 `v0.0.7` 清单回归和 `schema:verify` 均通过。
最终代码复审补充发现无引号 Vue 外部 `script src` 可绕过早期正则门禁;影响分析为 LOW,只有 1 个直接调用者和 1 条边界检查流程。`95b8611` 改用 Vue 3.5.41 官方 SFC 解析器,并以单双引号、无引号和属性换序用例验证,未扩大应用运行影响面。
检测范围与开发前影响计划一致,未出现用户体系、生产数据库、外部消息写入或其他项目流程。
## 仅源码部署调整
- 对比基线:`cfcd7f13d9a6a35173d01bd8ca1458911190e70f`
- 实现提交:`47d0e0d248eb9b21cbd12f1625d3bd0e9c266dc9`
- 变更范围:27 个已索引文件、98 个变更符号、3 个受影响符号
- 风险:MEDIUM
开发前对 `assertImmutableImageReferences`、旧 Docker 辅助函数和 `forwardSignal` 的上游影响均为 LOW,0 条业务执行流受影响。最终 compare 的 MEDIUM 来自部署门禁整体替换:旧 Docker 验证删除,源码发布与 Redis 预检新增,并非应用业务依赖扩散。
Review 中 `verifySourceDeployment` 和 `assertDockerArtifactsAbsent` 的影响分析均为 LOW;后者只影响 1 条源码部署校验流程。递归活动资产扫描与 systemd 正式目标名测试完成后,部署 6/6、环境 10/10 和完整 `verify:release` 通过。
## v0.0.8 发布封存检测
- 检测日期:2026-08-17
- 检测命令:`npx gitnexus detect-changes --repo a-share-analysis`
- 结果:22 个已索引文档/版本文件、55 个文档符号、0 条受影响执行流,风险 LOW。
本次变化只封存用户确认、版本状态、独立开发总结、安全/性能证据和 Review,不修改运行时代码。逐项核对确认 HTTP/OpenAPI、Web API、消息、数据库、Redis、API、Scheduler、Worker 与源码部署无需代码同步;CHANGELOG、manifest、发布说明和回退说明已同步。
@@ -0,0 +1,63 @@
# GitNexus 开发前影响分析
- 功能编号:GOV-009
- 基线提交:`c04184a6111da0cfad90d1a265dc3cd3a6d90a9c`
- 分析日期:2026-08-13
## 查询范围
本功能会新增 Web、Server 和构建入口;这些文件在基线图谱中尚无符号,无法产生既有调用方。对已有代码的修改集中在 `tools/database/schema-baseline.mjs`、根工程编排、环境模板和部署配置,因此对 Schema 关键符号执行上游影响分析,并查询现有 Vue/NestJS 执行流。
## 结果
### `assertSafeDevelopmentConfiguration`
- 风险:**CRITICAL**。
- 直接影响:4 个调用方。
- 间接影响:9 个符号、5 组执行流程。
- 直接调用方:`buildMysqldumpArguments`、`runBaselineGeneration`、`assertNotApplicableMatchesDevelopmentConfiguration` 和 Schema 测试。
- 关键下游:`assertCurrentReleasedBaseline`、`assertCurrentReleasedBaselinePublished`、`runCommandLine` 与 `governance:start`。
### `resolveFixedDevelopmentEnv`
- 风险:**HIGH**。
- 直接影响:2 个调用方。
- 间接影响:7 个符号、3 组执行流程。
- 关键下游:Schema 生成、当前发布基线校验和下一功能开发前门禁。
### `buildCapturedArtifacts`
- 风险:LOW。
- 直接影响:Schema 测试;现有运行流程没有额外上游调用。
### 新增工程
GitNexus 查询未找到 Vue、NestJS、API、Scheduler 或 Worker 的既有运行符号,证明当前只有文档和治理工具。新增工程不会破坏已有应用调用方,但会建立新的构建、配置、HTTP 和进程启动流程,开发后必须重新索引并逐项核对。
## 直接与间接影响
- `assertSafeDevelopmentConfiguration` 为 CRITICAL:4 个直接调用方、9 个间接符号和 5 组流程,影响 Schema 生成、已发布基线校验与 `governance:start`。
- `resolveFixedDevelopmentEnv` 为 HIGH:2 个直接调用方、7 个间接符号和 3 组流程,影响开发配置解析和当前发布基线验证。
- 新增 Web、API、Scheduler、Worker 在开发前没有既有调用方,但会新增构建、启动、OpenAPI、生命周期和部署流程;开发后必须用 detect-changes 与 compare 核对实际边界。
## 跨模块同步修改
- HTTP/OpenAPI:新增 Server DTO、OpenAPI 输出、Web 生成类型和漂移门禁;Web 不直接依赖 Server 源码。
- Web API:建立生成契约与 adapter 边界;后续 GOV-010 再统一为 Axios request 与业务域 API。
- 消息:建立 RocketMQ 信封和禁用 Adapter,不创建 Topic 或启用真实收发。
- 数据库与 Redis:同步 MySQL 5.7.42、字符规则、开发 Schema 安全边界和只读健康检查,不实施业务迁移或缓存写入。
- API/Scheduler/Worker:同步三进程入口、最小配置、持续运行和优雅退出验证。
- 部署、测试与文档:同步环境模板、systemd/Nginx、源码发布门禁、Playwright、Review、回退和架构复核;早期 Docker 方案后来由仅源码部署设计取代。
## 风险控制
1. Schema 变更先写失败测试,覆盖固定远程白名单、未知远程拒绝、`api.env.local` 优先级、历史 N/A 基线验证和空库 captured 状态。
2. 已发布的 `v0.0.7` N/A 清单保持不可变;配置启用不得静默重写历史。GOV-009 不创建数据库对象,`v0.0.8` 发布后、下一功能开始前首次捕获空库或真实结构。
3. `governance:start` 的严格远程分支、标签和已提交基线校验必须继续通过现有测试。
4. Schema 密码只通过子进程环境传递;固定白名单写在代码中,不接受命令参数、动态 env 白名单或通配地址。
5. 新增 Server 进程分别测试配置最小权限、启动和关闭;Web 通过边界测试禁止导入 Server 源码。
6. 每个阶段运行全量 Schema 与治理回归;提交前运行 GitNexus `detect_changes`,若风险超出本报告则停止并重新确认。
## 回退
Schema 阶段可以独立回退到 GOV-009 开始提交,已发布基线目录不变。应用脚手架不执行业务迁移,回退对应提交即可移除 Web/Server 构建产物;本地 `*.env.local`、Redis 数据和远程开发库不随 Git 操作修改。
@@ -0,0 +1,643 @@
# GOV-009 应用工程脚手架基线实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 建立可启动、测试、构建和独立部署的 Vue 3 Web 与 NestJS API/Scheduler/Worker 工程,并修正开发 Schema 的本地配置、固定远程白名单和空库基线能力。
**Architecture:** 根 pnpm workspace 只编排 `web` 与 `server`。HTTP 契约由 Server 的 DTO 和 OpenAPI 单向发布,Web 生成自己的客户端;RocketMQ 消息契约只在 Server 内共享。Schema 安全门禁继续固定开发环境与数据库,只增加代码内固定远程主机和 `captured_empty` 状态。
**Tech Stack:** Node.js 22.x、pnpm 10.25.0、TypeScript 5.9.3、Vue 3.5.41、Vite 6.4.3、Naive UI 2.44.1、Dart Sass 1.102.0、Vitest 3.2.7、Playwright 1.62.1、NestJS 11.1.29、TypeORM 0.3.31、mysql2 3.23.3、ioredis 5.11.1、MySQL 5.7、Redis、RocketMQ 5.x。
## Global Constraints
- 本机当前 Node.js 是 `20.20.2`,不得用于正式安装或验收;源码运行前由开发机提供 Node 22,项目不安装 Node。实施期间可使用 `node:22.22.0-bookworm-slim` 执行安装、测试和构建。
- pnpm 固定 `10.25.0`,根 `package.json` 写入精确 `packageManager`,依赖提交精确版本及 `pnpm-lock.yaml`,禁止 `latest`。
- 所有关键业务边界、配置安全、异常恢复和架构取舍使用准确中文注释,不做逐行翻译式注释。
- Web 不得导入 `server/`;RocketMQ 消息契约不得进入 Web;数据库实体不得作为 HTTP DTO。
- MySQL 只允许 5.7.x、`a_share_analysis_dev`、`utf8mb4`、`utf8mb4_general_ci` 和 `+08:00` 会话时区,禁止 `synchronize: true`。
- Schema 只读取开发配置,只允许回环地址或固定白名单 `112.192.20.11`,不得接触生产环境。
- RocketMQ 在 GOV-009 中保持默认关闭;打开但没有已验证客户端时必须失败,不提供内存队列伪降级。
- 每个行为遵循 RED-GREEN-REFACTOR:先运行并确认测试因行为缺失而失败,再写最小实现;测试断言真实结果,不断言 Mock 自身。
- 每个提交使用中文 Conventional Commit 并带 `GOV-009`,验证后立即精确推送当前分支到 Gitea。
---
### Task 1: 修正 Schema 开发配置与空库基线
**Files:**
- Modify: `tools/database/schema-baseline.mjs`
- Modify: `tools/database/schema-baseline.test.mjs`
- Modify: `docs/governance/development-workflow.md`
- Modify: `docs/governance/code-development-standards.md`
- Modify: `docs/deployment/local-development.md`
**Interfaces:**
- Produces: `resolveFixedDevelopmentEnv(repositoryRoot): string`,优先返回 `deploy/env/development/api.env.local`,缺失时退回模板。
- Produces: `assertSafeDevelopmentConfiguration(config): Readonly<SchemaConfig>`,只接受回环地址或 `112.192.20.11`。
- Produces: `buildCapturedEmptyArtifacts(metadata): BaselineArtifacts`,状态为 `captured_empty`、format v2,只保存结构化清单、`object_counts` 和空结构 SHA-256,不创建 `schema.sql`。
- Preserves: `assertCurrentReleasedBaselinePublished(repositoryRoot)` 的已提交、已推送和远程标签严格门禁。
- [ ] **Step 1: 写入配置路径和主机白名单失败测试**
在 `schema-baseline.test.mjs` 增加行为测试:临时目录同时存在 `api.env.local` 与模板时必须选择 local;`112.192.20.11` 被接受;`112.192.20.12`、域名和空主机被拒绝。期望值直接使用固定路径和错误类型,不复用实现常量。
```js
assert.equal(
resolveFixedDevelopmentEnv(repositoryRoot),
path.join(repositoryRoot, 'deploy/env/development/api.env.local'),
);
assert.doesNotThrow(() =>
assertSafeDevelopmentConfiguration({
...validConfig,
MYSQL_HOST: '112.192.20.11',
}),
);
assert.throws(
() => assertSafeDevelopmentConfiguration({ ...validConfig, MYSQL_HOST: '112.192.20.12' }),
/固定开发数据库主机白名单/,
);
```
- [ ] **Step 2: 运行测试并确认 RED**
Run: `node --test --test-name-pattern='配置路径|远程开发库白名单' tools/database/schema-baseline.test.mjs`
Expected: FAIL,原因分别为 `api.env.local` 未被选择、固定远程地址仍被拒绝。
- [ ] **Step 3: 实现固定配置解析与白名单**
在代码内使用不可变集合,不读取动态白名单变量:
```js
const DEVELOPMENT_HOSTS = new Set(['127.0.0.1', 'localhost', '::1', '112.192.20.11']);
export function resolveFixedDevelopmentEnv(repositoryRoot) {
const localEnv = path.join(repositoryRoot, 'deploy', 'env', 'development', 'api.env.local');
if (existsSync(localEnv)) return localEnv;
return path.join(repositoryRoot, 'deploy', 'env', 'development', 'api.env.example');
}
```
错误文案只输出主机,不输出用户名或密码。导出 `resolveFixedDevelopmentEnv` 供真实行为测试调用。
- [ ] **Step 4: 写入空库 captured 失败测试**
模拟 metadata 查询返回合法 MySQL 5.7 元数据,`mysqldump` 返回空结构;断言结果为 `captured_empty`、format v2、文件集合只有 `manifest.yaml`、`object_counts` 全为零、摘要为 SHA-256 空串,且没有 `schema.sql`。另加 fixture 回归测试证明既有 format v1 的 `not_applicable` 与 captured 清单仍可验证,并且当前运行配置改变不会静默重写历史。
- [ ] **Step 5: 运行测试并确认 RED**
Run: `node --test --test-name-pattern='空库|历史不适用基线' tools/database/schema-baseline.test.mjs`
Expected: FAIL,现有实现以“真实 Schema SQL 不能为空”拒绝空库,并重新读取当前配置否定历史 N/A 清单。
- [ ] **Step 6: 实现 `captured_empty` 和不可变历史语义**
`buildCapturedArtifacts` 在规范化 SQL 为空时调用:
```js
export function buildCapturedEmptyArtifacts(metadata) {
assertMysql57Metadata(metadata);
return Object.freeze({
status: 'captured_empty',
files: Object.freeze({
'manifest.yaml': buildManifest({
...metadata,
status: 'captured_empty',
captured: false,
schemaSha256: sha256(''),
}),
}),
});
}
```
新生成的 format v2 Manifest 增加 `object_counts`,空库固定为零;普通 captured 从导出 SQL 解析并记录非负计数。既有 format v1 的 `objects` 布尔结构保持只读兼容,验证器按格式版本与状态校验精确文件集合。已发布 N/A 清单只验证生成事实,不在 `schema:verify` 阶段用当前 env 改写历史;下一版本生成时才读取当前 local 配置。
- [ ] **Step 7: 验证真实固定开发库**
先运行只读元数据查询确认目标仍为空,再使用项目支持的 MySQL 5.7 原生客户端或 Docker 客户端执行一次临时目录生成测试;不得覆盖 `database/schema-baselines/v0.0.7/`。
Expected: 服务端 `5.7.42`、数据库 `a_share_analysis_dev`、字符集 `utf8mb4`、排序规则 `utf8mb4_general_ci`、对象计数 0。
- [ ] **Step 8: 全量 Schema 回归、影响检测、提交和推送**
Run:
```bash
npm run test:schema-baseline
npm run schema:verify
npm run test:governance
git diff --check
```
Expected: 全部 PASS,`v0.0.7` 清单逐字节不变。运行 GitNexus `detect_changes`,风险只能落在本报告列出的 Schema/governance 流程。
Commit: `feat(GOV-009): 支持固定开发库结构基线`
Push: `git push origin "$(git branch --show-current)"`
---
### Task 2: 建立 Node 22 与 pnpm workspace 质量基线
**Files:**
- Modify: `package.json`
- Create: `pnpm-workspace.yaml`
- Create: `pnpm-lock.yaml`
- Create: `.npmrc`
- Create: `eslint.config.mjs`
- Create: `.prettierrc.json`
- Create: `tools/runtime/verify-runtime.mjs`
- Create: `tools/runtime/verify-runtime.test.mjs`
**Interfaces:**
- Produces: `assertSupportedRuntime({ nodeVersion, pnpmVersion })`。
- Produces root scripts: `check:runtime`, `lint`, `format:check`, `typecheck`, `test`, `build`, `verify`。
- [ ] **Step 1: 写运行时门禁失败测试**
覆盖 Node `22.0.0` 与 pnpm `10.25.0` 通过,Node 20/24、pnpm 9/11 拒绝;错误消息包含实际版本,不执行安装。
- [ ] **Step 2: 运行并确认 RED**
Run: `node --test tools/runtime/verify-runtime.test.mjs`
Expected: FAIL with `ERR_MODULE_NOT_FOUND`。
- [ ] **Step 3: 实现运行时门禁和 workspace**
```js
export function assertSupportedRuntime({ nodeVersion, pnpmVersion }) {
if (Number(nodeVersion.split('.')[0]) !== 22) {
throw new Error(`Node.js 必须为 22.x,实际 ${nodeVersion}`);
}
if (Number(pnpmVersion.split('.')[0]) !== 10) {
throw new Error(`pnpm 必须为 10.x,实际 ${pnpmVersion}`);
}
}
```
`pnpm-workspace.yaml` 只包含:
```yaml
packages:
- web
- server
```
根 `package.json` 写入 `engines.node: 22.x`、`packageManager: pnpm@10.25.0`,根脚本通过 `pnpm --filter` 编排两个工程,不创建业务依赖。
- [ ] **Step 4: 在 Node 22 容器安装精确依赖并生成锁文件**
Run: `docker run --rm --user "$(id -u):$(id -g)" -e COREPACK_HOME=/tmp/corepack -v "$PWD:/workspace" -w /workspace node:22.22.0-bookworm-slim sh -lc 'corepack pnpm install --lockfile-only'`
Expected: 生成单一 `pnpm-lock.yaml`,无 `latest`,宿主项目文件归当前用户可读写。
- [ ] **Step 5: 验证、提交和推送**
Run: Node 22 容器中的 `corepack pnpm check:runtime`、运行时单测、`git diff --check`。
Commit: `build(GOV-009): 建立 Node 与工作区基线`
Push current branch and verify local/remote SHA equality.
---
### Task 3: 建立 Vue 3 Web 工程
**Files:**
- Delete: `web/.gitkeep`
- Create: `web/package.json`
- Create: `web/tsconfig.json`
- Create: `web/tsconfig.node.json`
- Create: `web/vite.config.ts`
- Create: `web/vitest.config.ts`
- Create: `web/playwright.config.ts`
- Create: `web/index.html`
- Create: `web/src/main.ts`
- Create: `web/src/app/App.vue`
- Create: `web/src/app/router.ts`
- Create: `web/src/app/providers.ts`
- Create: `web/src/styles/index.scss`
- Create: `web/src/env.d.ts`
- Create: `web/src/app/App.test.ts`
- Create: `web/tests/smoke.spec.ts`
**Interfaces:**
- Produces: `createAppRouter()` 和 `installAppProviders(app)`。
- Consumes: only `VITE_APP_ENV`, `VITE_API_BASE_URL`, `VITE_APP_TITLE` from `web.env.local`。
- Preserves: FEAT-MO-001 将在 `src/features/market-overview/` 添加首屏,不需要重构应用入口。
- [ ] **Step 1: 写 Web 应用外壳失败测试**
使用真实 Pinia、Router 和 Naive UI provider 挂载 `App.vue`,断言应用标题和主内容区域可访问;禁止 mock 子组件。
- [ ] **Step 2: 运行并确认 RED**
Run: `pnpm --filter @a-share-analysis/web test --run`
Expected: FAIL,因为 Web 包和应用入口尚不存在。
- [ ] **Step 3: 创建精确依赖和最小应用外壳**
Web dependencies 精确锁定 Vue 3.5.41、Vue Router 4.6.4、Pinia 3.0.4、Naive UI 2.44.1;dev dependencies 锁定 Vite 6.4.3、plugin-vue 5.2.4、TypeScript 5.9.3、vue-tsc 3.3.9、Sass 1.102.0、Vitest 3.2.7、Vue Test Utils 2.4.11、jsdom 26.1.0、Playwright 1.62.1。该组合兼容开发机 Node 22.11;Vite 7 要求 Node 22.12+,不在本基线采用。
`main.ts` 固定从项目外部加载开发 env:
```ts
const app = createApp(App);
installAppProviders(app);
app.mount('#app');
```
Vite `envDir` 指向 `../deploy/env/development`,开发模式通过 `--mode web` 加载 `web.env.local`;生产构建只接受部署注入的 `VITE_` 值。样式仅建立字体、颜色 token、页面高度和可访问焦点基线,不提前设计市场概览。
- [ ] **Step 4: 运行单测、类型和构建**
Run:
```bash
pnpm --filter @a-share-analysis/web test --run
pnpm --filter @a-share-analysis/web typecheck
pnpm --filter @a-share-analysis/web build
```
Expected: PASS,`web/dist` 不包含 `MYSQL_`、`REDIS_`、`ROCKETMQ_`、密码或 Server 消息字段。
- [ ] **Step 5: 写 Playwright 冒烟测试并确认 RED/GREEN**
测试访问 `/`,验证 `main` 存在、无页面错误和水平溢出,视口覆盖 `1440x900` 与 `390x844`。先在未配置 webServer 时确认失败,再配置 Vite webServer 并通过。
- [ ] **Step 6: 提交和推送**
Commit: `feat(GOV-009): 建立 Vue 前端工程基线`
Push current branch and verify remote SHA.
---
### Task 4: 建立 NestJS 三进程与最小权限配置
**Files:**
- Delete: `server/.gitkeep`
- Create: `server/package.json`
- Create: `server/nest-cli.json`
- Create: `server/tsconfig.json`
- Create: `server/tsconfig.build.json`
- Create: `server/apps/api/src/main.ts`
- Create: `server/apps/api/src/api.module.ts`
- Create: `server/apps/scheduler/src/main.ts`
- Create: `server/apps/scheduler/src/scheduler.module.ts`
- Create: `server/apps/worker/src/main.ts`
- Create: `server/apps/worker/src/worker.module.ts`
- Create: `server/libs/config/src/runtime-config.ts`
- Create: `server/libs/config/src/runtime-config.test.ts`
- Create: `server/libs/config/src/load-process-env.ts`
- Create: `server/test/process-smoke.test.ts`
**Interfaces:**
- Produces: `loadApiConfig`, `loadSchedulerConfig`, `loadWorkerConfig`,返回冻结且不含未知字段的配置。
- Produces: `bootstrapApi`, `bootstrapScheduler`, `bootstrapWorker`,支持依赖注入端口和优雅关闭。
- Consumes: `deploy/env/development/<process>.env.local` only in development; production only consumes `process.env` injected by Compose/systemd.
- [ ] **Step 1: 写进程配置失败测试**
分别证明 API 不要求 Scheduler/Worker 变量、Scheduler 不读取 MySQL 密码、Worker 不要求 API 端口;MySQL 启用时缺少时区或密码失败;日志序列化不包含敏感值。
- [ ] **Step 2: 运行并确认 RED**
Run: `pnpm --filter @a-share-analysis/server test -- runtime-config.test.ts`
Expected: FAIL,因为配置模块不存在。
- [ ] **Step 3: 实现进程级配置**
使用纯函数解析、显式条件必填和对象冻结。公共字段保持在同一文件连续阅读,避免每个变量一个文件。MySQL 配置接口固定:
```ts
export interface MysqlRuntimeConfig {
enabled: boolean;
host: string;
port: number;
database: 'a_share_analysis_dev' | string;
username: string;
password: string;
charset: 'utf8mb4';
collation: 'utf8mb4_general_ci';
timezone: '+08:00';
}
```
生产配置不从仓库路径加载;开发入口根据自身 `import.meta.url` 定位唯一 local 文件,不接受用户传入 env 路径。
- [ ] **Step 4: 写三进程启动关闭失败测试**
测试调用三个 bootstrap 函数,使用真实 Nest application/context 和只在基础设施端口注入的轻量 fake;断言 API 监听给定端口,Scheduler/Worker 不打开 HTTP 端口,三者收到关闭信号后释放资源。
- [ ] **Step 5: 运行并确认 RED 后实现入口**
API 使用 `NestFactory.create`;Scheduler/Worker 使用 `NestFactory.createApplicationContext`。所有进程启用 shutdown hooks,启动日志只记录进程名、环境和非敏感端口。
- [ ] **Step 6: 验证构建产物路径**
Run:
```bash
pnpm --filter @a-share-analysis/server test
pnpm --filter @a-share-analysis/server typecheck
pnpm --filter @a-share-analysis/server build
test -f server/dist/apps/api/main.js
test -f server/dist/apps/scheduler/main.js
test -f server/dist/apps/worker/main.js
```
Expected: 与现有 systemd/Compose 命令完全一致。
- [ ] **Step 7: 提交和推送**
Commit: `feat(GOV-009): 建立 NestJS 三进程基线`
---
### Task 5: 建立后端契约、基础设施与 API 健康检查
**Files:**
- Create: `server/libs/http-contracts/src/health.dto.ts`
- Create: `server/libs/message-contracts/src/message-envelope.ts`
- Create: `server/libs/message-contracts/src/message-envelope.test.ts`
- Create: `server/libs/infrastructure/src/message-bus.adapter.ts`
- Create: `server/libs/infrastructure/src/disabled-message-bus.adapter.ts`
- Create: `server/libs/infrastructure/src/redis-health.client.ts`
- Create: `server/libs/infrastructure/src/mysql-health.client.ts`
- Create: `server/libs/infrastructure/src/typeorm-options.ts`
- Create: `server/apps/api/src/health.controller.ts`
- Create: `server/apps/api/src/health.service.ts`
- Create: `server/apps/api/test/health.e2e-spec.ts`
- Create: `server/tools/export-openapi.ts`
- Create: `server/openapi/openapi.json`
- Modify: `deploy/env/development/api.env.example`
- Modify: `deploy/env/development/worker.env.example`
- Modify: `deploy/env/production/api.env.example`
- Modify: `deploy/env/production/worker.env.example`
- Modify ignored local API/Worker env files to retain `MYSQL_TIMEZONE=+08:00` without staging them.
**Interfaces:**
- Produces: `GET /api/v1/health -> HealthResponseDto`。
- Produces: `MessageEnvelope<TPayload>` with `version`, `eventType`, `idempotencyKey`, `occurredAt`, `payload`。
- Produces: `MessageBusAdapter.publish/subscribe/close`,disabled adapter rejects publish/subscribe with a typed error。
- Produces: TypeORM options with `synchronize: false`, MySQL 5.7 charset/collation/timezone.
- [ ] **Step 1: 写消息契约与禁用 adapter 失败测试**
覆盖有效信封、缺失幂等键、非法时间、未知版本;disabled adapter 的发布/订阅必须拒绝且不缓存消息。
- [ ] **Step 2: RED 后实现 Server 内部契约**
```ts
export interface MessageEnvelope<TPayload> {
version: 1;
eventType: string;
idempotencyKey: string;
occurredAt: string;
payload: TPayload;
}
```
验证函数返回规范化冻结对象;Web 无路径别名能够解析此目录。
- [ ] **Step 3: 写健康检查 E2E 失败测试**
启动真实 Nest API,注入确定性的 Redis/MySQL health ports,调用 `/api/v1/health`,断言 HTTP 200、进程状态、Redis/MySQL 分项和 RocketMQ `disabled`;依赖失败时 HTTP 503 且错误体不包含凭据。
- [ ] **Step 4: RED 后实现只读健康客户端**
Redis 只执行 `PING`;MySQL 使用 `SELECT VERSION(), DATABASE(), @@character_set_database, @@collation_database, @@session.time_zone`,连接建立时设置 `+08:00`。TypeORM options 明确:
```ts
{
type: 'mysql',
connectorPackage: 'mysql2',
charset: 'utf8mb4',
timezone: '+08:00',
synchronize: false,
migrationsRun: false,
}
```
如果 TypeORM 实际类型不支持 `connectorPackage`,删除该字段并通过安装的 `mysql2` 驱动解析;不得用类型断言掩盖错误。
- [ ] **Step 5: 写 OpenAPI 导出失败测试并实现**
导出命令从真实 Controller/DTO 生成排序稳定的 `server/openapi/openapi.json`。测试解析 JSON,断言 `/api/v1/health` 与 `HealthResponseDto` 存在;再次生成后 `git diff --exit-code -- server/openapi/openapi.json` 必须通过。
- [ ] **Step 6: 更新环境模板并运行契约测试**
四份 MySQL 模板增加 `MYSQL_TIMEZONE=+08:00`,开发/生产同进程键集合继续一致,生产密码保持空值。
Run: Server tests, `npm run test:environment-baseline`, typecheck, OpenAPI drift check.
- [ ] **Step 7: 使用真实开发基础设施只读冒烟**
Redis DB 0/1/2 分别 PING;API/Worker MySQL 连接验证版本、库名、字符集、排序规则和时区。RocketMQ 只检查既有 NameServer/Broker/Proxy 管理链路,Node adapter 保持 disabled。
- [ ] **Step 8: 提交和推送**
Commit: `feat(GOV-009): 建立后端契约与健康检查`
---
### Task 6: 生成 Web OpenAPI 客户端并强制边界
**Files:**
- Create: `web/src/api/generated/schema.ts`
- Create: `web/src/api/client.ts`
- Create: `web/src/api/adapters/health.adapter.ts`
- Create: `web/src/api/adapters/health.adapter.test.ts`
- Create: `tools/boundaries/verify-project-boundaries.mjs`
- Create: `tools/boundaries/verify-project-boundaries.test.mjs`
- Modify: `web/package.json`
- Modify: root `package.json`
**Interfaces:**
- Consumes: `server/openapi/openapi.json` as the only cross-project contract artifact.
- Produces: `createApiClient(baseUrl)` using `openapi-fetch` and generated `paths` type.
- Produces: `toHealthViewModel(dto): HealthViewModel`,页面模型不暴露后端枚举细节。
- [ ] **Step 1: 写项目边界失败测试**
在临时 fixture 中创建 Web 对 `server/libs` 的 import 和消息字段,运行真实边界检查器并断言失败;合法的 `web/src/api/generated/schema.ts` 通过。检查器解析 TypeScript import/export specifier,不用简单 grep 代替模块边界。
- [ ] **Step 2: RED 后实现边界检查器**
检查 Web 源文件的静态 import、动态 import 和路径别名,拒绝解析到仓库 `server/`;检查生成 OpenAPI schema 不包含 `MessageEnvelope` 或 `message-contracts`。
- [ ] **Step 3: 生成 Web 客户端**
Run: `openapi-typescript ../server/openapi/openapi.json -o src/api/generated/schema.ts`
`client.ts` 只包装 base URL 和错误归一化;健康 adapter 使用手写页面模型和显式映射,不把生成 DTO 传入 Vue 组件。
- [ ] **Step 4: 写 adapter 失败测试并实现**
使用手写完整 DTO fixture,断言 healthy/degraded/unavailable 映射和未知依赖状态拒绝。先运行确认函数缺失失败,再实现最小映射。
- [ ] **Step 5: 运行边界、生成漂移、Web 测试和构建**
Run root `check:contracts` twice; second run must leave clean diff. Scan `web/dist` for Server env keys, message fields and secrets; expected no match.
- [ ] **Step 6: 提交和推送**
Commit: `feat(GOV-009): 建立前端 OpenAPI 客户端边界`
---
### Task 7: 对齐 Docker、Compose、systemd 与源码开发命令
**Files:**
- Create: `web/Dockerfile`
- Create: `web/nginx.conf`
- Create: `server/Dockerfile`
- Modify: `deploy/compose/production.yml.example`
- Modify: `deploy/nginx/a-share-analysis.conf.example`
- Modify: `deploy/systemd/a-share-api.service.example`
- Modify: `deploy/systemd/a-share-scheduler.service.example`
- Modify: `deploy/systemd/a-share-worker.service.example`
- Modify: `docs/deployment/local-development.md`
- Modify: `docs/deployment/docker-compose-production.md`
- Modify: `docs/deployment/ubuntu-source-production.md`
- Modify: `README.md`
- Modify: `tools/governance/environment-baseline.test.mjs`
**Interfaces:**
- Produces immutable Web image serving `/` and proxying `/api/` according to deployment contract.
- Produces one Server image with commands `dist/apps/api/main.js`, `dist/apps/scheduler/main.js`, `dist/apps/worker/main.js`.
- [ ] **Step 1: 扩展部署行为测试并确认 RED**
使用 `docker build` 和 `docker compose config` 作为真实行为测试;验证镜像入口文件存在、非 root 运行、生产 Compose 必填不可变镜像、systemd ExecStart 对应真实 dist 文件。不要只断言文档文本。
- [ ] **Step 2: 实现多阶段 Dockerfile**
Builder 使用固定 Node 22.22.0 与 pnpm 10.25.0;Server runtime 只复制生产依赖和 dist,使用非 root 用户;Web runtime 使用固定 Nginx 镜像并复制 dist。镜像层不得复制 `deploy/env/development/*.local`。
- [ ] **Step 3: 更新双部署说明**
本地命令明确 Node 22 前置、`pnpm install --frozen-lockfile`、四进程启动顺序和 env 路径;生产说明分别给出 Compose 与 Ubuntu/systemd 的构建、迁移、启动、健康检查和回退命令。不得记录真实开发密码或远程库账号。
- [ ] **Step 4: 构建并启动容器冒烟**
Build Web/Server images with local-only tags. 使用临时生产 env(无真实生产密钥)验证配置缺失会失败;使用开发只读配置只启动 API 健康检查,不启动 Scheduler/Worker 的 RocketMQ 消费。
- [ ] **Step 5: 提交和推送**
Commit: `build(GOV-009): 对齐应用部署与运行入口`
---
### Task 8: 完成全量验证、Review 与发布留痕
**Files:**
- Update: `docs/features/GOV-009-application-scaffold-baseline/manifest.yaml`
- Create: `docs/features/GOV-009-application-scaffold-baseline/gitnexus/detected-changes.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/gitnexus/after.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/gitnexus/comparison.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/qa/visual-qa.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/review/code-review.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/review/standards-review.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/release-notes.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/rollback.md`
- Create: `docs/features/GOV-009-application-scaffold-baseline/architecture-review.md`
- Modify: `VERSION`
- Modify: `CHANGELOG.md`
**Interfaces:**
- Produces: reproducible evidence for tests, builds, browser screenshots, GitNexus changes, reviews, release and rollback.
- [ ] **Step 1: 在固定 Node 22 环境运行完整验证**
Run root `pnpm verify`, all four governance suites, `schema:verify`, Web Playwright at desktop/mobile, both Docker builds, development and production Compose validation, secret scan and `git diff --check`.
Expected: zero failures and zero unexpected warnings. Save exact commands, versions and result counts in `qa/test-results.md`.
- [ ] **Step 2: 保存视觉证据**
启动 Web/API 本地服务,Playwright 保存 `1440x900` 与 `390x844` 截图;检查无空白画面、溢出、重叠和控制台错误。GOV-009 只验证应用外壳,不评价市场概览视觉质量。
- [ ] **Step 3: 执行 GitNexus 变更检测和结束门禁**
Run GitNexus `detect_changes`,核对新增 API、Scheduler、Worker、OpenAPI 和 Web 流程,记录与开发前 23 条流程的差异。运行 `npm run governance:finish -- GOV-009 application-scaffold-baseline`。
- [ ] **Step 4: 独立代码与规范 Review**
代码 Review 检查配置泄漏、MySQL 5.7、进程生命周期、契约方向、Docker 产物和真实测试。规范 Review 逐条核对中文注释、文件拆分、中文提交、GitNexus 和文档追溯。两份报告必须包含精确行:
```text
最终结论:passed
```
- [ ] **Step 5: 更新版本、发布说明和回退**
将版本提升到 `0.0.8`,说明工程能力而不声称市场概览已实现。回退说明不得删除远程数据库或 Redis 数据,只回退应用代码和镜像。
- [ ] **Step 6: 基于实际实现完成架构复核并向用户论证**
`architecture-review.md` 必须引用真实文件和 GitNexus 流程,说明 Web 分层、Server 三进程、HTTP 与消息契约方向、基础设施边界、部署产物、替代方案、已知限制和后续调整触发条件。将 manifest 保持 `reviewing` 和 `unreleased`,提交并推送复核材料,然后向用户展示论证;未获得用户再次确认时在此停止,不创建标签。
- [ ] **Step 7: 用户确认后执行最终提交、推送与标签**
Commit: `docs(GOV-009): 封存应用脚手架验证结果`
Push current branch, compare local and remote SHA, create annotated tag `v0.0.8`, then run `git push origin v0.0.8`。禁止 `--tags` 和任何 force 选项。
- [ ] **Step 8: 刷新 GitNexus 并确认干净状态**
Run `npx gitnexus status`; stale 时运行 analyze。最终要求工作区干净、`main` 与 `origin/main` 一致、远程 `v0.0.8^{}` 指向本地标签提交。
---
## 实际执行记录
### 已完成任务与远端提交
| Task | RED / GREEN 与验证摘要 | 提交 | 推送证据 |
| --- | --- | --- | --- |
| 1 Schema | 配置路径、固定远程白名单、历史 N/A 与空库用例先失败;实现后 Schema 27/27、治理 5/5、环境 7/7 | `b3d8e29` | 15:43:07 `origin/main update by push` |
| 2 Workspace | 运行时模块缺失先失败;Node 22/pnpm 10 门禁与 frozen install 后通过 | `258a2d2` | 15:54:08 推送 |
| 3 Web | App 缺失、模板 `import.meta.env` 与路由警告依次复现;Vitest、类型、构建、双视口 Playwright 后通过 | `28d5418`、`dcdf634` | 16:43:48、18:03:38 推送 |
| 4 三进程 | 配置条件与启动入口先失败;三个 Nest 入口和独立配置 Schema 后通过 | `3fc703d` | 16:59:12 推送 |
| 5 后端契约 | 消息、健康接口和 OpenAPI 先失败;Server 契约与只读客户端后通过 | `420aa22` | 17:26:53 推送 |
| 6 Web 契约 | Web 越界导入与 adapter 行为先失败;OpenAPI 生成客户端和边界门禁后通过 | `4665336` | 17:36:58 推送 |
| 7 部署 | Docker/systemd 产物断言先失败;双镜像、三入口和双部署文档后通过 | `c771a98` | 17:56:39 推送 |
| 8 Review 整改 | 生命周期、配置注入、消息字段、5.7.42、空库、SFC、漂移、代理与 Docker 集成均有 RED/GREEN;最终补齐未跟踪契约、Vue 官方 SFC 解析、镜像摘要和容器生命周期门禁;`pnpm verify` 通过,Docker 留存历史验证 | `3a8120a`、`cb550e3`、`95b8611` | 18:31:10、18:51:16、19:49:46 推送 |
上述推送时间来自项目级 `origin/main` reflog;所有阶段均在提交后 1–83 秒内推送。提交摘要全部为包含 `GOV-009` 的中文 Conventional Commit。
### 计划状态
- Task 1–7:已实现、验证、提交并推送;原始步骤复选框保留为开发前计划,不反向改写预期命令和 RED 描述。
- Task 8 Step 1–3、5:已完成全量验证、视觉证据、GitNexus 检测与发布/回退材料。
- Task 8 Step 4:代码 Review 追加发现无引号外部脚本绕过,已用 Vue 官方 SFC 解析器整改;代码 Review 与规范 Review 最终结论均为 `passed`。
- Task 8 Step 6:架构复核文档已生成并完成论证;用户于 2026-08-17 确认以仅源码部署后的实际架构作为业务开发基线。
- Task 8 Step 7:用户确认后进入发布封存;最终档案提交、`main` 推送及 `v0.0.8` 精确标签推送由本次收尾执行并记录。
- Task 8 Step 8:开发后图谱已在各实施阶段刷新;本次最终档案提交后再次刷新并核对本地、远端分支与标签。
### Docker 后续执行口径
用户于 2026-08-13 最终决定彻底移除 Docker 依赖,项目生产交付只支持 Ubuntu 源码部署。早期 Docker/Compose 验证记录作为当时真实事实保留在历史档案,但现行仓库已删除可执行 Docker 资产;后续发布统一执行 `pnpm verify:release` 的源码门禁。
@@ -0,0 +1,24 @@
id: GOV-009
name: 应用工程脚手架基线
slug: application-scaffold-baseline
status: released
owner: project
created_at: 2026-08-13
prd: prd.md
requirements: requirements.md
design: design.md
implementation_plan: implementation-plan.md
test_plan: test-plan.md
development_summary: development-summary.md
gitnexus_before: gitnexus/before.md
gitnexus_impact: gitnexus/impact-plan.md
gitnexus_after: gitnexus/after.md
gitnexus_comparison: gitnexus/comparison.md
code_review: review/code-review.md
standards_review: review/standards-review.md
release: v0.0.8
architecture_confirmation: 2026-08-17
completion_gate: 已完成基于实际前后端架构的论证并获得用户确认
architecture_review: architecture-review.md
source_only_deployment_design: source-only-deployment-design.md
source_only_deployment_implementation_plan: source-only-deployment-implementation-plan.md
@@ -0,0 +1,61 @@
# 应用工程脚手架基线 PRD
- 功能编号:GOV-009
- PRD 版本:0.1
- 状态:approved
- 日期:2026-08-13
## 问题
项目已经完成工程治理、部署配置、MySQL 5.7、Redis 和 RocketMQ 5.x 的架构基线,但 `web/` 与 `server/` 仍只有占位文件,尚不能启动、构建或承载市场概览功能。现有 Schema 工具也没有读取项目约定的 `*.env.local`,并只允许回环主机,无法对已经确认的固定远程开发库执行版本化结构备份。
## 目标
- 建立可独立开发和部署的 Vue 3 Web 与 NestJS Server 工程。
- Server 在同一工程内提供 API、Scheduler、Worker 三个独立进程入口。
- 建立统一的 Node.js 22 LTS、pnpm 10、TypeScript、检查、测试和构建入口。
- HTTP 契约由 Server 的 DTO 与 OpenAPI 定义,Web 使用生成客户端,不共享后端源码。
- RocketMQ 消息契约只在 Server 内由 Scheduler 与 Worker共享。
- 本地进程加载现有 `deploy/env/development/*.env.local`,同时保持真实配置不进入 Git。
- Schema 工具只允许读取固定开发配置,支持经过白名单批准的远程开发库。
- 为 FEAT-MO-001 提供能够直接开始页面开发的工程底座。
## 用户价值
开发者可以用明确命令安装依赖、启动 Web/API/Scheduler/Worker、运行测试和构建,并能在不复制接口类型、不泄漏密钥、不误触生产数据库的前提下持续开发市场分析功能。
## 范围
- 根 pnpm workspace 与统一版本约束。
- Vue 3、Vite、TypeScript、Vue Router、Pinia、Naive UI、Dart Sass、Vitest 和 Playwright 基础工程。
- NestJS API、Scheduler、Worker 多应用工程及共享后端库边界。
- Server 配置解析、条件必填和启动失败策略。
- API 健康检查、OpenAPI 产物与 Web 客户端生成链路。
- Redis 与 MySQL 开发连接健康检查;RocketMQ 保持配置可选和默认关闭。
- Ubuntu 源码部署所需 Web/Server 产物与 systemd、Nginx 命令对齐,Docker 能力由后续确认的仅源码决策移除。
- Schema 开发配置路径、固定远程开发库白名单及空库基线处理。
## 非目标
- 不实现市场概览页面和业务指标。
- 不实现正式行情采集、AI 分析或付费功能。
- 不实现用户、邀请、权限、会员或订阅。
- 不把 HTTP DTO、数据库实体或消息事件做成前后端共享源码包。
- 不实现未经验证的 RocketMQ Node SDK;本功能只建立 Adapter 边界、配置校验和禁用态启动能力。
- 不创建、删除或修改生产基础设施与生产数据。
- 不管理本地或生产 Redis、MySQL、RocketMQ 的生命周期,不提供容器兜底。
## 验收标准
- Node.js 非 22.x 时安装或校验入口明确失败,pnpm 主版本固定为 10。
- 根命令可以分别启动、测试和构建 Web、API、Scheduler、Worker。
- 三个 Server 进程共享配置和后端库,但拥有独立入口与最小配置读取范围。
- Web 不导入 `server/` 源码;前端 API 类型来自提交或构建生成的 OpenAPI 客户端。
- RocketMQ 事件类型不进入 Web 构建产物。
- API 健康检查能够报告进程状态,并分别区分 Redis、MySQL 和禁用的 RocketMQ。
- 开发配置从 `*.env.local` 加载,真实值继续被 Git 忽略,生产模板不获得开发地址或密码。
- Schema 工具只接受 `development`、`a_share_analysis_dev`、MySQL 5.7、`utf8mb4_general_ci` 和固定主机白名单;其他远程主机立即拒绝。
- 空开发库可以生成可验证的 captured Schema 基线,不用空 SQL 冒充结构,也不退回 `not_applicable`。
- 单元测试、契约测试、构建、开发启动冒烟和适用的浏览器验证全部通过。
- 仓库不存在活动 Dockerfile、Compose 或 Docker 专用门禁;`pnpm verify:release` 只执行源码发布检查。
- 全部实施完成后必须基于真实代码和部署产物提交《实施架构复核》,向用户论证前后端职责、依赖方向、进程边界、替代方案和演进成本;获得用户再次确认前,GOV-009 不得标记完成或创建发布标签。
@@ -0,0 +1,93 @@
# 测试结果
- 日期:2026-08-13
- 实现提交:`95b8611bd9bbc282193591e472e2e19c617e5035`
- 状态:passed
## 测试先行证据
- 三进程配置 Token 缺失、Scheduler/Worker 启动后自行退出:RED;动态模块注入和生命周期锚点实现后 GREEN。
- 消息信封缺少追溯字段、MySQL 接受 5.7.41、真实空库 dump 被误判:RED;完整信封、5.7.42 固定和对象计数判空后 GREEN。
- `.vue` 越界导入未被发现、Vite 无 `/api` 代理:RED;SFC 脚本扫描和同源代理后 GREEN。
- 契约漂移验证模块不存在:RED;生成后限定路径 Git diff 与 Git 跟踪门禁后 3/3 GREEN。
- Vue 外部 `script src`、可变镜像标签和干净 checkout 生命周期用例依次 RED;禁止外部脚本、摘要校验与公开生产 fixture 实现后 GREEN。
- Playwright 访问真实健康接口时代理连接拒绝:RED;同时启动测试 API 并复用可用本机 Redis 后 GREEN。
## 完整验证
`pnpm verify`:passed。
- 运行时:Node.js 22.11.0、pnpm 10.25.0。
- 治理:5/5。
- MySQL 架构规范:2/2。
- 环境与部署契约:11/11。
- Schema 基线:28/28;`v0.0.7 (not_applicable)` 验证通过。
- 生成契约漂移:3/3;OpenAPI 与 Web 生成类型同步,未跟踪生成物会阻断。
- 工程边界:8/8,包含 Vue SFC 内联脚本,以及外部脚本单双引号、无引号和属性换序越界用例。
- 生产镜像引用:5/5;拒绝空值、`latest`、普通 tag 和裸摘要。
- Web Vitest:8/8。
- Server Vitest:30/30,包含 API/Scheduler/Worker 与两个真实子进程生命周期用例。
- Web、API、Scheduler、Worker 生产构建:passed。
- Playwright:桌面/移动共 4/4;页面外壳与 Web → Vite → Nest API 健康链路均通过。
- `git diff --check`、ESLint、Prettier、TypeScript:passed。
`pnpm verify:docker`:passed。
该结果是 2026-08-13 已完成的历史交付验证。按用户随后决定,Docker 不再作为日常开发必跑项;核心功能完成后再决定是否保留 Docker 部署,并仅在最终交付阶段按需重跑。
- Web 与 Server 多阶段镜像真实构建成功。
- Server 镜像以 `node` 非 root 用户运行。
- API、Scheduler、Worker 三个镜像入口存在;Scheduler/Worker 均在容器内持续运行,并在 `SIGTERM` 后退出码为 0。
- 隔离容器内 Redis/API/Web 启动,API 健康 200、Web 首页和 Nginx `/api` 代理通过。
- 临时容器、网络和验证镜像已清理。
## 本机与固定开发基础设施
- 本机 Redis `127.0.0.1:6379` 的 DB 0、1、2 分别执行只读 `PING`,三次均返回 `PONG`;未读取或修改业务键。
- 固定开发 MySQL 只读会话返回 `5.7.42-0ubuntu0.18.04.1`、库 `a_share_analysis_dev`、`utf8mb4`、`utf8mb4_general_ci`、会话时区 `+08:00`;Task 1 对象计数为 0。密码只通过临时进程环境传递,未输出或写入命令参数;未连接、探测或读取生产数据库。
- 本机 RocketMQ 只读 TCP 可达性复核:NameServer `127.0.0.1:9876`、Broker `127.0.0.1:10911`、Proxy `127.0.0.1:8081` 均可达。Node Adapter 仍保持禁用,没有创建 Topic、消费或发送消息。
## 仅源码部署调整(2026-08-13)
### RED
- `pnpm test:deployment` 因 `verify-source-deployment.mjs` 尚不存在而失败,证明新测试先于源码发布门禁实现。
- `pnpm test:environment-baseline` 因 Docker 活动文件和本地 Compose 指令仍存在而失败,证明政策测试能捕获待移除能力。
- `node --test server/tools/run-test-api.test.mjs` 因 `checkLocalRedis` 尚未导出而失败,证明外部 Redis 预检行为先有测试。
### GREEN
- 源码部署夹具:初始 5/5;最终 Review 加入任意新 Dockerfile/Compose 路径回归后为 6/6。
- 环境与部署契约:10/10;活动 Docker 入口不存在,本地外部 Redis和唯一 Ubuntu 源码部署规则通过。
- Redis 预检:2/2;OS 分配的本机 TCP 端口分别验证可达和不可达,不安装或启动外部服务。
- 本机 `redis-cli -h 127.0.0.1 -p 6379 ping` 返回 `PONG`。
- Server 原有 30 项 Vitest 与新增 2 项 Node 测试全部通过。
- Playwright 桌面与移动视口共 4/4,通过真实本机 Redis、API 健康接口和 Web 同源代理链路。
前述 `pnpm verify:docker` 及镜像验证内容是调整前的真实历史证据。2026-08-13 用户确认仅源码部署后,这些能力已被取代并从活动仓库删除,不再执行或作为发布依据。
### 最终源码发布验证
`pnpm verify:release`:passed。
- Node.js 22.11.0、pnpm 10.25.0 运行时检查通过。
- 环境 10/10、Schema 28/28、契约 3/3、工程边界 8/8、源码部署 6/6。
- Web 8/8;Server Vitest 30/30,Redis 预检 Node 测试 2/2。
- Web、API、Scheduler、Worker 生产构建通过。
- Playwright 桌面/移动共 4/4,通过现有本机 Redis 和真实 API 健康链路。
- `verify:source` 确认四类产物、三份 systemd 单元与 Nginx 配置一致;未调用 Docker。
应用内浏览器补充验证 1440×900 与 390×844:两种视口页面均非空,页面宽度等于视口宽度,无横向溢出、文字重叠或控制台 warning/error;DOM 中导航与“应用就绪”区域完整。
最终 Review 发现并修复两项 Important:systemd 模板曾以 `.service.example` 目标名安装,任意新路径的 Dockerfile/Compose 文件曾可绕过固定清单。两项均先增加失败测试,再修复至 GREEN。
## v0.0.8 发布封存验证(2026-08-17)
`npm run governance:finish -- GOV-009 application-scaffold-baseline`、`npm run governance:finish -- GOV-010 development-quality-architecture` 与 `pnpm verify:release` 均以退出码 0 完成。
- 运行时:Node.js 22.22.0、pnpm 10.25.0。
- 治理 10/10、MySQL 规范 2/2、环境 10/10、Schema 28/28、契约 3/3、边界 16/16、源码部署 6/6。
- Web Vitest 11/11;Server Vitest 30/30;Redis API 预检 2/2。
- Web、API、Scheduler、Worker 生产构建均通过;Web JS 163.91 kB、CSS 0.81 kB,未因发布文档变化增加运行时代码。
- Playwright 桌面/移动共 4/4;`verify:source` 确认四类构建产物、systemd 与 Nginx 配置一致。
- 验证只使用开发配置安全边界和现有本机 Redis;没有连接、探测或读取生产数据库,没有创建 RocketMQ Topic 或读写业务数据。
@@ -0,0 +1,21 @@
# 视觉 QA
- 日期:2026-08-13
- 浏览器:Playwright Chromium
- 状态:passed
## 桌面 1440 × 900
- 证据:`../screenshots/iterations/app-shell-ready-1440x900-3a8120a.png`
- SHA-256:`79b3ef53178c9d35fc10b75aac2d844d34c886d4e2faab69762922f4cda17802`
- 顶部品牌栏、应用标题和“工程基线已就绪”可见。
- `main` 可见,无水平溢出、控制台 warning/error 或页面异常。
## 移动 390 × 844
- 证据:`../screenshots/iterations/app-shell-ready-390x844-3a8120a.png`
- SHA-256:`12f56ae24d51c64b1e0dfc03a8a2e3538e5ce5a7a33c2863f9bff5d53efe3d1d`
- 品牌栏与正文在窄屏正常换行和留白,无水平溢出。
- 无控制台 warning/error 或页面异常。
当前画面仅证明工程外壳与响应式基线,不代表市场概览产品视觉已经完成;市场概览页面将在后续功能档案中单独设计、实现和验收。
@@ -0,0 +1,16 @@
# 发布说明
GOV-009 建立了可运行的应用工程基线:
- 根 pnpm workspace 编排独立的 Vue 3 Web 与 NestJS Server 工程。
- Server 提供 API、Scheduler、Worker 三个独立入口、最小权限配置和优雅关闭生命周期。
- HTTP 契约由 Server DTO/OpenAPI 单向生成 Web 客户端;RocketMQ 消息契约保持 Server 内部。
- Redis/MySQL 只读健康检查、TypeORM MySQL 5.7.42 基线和 RocketMQ 禁用 Adapter 已建立。
- 开发/生产模板、Ubuntu systemd/Nginx 与唯一源码部署路径已对齐。
- Schema 支持固定远程开发库与真实空库 `captured_empty`,历史清单保持不可变。
- 新增契约漂移、Vue SFC 边界、三进程生命周期、Playwright 真实 API 和源码发布门禁。
- 删除 Dockerfile、Compose、镜像校验和容器测试;Redis/MySQL/RocketMQ 统一为外部服务。
本功能已完成基于真实实现的架构论证,并于 2026-08-17 获得用户确认,随 `v0.0.8` 发布。确认范围包括前后端工程边界、Server 三进程、OpenAPI 单向契约、外部基础设施边界和 Ubuntu 仅源码部署路径。
2026-08-13 后续确认的仅源码部署决策已取代此前可选 Docker 交付结论。历史验证记录继续保留用于追溯,但仓库不再提供可执行 Docker 能力。
@@ -0,0 +1,60 @@
# 工程需求
## R1 运行时与包管理
- 仓库声明 Node.js `22.x` 和 pnpm `10.x`,不得由项目脚本安装或替换系统 Node。
- 使用根 `pnpm-workspace.yaml` 编排 `web` 与 `server`;两个工程保持独立 `package.json` 和独立构建产物。
- 锁文件必须提交,依赖版本不得使用无上限的 `latest`。
## R2 Web 工程
- 使用 Vue 3、Vite、TypeScript、Vue Router、Pinia、Naive UI 和 Dart Sass。
- 使用 Vitest 执行组件与状态测试,使用 Playwright 执行浏览器流程和视觉验证。
- Web 只读取 `VITE_` 前缀配置,不接触数据库、Redis、RocketMQ 或 AI 密钥。
- OpenAPI 生成代码与页面模型分层,页面不得直接绑定后端 DTO。
## R3 Server 工程
- 使用 NestJS 与 TypeScript,建立 `apps/api`、`apps/scheduler`、`apps/worker` 三个独立启动入口。
- 后端库按稳定职责划分为配置、HTTP 契约、消息契约、领域和基础设施;禁止按单个类过度拆分。
- API、Scheduler、Worker 分别校验自身所需配置,未使用的密钥不得成为必填项。
- 配置错误必须在进程启动阶段失败,错误日志不得输出密码或访问令牌。
## R4 契约边界
- HTTP DTO 与 OpenAPI 定义归 Server 所有,Web 通过 OpenAPI 生成自己的 TypeScript 客户端。
- Web 禁止直接引用 Server DTO、实体、领域模型或消息事件。
- RocketMQ 消息契约只在 Server 内部共享,并包含版本、事件类型、幂等键、发生时间和载荷。
- OpenAPI 生成漂移必须由自动化测试或 Git diff 检测发现。
## R5 数据与基础设施
- Redis 使用现有开发配置,API、Scheduler、Worker 使用独立逻辑库编号。
- MySQL 使用 Nest 官方集成的 TypeORM 与 `mysql2` 驱动,并显式配置 MySQL 5.7、`utf8mb4`、`utf8mb4_general_ci` 和 `+08:00` 会话时区。
- RocketMQ 默认关闭;未选定并验证 Node 客户端前,不得用虚假实现宣称消息收发可用。
- 所有健康检查必须是只读操作,不创建表、不写入业务数据。
## R6 Schema 基线
- 固定真实配置路径为 `deploy/env/development/api.env.local`,不存在时才允许读取无秘密模板并生成禁用态基线。
- 允许主机仅为回环地址或显式白名单 `112.192.20.11`;白名单不得通过命令参数或任意环境变量扩展。
- 仍固定 `APP_ENV=development`、`a_share_analysis_dev`、MySQL 5.7、`utf8mb4` 和 `utf8mb4_general_ci`。
- 空库 captured 基线必须用 format v2 结构化清单的 `object_counts` 明确记录零对象,并产生确定性校验值;不得创建伪造 SQL 文件。验证器必须继续兼容既有 format v1 历史清单且不得重写。
- Schema 工具不得读取生产 env、连接生产数据库或导出任何表数据。
## R7 部署与质量
- 项目只支持 Ubuntu 22.04/24.04 LTS x86_64 源码部署,不提供 Docker 运行、构建、测试或部署入口。
- Web、API、Scheduler、Worker 构建产物必须完整,源码部署的 systemd 命令必须与三个 Server 构建入口一致。
- 本地 Redis 和生产 Redis/MySQL/RocketMQ 均为外部系统服务,项目脚本不得安装、启动、停止或删除它们。
- `verify:release` 必须校验真实构建产物、systemd 最小权限和 Nginx Web/API 链路;Redis 不可达时 E2E 必须明确失败且不得提供容器兜底。
- 根级检查必须覆盖格式、静态检查、类型、单元测试、契约测试和构建。
- 所有关键配置边界、契约生成和启动失败行为必须有自动化测试。
- Server 使用 `@nestjs/swagger` 输出稳定的 `openapi.json`;Web 使用 `openapi-typescript` 与 `openapi-fetch` 生成类型安全客户端。
## R8 实施后架构复核
- 开发阶段允许按批准设计实施,但设计文档不能代替对实际代码结构的复核。
- 所有测试和 Review 通过后,必须新增 `architecture-review.md`,以实际文件、依赖图、进程入口、契约生成和部署产物为证据。
- 复核必须比较至少一个替代架构,解释当前方案的收益、限制、后续拆分条件和可能的技术债。
- 必须向用户展示并完成论证;用户确认前 manifest 保持 `reviewing`、版本保持 `unreleased`,不得创建 `v0.0.8` 标签。
@@ -0,0 +1,68 @@
# 代码 Review
- 审查范围:`c04184a6111da0cfad90d1a265dc3cd3a6d90a9c..95b8611bd9bbc282193591e472e2e19c617e5035`
- 审查方式:独立只读复审
- 日期:2026-08-13
## 发现与处置
第一轮发现三进程生命周期依赖本地 env、未跟踪生成契约可绕过漂移检查、Vue 外部脚本可绕过边界、生产镜像允许可变 tag,以及 Docker 未验证镜像内 Scheduler/Worker 生命周期。上述问题已在 `cb550e3` 完成整改并通过针对性测试。
最终复审进一步发现早期外部脚本正则不能识别合法的无引号 `src` 属性。GitNexus 单符号影响分析为 LOW,只有 `verifyProjectBoundaries` 一个直接调用者和一条边界检查流程。`95b8611` 改用固定版本 `@vue/compiler-sfc@3.5.41`,直接拒绝普通脚本或 setup 脚本的外部 `src`,测试覆盖双引号、单引号、无引号和属性换序,边界用例 8/8 通过。
## 最终证据
- `pnpm verify` 完整通过:静态检查、类型、全部测试、Web/Server 构建和 Playwright 4/4。
- 契约漂移 3/3、工程边界 8/8、镜像引用 5/5、Web 8/8、Server 30/30。
- Scheduler/Worker 的源码子进程生命周期使用公开 production fixture,可在干净 checkout 复现。
- HTTP 契约保持 Server DTO → OpenAPI → Web 单向发布;RocketMQ 消息契约只在 Server 内部。
- 未发现新的配置泄漏、安全、生命周期、错误处理或生产风险。
- Docker 是已验证过的历史可选交付能力;按用户决定不再作为后续日常门禁,最终开发完成后再决定是否保留。
Critical、Important、Minor 均无未关闭问题。
最终结论:passed
## 仅源码部署调整复审
- 审查范围:`cfcd7f13d9a6a35173d01bd8ca1458911190e70f..47d0e0d248eb9b21cbd12f1625d3bd0e9c266dc9` 及其后 Review 修复
- 审查重点:发布门禁绕过、子进程与信号、Redis 失败语义、systemd/Nginx 真实命令、历史证据和测试缺口
### 发现与处置
1. **Important:systemd 模板目标名不可执行。** 初版源码手册把 `*.service.example` 原样安装并以该名称重启,真实 systemd 单元名不正确。新增环境契约测试先 RED,随后改为分别安装成 `a-share-api.service`、`a-share-scheduler.service`、`a-share-worker.service`,并统一 verify/restart/status/journalctl 命令;环境 10/10 GREEN。
2. **Important:Docker 禁止清单可被新路径绕过。** 初版只阻断已删除的固定旧路径,`ops/Dockerfile` 或新 Compose YAML 会被放行。新增未列举路径测试先 RED,随后用递归活动资产扫描阻断任意 Dockerfile、`.dockerignore`、`docker-compose*.yml` 和 `compose/` YAML;部署测试 6/6 GREEN。
### 最终证据
- `pnpm verify:release` 完整通过,包含静态检查、类型、全部测试、四类构建、Playwright 4/4 和源码发布校验。
- Redis 不可达时只返回脱敏的固定本机服务提示;无安装、启动、停止或删除基础设施的分支。
- API 子进程只接收公开禁用态测试夹具,SIGINT/SIGTERM 只转发给该子进程。
- 源码门禁要求 Web 与三个 Server 入口、三份最小权限 systemd 单元和 Nginx Web/API 配置完整。
- 当前跟踪文件没有 Dockerfile、Compose、`.dockerignore` 或 Docker 专用脚本;历史文档事实仍可追溯。
Critical、Important、Minor 均无未关闭问题。
最终结论:passed
## v0.0.8 发布封存复核
- 复核日期:2026-08-17
- 本次变化只更新用户确认记录、功能状态、版本、发布说明与开发总结,没有修改运行时代码、数据库结构、消息契约或部署入口。
- `architecture-review.md` 记录的确认范围与实际实现一致;仅源码部署决策继续取代早期 Docker 方案,没有删除或伪造历史验证证据。
- 发布状态变化不会扩大生产权限,不读取生产配置或数据;回退继续采用新提交和更高补丁版本,禁止移动已推送标签。
- 完整验证与源码发布门禁在最终发布树上重新执行,结果写入本次发布记录。
## 安全与残余风险
配置、Schema、Redis/MySQL 健康检查、OpenAPI 边界和源码部署均保持最小权限与脱敏策略;本次封存不访问生产数据库、不写入外部基础设施。残余风险集中在尚未实现的 RocketMQ Node 客户端、TDX 采集和市场业务,必须在对应功能中重新 Review,不能沿用脚手架结论直接放行。
## 性能与资源影响
本次封存只有文档和版本元数据变化,没有增加线上进程、请求、数据库查询、缓存写入或消息负载。既有 Web 与三进程构建、生命周期和 Playwright 证据覆盖脚手架边界;行情刷新与分析吞吐不属于 GOV-009,后续需建立业务性能指标。
## GitNexus 与同步修改
发布封存不修改运行时符号。HTTP/OpenAPI、Web API、消息、数据库、Redis、API、Scheduler、Worker 和源码部署边界均无需代码同步;版本、manifest、CHANGELOG、开发总结、Review、发布说明和回退记录已同步更新。
最终结论:passed
@@ -0,0 +1,52 @@
# 开发规范符合性 Review
- 审查范围:`c04184a6111da0cfad90d1a265dc3cd3a6d90a9c..95b8611bd9bbc282193591e472e2e19c617e5035`
- 审查方式:独立只读复审
- 日期:2026-08-13
## 规范核对
- 所有 GOV-009 实现提交均为包含功能编号的中文 Conventional Commit,并在验证后及时推送 Gitea。
- GitNexus 前置、影响分析、开发后索引和前后对比完整;最终索引提交为 `95b8611`。
- 公共导出、契约字段、安全边界和架构取舍均有准确中文注释,未发现无意义逐行注释或过度拆分。
- MySQL 固定为 5.7.42、`utf8mb4`、`utf8mb4_general_ci` 和 `+08:00`;Schema 流程只允许固定开发库和白名单主机。
- Redis DB 0/1/2 均只读 `PING` 成功;RocketMQ NameServer/Broker/Proxy 均只读验证可达,未创建 Topic 或发送消息。
- 截图位于 `screenshots/iterations/`,文件名包含页面、状态、视口和实现版本,文档引用与 SHA-256 一致。
- 未发现密钥、真实 env、生产数据或 GitNexus 本地索引被 Git 跟踪。
- Docker 最新决定已统一记录为历史验证、可选交付、非日常必跑,不篡改此前真实验证记录。
- manifest 保持 `reviewing/unreleased`,本地与远端均不存在 `v0.0.8`。
Critical、Important、Minor 均无未关闭问题。
最终结论:passed
## 仅源码部署调整复审
- 实施计划、TDD RED/GREEN、GitNexus 前置影响、开发后 compare 和回退说明均已写入 GOV-009 档案。
- 新增关键函数包含外部基础设施所有权和安全边界中文注释,文件按“源码发布门禁”和“E2E 启动器”稳定职责组织,未过度拆分。
- MySQL 仍固定 5.7.42、`utf8mb4`、`utf8mb4_general_ci`、`+08:00`;本次没有连接、探测或读取生产数据库,也没有创建迁移或业务表。
- 本机 Redis 只执行 `PING` 与 TCP 可达性检查;RocketMQ 保持禁用,没有创建 Topic、生产或消费消息。
- 现行架构、开发规范、流程规范和部署手册只宣称 Ubuntu 源码部署;GOV-006 与早期 GOV-009 Docker 记录保留为历史并明确被取代。
- `47d0e0d` 为带 GOV-009 的中文 Conventional Commit,已推送项目专用 Gitea;最终 Review 修复和证据将在验证后以独立中文提交推送。
- manifest 保持 `reviewing/unreleased`,本地与远端均不存在 `v0.0.8`,等待用户完成总体架构确认。
Critical、Important、Minor 均无未关闭问题。
最终结论:passed
## v0.0.8 发布封存复核
- 用户于 2026-08-17 确认 GOV-009 实际架构,原有 `reviewing/unreleased` 描述作为确认前事实保留;manifest 和发布说明现已同步为 `released/v0.0.8`。
- 新增独立 `development-summary.md`,七个固定章节完整记录原始需求、范围变化、完成项、缺陷、延期、提交和验证证据。
- GOV-009 与 GOV-010 的状态、版本、CHANGELOG、Review 和回退口径一致;FEAT-DS-001 仍为未发布 PoC 前置档案,没有误报为已实现采集能力。
- 本次提交继续使用带 GOV-009 的中文 Conventional Commit,推送 `main` 后再单独精确推送 `v0.0.8`,不使用 GitHub、全局 Git 配置、强推或批量标签推送。
## 安全、性能与架构检查
安全边界覆盖开发库固定白名单、秘密隔离、最小权限配置、错误脱敏和外部基础设施只读检查;性能边界覆盖独立构建、三进程生命周期、无生产时治理开销和后续业务指标延期说明。实际架构与用户确认的 Vue 3、NestJS 三进程、OpenAPI 单向契约和 Ubuntu 仅源码部署一致。
## GitNexus 与开发总结检查
开发前影响、开发后检测、索引基线和前后对比文件完整;发布封存只影响文档与版本,不改变执行流。独立开发总结七个固定章节均有实质内容,并逐项说明 HTTP/OpenAPI、Web API、消息、数据库、Redis、API、Scheduler、Worker、部署、测试和文档的同步边界。
最终结论:passed
@@ -0,0 +1,18 @@
# 回退说明
GOV-009 没有创建业务表、执行迁移、写入生产数据库、创建 RocketMQ Topic 或发送消息。回退重点是应用代码与部署产物,不包含数据回滚。
## 代码回退
- 以中文 Conventional Commit 新建回退提交,按逆序撤销 GOV-009 提交;禁止 `reset --hard`、强推或改写 Gitea 历史。
- 若只回退 Review 整改,目标提交为 `3a8120a33aff3fc4e1f73059eed78d88d57d33a2`,必须同时恢复消息契约、三进程生命周期、契约漂移和部署门禁,禁止形成半套状态。
- 若整体移除脚手架,回到基线 `c04184a6111da0cfad90d1a265dc3cd3a6d90a9c` 的等价内容,并保留既有 `v0.0.7` Schema 历史目录。
## 部署回退
- 把 `/opt/a-share-analysis/current` 原子切回上一完整发布目录并重启 API、Scheduler、Worker 三个 systemd 服务。
- `/etc/a-share-analysis/*.env`、本地 `*.env.local`、Redis、MySQL 和 RocketMQ 数据不随应用回退覆盖或删除。
- 回退后重新执行健康检查、契约门禁和可用性验证。
- 外部基础设施和 `/etc/a-share-analysis/*.env` 不属于应用回退范围,禁止删除或覆盖。
`v0.0.8` 发布后不得删除、移动或覆盖已推送标签。需要回退时只能创建新的中文回退提交,验证并推送后再发布更高补丁版本;远程数据库、Redis、RocketMQ 和环境文件均不属于代码回退对象。
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,78 @@
# 仅源码部署调整设计
- 功能编号:GOV-009
- 决策日期:2026-08-13
- 状态:已实施并通过 Review,等待总体架构确认
- 取代范围:GOV-006、GOV-009 中仍有效的 Docker 部署约定
## 结论
项目只支持源码部署,不再提供或维护任何 Docker 运行、构建、测试或部署能力。开发环境的 Redis 使用开发机已开机自启的 `127.0.0.1:6379`;生产环境的 Redis、MySQL 5.7.42 和 RocketMQ 均由服务器外部系统服务提供。应用只连接这些基础设施,不负责安装、启动、停止或删除它们。
Ubuntu 源码部署是唯一生产交付路径:固定提交在构建机完成依赖安装、测试和 Web/Server 构建,将不可变发布目录部署到服务器,再由 systemd 管理 API、Scheduler、Worker,Nginx 托管 Web 静态文件并代理 `/api/`。
## 调整范围
### 删除的 Docker 能力
- 删除 Web 与 Server Dockerfile、根 `.dockerignore` 和 Web 容器专用 Nginx 配置。
- 删除开发与生产 Compose 文件;本地 Redis 不再由仓库拉起。
- 删除生产 Compose 部署文档、Docker 构建验证器、不可变镜像校验器及对应测试。
- 删除根级 `check:images`、`verify:docker` 等 Docker 专用命令。
- API E2E 启动器不再在 Redis 不可达时创建临时容器;Redis 不可达必须直接失败并提示本机服务要求。
### 保留和加强的源码能力
- 保留 `deploy/env/development/` 与 `deploy/env/production/` 的四进程配置契约。
- 保留并验证 systemd API、Scheduler、Worker 服务文件和生产 Nginx 配置。
- 保留 Web、API、Scheduler、Worker 的独立构建产物。
- `verify:release` 只执行源码发布门禁,不调用 Docker。
- 本地开发文档先验证 `redis-cli -h 127.0.0.1 -p 6379 ping`,再从源码启动应用进程。
## 源码部署流程
1. 在已固定 Node.js 22.x 与 pnpm 10.25.0 的构建机检出确定提交。
2. 执行 `pnpm install --frozen-lockfile` 和根级源码发布验证。
3. 构建 Web dist 与 API、Scheduler、Worker 三个 Server dist 入口。
4. 将完整、只读的版本发布目录放入 `/opt/a-share-analysis/releases/<版本或提交>/`。
5. 将 `/opt/a-share-analysis/current` 原子切换到目标发布目录。
6. systemd 通过 `/etc/a-share-analysis/*.env` 分别向三个 Server 进程注入最小配置。
7. Nginx 从当前 Web dist 提供静态文件,并把 `/api/` 代理到 API 进程。
8. 验证 systemd 状态、API 健康接口、Web 首页和同源 API 代理。
## 源码发布门禁
自动验证必须覆盖以下真实行为:
- 仓库不存在 Dockerfile、Compose、`.dockerignore`、Docker 专用验证器和 Docker 命令。
- README、现行架构、治理规范和部署索引只宣称源码部署。
- Web、API、Scheduler、Worker 构建产物存在且入口与 systemd `ExecStart` 一致。
- Nginx 静态目录指向 Web dist,`/api/` 代理指向 API 端口。
- 三份 systemd 服务使用独立 `EnvironmentFile`、非 root 用户和明确工作目录。
- 本地开发要求外部 Redis 可达,不存在自动拉起或容器兜底路径。
- Redis、MySQL 和 RocketMQ 的密码或 Token 不进入仓库、命令参数或构建产物。
## 失败处理
- 本地 Redis 不可达时,API E2E 和本地启动应快速失败,错误明确说明需要启动本机 Redis 服务;不自动改变用户机器状态。
- 源码构建任一产物缺失时阻断发布,不允许发布部分进程。
- systemd 或 Nginx 验证失败时保持上一 `current` 目录,不覆盖外部 env 和基础设施数据。
- 数据库迁移出现后,迁移必须在切换 `current` 和重启服务前单独执行;继续禁止 TypeORM `synchronize: true`。
## 历史追溯
GOV-006 与 GOV-009 已发布或已封存材料中的 Docker 记录属于当时真实设计和验证事实,不删除、不改写为“从未支持”。当前设计通过新的决策文档、现行架构、治理规范和发布说明明确取代其 Docker 结论。Git 历史仍可直接比较决策前后的文件和门禁变化。
## 回退策略
本调整尚未发布版本标签。实施失败时使用中文回退提交恢复本调整前的仓库内容,禁止强推或移动既有标签。外部 Redis、MySQL、RocketMQ、`/etc/a-share-analysis/*.env` 和服务器发布目录不由代码回退删除或覆盖。
源码部署调整完成后,应用回退只允许把 `/opt/a-share-analysis/current` 切回上一完整发布目录并重启 systemd 服务;不再提供镜像回退方案。
## 验收标准
- 仓库和现行文档中不存在仍可执行或仍被宣称支持的 Docker 能力。
- 本地与生产基础设施均被定义为外部系统服务。
- 根级完整验证、源码发布门禁、双视口页面验证、代码 Review 和规范 Review 全部通过。
- GitNexus 开发后分析只出现预期的部署与测试门禁影响。
- 所有变更以中文 Conventional Commit 提交并推送 Gitea;用户确认架构前仍不创建 `v0.0.8`。
@@ -0,0 +1,526 @@
# Source-Only Deployment Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Remove every active Docker dependency and make Ubuntu source deployment, external infrastructure, and local pre-existing Redis the only supported runtime path.
**Architecture:** The root workspace keeps one release gate that first runs the existing complete verification and then validates source artifacts against systemd and Nginx templates. Playwright's API launcher performs a read-only TCP preflight against the developer-managed Redis at `127.0.0.1:6379` and fails without starting infrastructure. Historical Docker evidence remains unchanged as history, while current architecture, governance, and GOV-009 decision records explicitly supersede it.
**Tech Stack:** Node.js 22.x, pnpm 10.25.0, Node test runner, Vue 3/Vite, NestJS, Playwright, Redis, MySQL 5.7.42, RocketMQ 5.x, Ubuntu 22.04/24.04 LTS, systemd, Nginx.
## Global Constraints
- Production supports Ubuntu source deployment only; Docker is absent from development, test, build, and production paths.
- Redis, MySQL 5.7.42, and RocketMQ 5.x are external services; project scripts never install, start, stop, or delete them.
- Local development and browser E2E use the existing Redis at `127.0.0.1:6379`; unavailability must fail fast without fallback.
- MySQL is fixed to 5.7.42 with `utf8mb4`, `utf8mb4_general_ci`, and `+08:00`; no production database may be connected, probed, or read.
- Node.js is fixed to 22.x and pnpm to 10.25.0; the repository does not install or replace system Node.js.
- Source releases use immutable `/opt/a-share-analysis/releases/<version-or-commit>/` directories and atomically switch `/opt/a-share-analysis/current`.
- API, Scheduler, and Worker use separate systemd units and separate `/etc/a-share-analysis/*.env` files under the non-root `a-share` account.
- Existing GOV-006 and GOV-009 records of past Docker decisions and successful validation remain truthful historical evidence; current records must state that the source-only decision supersedes them.
- No `v0.0.8` tag is created until the user separately confirms the implemented architecture.
- Every implementation commit uses Chinese Conventional Commit with `GOV-009`, passes GitNexus change detection, and is pushed immediately to the project Gitea remote.
---
## File Map
- `tools/deployment/verify-source-deployment.mjs`: source-release artifact and deployment-template verifier.
- `tools/deployment/verify-source-deployment.test.mjs`: verifier RED/GREEN coverage using isolated fixture directories.
- `tools/governance/environment-baseline.test.mjs`: active environment, documentation, systemd, Nginx, and no-Docker policy tests.
- `server/tools/run-test-api.mjs`: Playwright API launcher and external local Redis preflight.
- `server/tools/run-test-api.test.mjs`: launcher behavior tests proving unavailable Redis fails without Docker fallback.
- `package.json`: source-only test and release commands.
- `deploy/systemd/*.service.example`: API/Scheduler/Worker production process definitions, retained and verified.
- `deploy/nginx/a-share-analysis.conf.example`: source Web static hosting and `/api/` reverse proxy, retained and verified.
- `README.md`, `docs/index.md`, `docs/architecture/system-architecture.md`: current public architecture and deployment entry points.
- `docs/governance/code-development-standards.md`, `docs/governance/development-workflow.md`: mandatory source-only engineering and release rules.
- `docs/deployment/local-development.md`, `docs/deployment/ubuntu-source-production.md`: the only current development and production runbooks.
- `docs/features/GOV-009-application-scaffold-baseline/*.md`: requirements, PRD, design, test, release, rollback, architecture review, and traceability updates.
- `docs/features/GOV-006-environment-deployment-baseline/`: historical archive; only add a supersession pointer if a current-status statement would otherwise be ambiguous.
- `CHANGELOG.md`: unreleased policy change, preserving earlier Docker entries as history.
- `.dockerignore`, `web/Dockerfile`, `web/nginx.conf`, `server/Dockerfile`, `deploy/compose/*`, `docs/deployment/docker-compose-production.md`, `tools/deployment/verify-docker.mjs`, `tools/deployment/verify-image-references*`: remove obsolete active Docker artifacts.
---
### Task 1: Establish Source-Only Deployment Tests
**Files:**
- Create: `tools/deployment/verify-source-deployment.test.mjs`
- Modify: `tools/governance/environment-baseline.test.mjs`
- Modify: `package.json`
**Interfaces:**
- Consumes: repository paths and the existing `deploy/systemd/`, `deploy/nginx/`, `web/dist/`, and `server/dist/` conventions.
- Produces: root scripts `test:deployment` and `verify:source`; failing tests that define the source-only repository contract before implementation.
- [x] **Step 1: Add failing fixture tests for the source verifier**
Create tests that import the not-yet-existing module and define these exact behaviors:
```js
import assert from 'node:assert/strict';
import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import test from 'node:test';
import { verifySourceDeployment } from './verify-source-deployment.mjs';
test('完整源码发布夹具通过', async () => {
const root = await createSourceReleaseFixture();
await assert.doesNotReject(() => verifySourceDeployment(root));
});
test('任一 Docker 活动文件会阻断源码发布', async () => {
const root = await createSourceReleaseFixture();
await writeFile(path.join(root, 'Dockerfile'), 'FROM node:22\n');
await assert.rejects(() => verifySourceDeployment(root), /禁止存在 Docker 活动文件.*Dockerfile/);
});
test('Server 构建入口缺失会阻断源码发布', async () => {
const root = await createSourceReleaseFixture({ omit: 'server/dist/apps/worker/main.js' });
await assert.rejects(() => verifySourceDeployment(root), /Worker 构建入口不存在/);
});
test('systemd 配置不是最小权限时会阻断源码发布', async () => {
const root = await createSourceReleaseFixture({ apiUser: 'root' });
await assert.rejects(() => verifySourceDeployment(root), /API systemd 必须使用 User=a-share/);
});
test('Nginx 未代理 API 或未指向 Web dist 时会阻断源码发布', async () => {
const root = await createSourceReleaseFixture({ invalidNginx: true });
await assert.rejects(() => verifySourceDeployment(root), /Nginx/);
});
```
The local `createSourceReleaseFixture` helper must create only the minimum paths needed by the verifier: four build outputs, three unit files with distinct `EnvironmentFile`, and one Nginx file. It must accept `omit`, `apiUser`, and `invalidNginx` options so each negative test changes one condition.
- [x] **Step 2: Replace Docker assertions in the environment baseline with source-only assertions**
Keep env-template and RocketMQ tests unchanged. Replace Compose/Docker tests with explicit active-path assertions:
```js
const forbiddenActivePaths = [
'.dockerignore',
'web/Dockerfile',
'web/nginx.conf',
'server/Dockerfile',
'deploy/compose/development.yml',
'deploy/compose/production.yml.example',
'docs/deployment/docker-compose-production.md',
'tools/deployment/verify-docker.mjs',
'tools/deployment/verify-image-references.mjs',
'tools/deployment/verify-image-references.test.mjs',
];
test('活动仓库不再包含 Docker 运行构建或部署入口', async () => {
for (const relativePath of forbiddenActivePaths) {
await assert.rejects(access(new URL(relativePath, repoRoot)), { code: 'ENOENT' });
}
});
```
Add focused checks that current docs describe external local Redis, Ubuntu 22.04/24.04, Node 22.x, pnpm 10.25.0, immutable releases, health checks, and rollback. Do not scan historical feature archives for the word Docker because those files are intentional evidence.
- [x] **Step 3: Point root deployment scripts at the not-yet-existing source verifier**
Change root scripts to the following contract:
```json
"test:deployment": "node --test tools/deployment/verify-source-deployment.test.mjs",
"verify:source": "node tools/deployment/verify-source-deployment.mjs",
"verify:release": "pnpm verify && pnpm verify:source"
```
Remove `check:images` and `verify:docker`.
- [x] **Step 4: Run RED tests and record expected failures**
Run:
```bash
pnpm test:deployment
pnpm test:environment-baseline
```
Expected: the deployment test fails because `verify-source-deployment.mjs` does not exist; the environment baseline fails while active Docker artifacts and current Docker documentation still exist. Record both failures in `docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md` as the RED phase.
---
### Task 2: Implement the Source Release Verifier and Remove Docker Artifacts
**Files:**
- Create: `tools/deployment/verify-source-deployment.mjs`
- Delete: `.dockerignore`
- Delete: `web/Dockerfile`
- Delete: `web/nginx.conf`
- Delete: `server/Dockerfile`
- Delete: `deploy/compose/development.yml`
- Delete: `deploy/compose/production.yml.example`
- Delete: `docs/deployment/docker-compose-production.md`
- Delete: `tools/deployment/verify-docker.mjs`
- Delete: `tools/deployment/verify-image-references.mjs`
- Delete: `tools/deployment/verify-image-references.test.mjs`
**Interfaces:**
- Consumes: `verifySourceDeployment(repositoryRoot?: string | URL): Promise<void>` inputs and the existing build/deployment paths.
- Produces: an importable verifier plus the CLI command `pnpm verify:source`, which exits non-zero on incomplete or unsafe source releases.
- [x] **Step 1: Run GitNexus impact before modifying or deleting deployment symbols**
Run upstream impact for `assertImmutableImageReferences`, `docker`, and `verifyLongRunningProcess`, including tests. Report direct callers, affected processes, and risk to the user. If risk is HIGH or CRITICAL, stop before editing and ask for confirmation as required by `AGENTS.md`.
- [x] **Step 2: Implement the minimal source verifier**
Implement these exports in one readable file:
```js
export const FORBIDDEN_DOCKER_PATHS = Object.freeze([
'.dockerignore',
'Dockerfile',
'web/Dockerfile',
'web/nginx.conf',
'server/Dockerfile',
'deploy/compose/development.yml',
'deploy/compose/production.yml.example',
'tools/deployment/verify-docker.mjs',
'tools/deployment/verify-image-references.mjs',
]);
export async function verifySourceDeployment(repositoryRoot = defaultRepositoryRoot) {
await assertDockerArtifactsAbsent(repositoryRoot);
await assertBuildOutputsPresent(repositoryRoot);
await assertSystemdUnits(repositoryRoot);
await assertNginxConfig(repositoryRoot);
}
```
The implementation must:
- use `node:fs/promises` structured file APIs;
- reject every listed Docker path if it exists;
- require `web/dist/index.html` and `server/dist/apps/{api,scheduler,worker}/main.js`;
- parse each unit sufficiently to verify `User=a-share`, `Group=a-share`, `WorkingDirectory=/opt/a-share-analysis/current`, the process-specific `EnvironmentFile`, `ExecStartPre` env readability, and the exact built `ExecStart` entry;
- verify Nginx root `/opt/a-share-analysis/current/web/dist`, `location /api/`, and `proxy_pass http://127.0.0.1:3000`;
- produce errors that identify the missing or invalid file without printing env values;
- print `源码发布产物与 systemd/Nginx 配置验证通过` only in direct CLI mode.
- [x] **Step 3: Delete the obsolete Docker artifacts**
Delete only the paths listed in this task. Do not delete env templates, systemd units, the production Nginx template, or historical GOV-006/GOV-009 evidence.
- [x] **Step 4: Run GREEN deployment tests after creating build outputs**
Run:
```bash
pnpm build
pnpm test:deployment
pnpm test:environment-baseline
pnpm verify:source
```
Expected: all commands pass; `verify:source` confirms all four build outputs and the deployment templates.
- [x] **Step 5: Detect scope, commit, and push the executable deployment change**
Run GitNexus `detect_changes(scope: "all")`. Review that only deployment validation and environment-policy flows are affected, then run:
```bash
git add package.json tools/deployment tools/governance/environment-baseline.test.mjs deploy web/Dockerfile web/nginx.conf server/Dockerfile .dockerignore docs/deployment/docker-compose-production.md docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md
git commit -m "refactor(GOV-009): 切换为仅源码部署门禁"
git push origin "$(git branch --show-current)"
```
---
### Task 3: Make Playwright Depend Only on Existing Local Redis
**Files:**
- Modify: `server/tools/run-test-api.mjs`
- Create: `server/tools/run-test-api.test.mjs`
- Modify: `server/package.json`
**Interfaces:**
- Consumes: TCP endpoint `127.0.0.1:6379` and the existing public production API fixture.
- Produces: `checkLocalRedis({ host, port, timeoutMs }): Promise<void>` and `runTestApi(): Promise<void>`; direct execution launches only the API process after Redis succeeds.
- [x] **Step 1: Run GitNexus upstream impact for launcher symbols**
Run impact for `forwardSignal` and the `run-test-api.mjs` file, including tests. Report the Playwright web-server dependency and any API health flows before editing. Stop for confirmation only if the graph reports HIGH or CRITICAL risk.
- [x] **Step 2: Write failing launcher tests**
Refactor-safe tests must verify behavior rather than depend on Docker availability:
```js
test('Redis 不可达时给出外部服务提示并拒绝启动', async () => {
await assert.rejects(
checkLocalRedis({ host: '127.0.0.1', port: unusedPort, timeoutMs: 100 }),
/本机 Redis.*127\.0\.0\.1.*6379.*启动后重试/,
);
});
test('Redis TCP 可达时预检通过', async () => {
const server = net.createServer();
// Bind to 127.0.0.1:0, call checkLocalRedis with the assigned port, then close.
});
test('API 测试启动器不包含 Docker 子进程路径', async () => {
const source = await readFile(new URL('./run-test-api.mjs', import.meta.url), 'utf8');
assert.doesNotMatch(source, /execFileSync|docker|Container/i);
});
```
Use an OS-assigned loopback port for deterministic tests. The user-facing failure message may state the fixed required Redis endpoint even when the injected test port differs.
- [x] **Step 3: Run the launcher RED test**
Run:
```bash
node --test server/tools/run-test-api.test.mjs
```
Expected: FAIL because `checkLocalRedis` and guarded direct-execution behavior do not yet exist.
- [x] **Step 4: Refactor the launcher without infrastructure fallback**
Remove `execFileSync`, container naming, dynamic Redis port publication, ownership flags, and cleanup. Export and use:
```js
export async function checkLocalRedis({
host = '127.0.0.1',
port = 6379,
timeoutMs = 500,
} = {}) { /* TCP connect or throw a sanitized Error */ }
export async function runTestApi() {
await checkLocalRedis();
const child = spawn(/* existing API command and public fixture */);
// Forward SIGINT/SIGTERM only to the child and preserve its exit result.
}
```
Guard execution with the existing `process.argv[1]` and `fileURLToPath(import.meta.url)` pattern so tests can import the functions without starting API. Keep `REDIS_PORT: '6379'`; never derive or override it from a container.
- [x] **Step 5: Include the new test in the Server test command**
Change the Server test script to run both Vitest and the Node launcher test:
```json
"test": "vitest run && node --test tools/run-test-api.test.mjs"
```
- [x] **Step 6: Run GREEN and real local Redis checks**
Run:
```bash
node --test server/tools/run-test-api.test.mjs
redis-cli -h 127.0.0.1 -p 6379 ping
pnpm --filter @a-share-analysis/server test
pnpm verify:e2e
```
Expected: unit tests pass, Redis prints `PONG`, and both Playwright viewports pass using the already-running local Redis. If Redis is unavailable, stop with the new explicit error; do not start or install it.
- [x] **Step 7: Detect scope, commit, and push the launcher change**
Run GitNexus `detect_changes(scope: "all")`, confirm the impact is limited to Playwright/API startup, then run:
```bash
git add server/package.json server/tools/run-test-api.mjs server/tools/run-test-api.test.mjs
git commit -m "fix(GOV-009): 移除测试 Redis 容器兜底"
git push origin "$(git branch --show-current)"
```
---
### Task 4: Align Current Architecture, Governance, and Traceability
**Files:**
- Modify: `README.md`
- Modify: `docs/index.md`
- Modify: `docs/architecture/system-architecture.md`
- Modify: `docs/governance/code-development-standards.md`
- Modify: `docs/governance/development-workflow.md`
- Modify: `docs/deployment/local-development.md`
- Modify: `docs/deployment/ubuntu-source-production.md`
- Modify: `CHANGELOG.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/manifest.yaml`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/prd.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/requirements.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/design.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/test-plan.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/release-notes.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/rollback.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/architecture-review.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md`
- Optional modify: `docs/features/GOV-006-environment-deployment-baseline/manifest.yaml`
**Interfaces:**
- Consumes: the confirmed `source-only-deployment-design.md` decision and actual Task 2/3 behavior.
- Produces: one unambiguous current deployment policy with intact historical evidence and a traceable GOV-009 record.
- [x] **Step 1: Update current public docs and architecture**
Make these statements exact and consistent:
- `deploy/` contains env, systemd, and Nginx source-deployment configuration, not a dual deployment entry.
- local setup runs `redis-cli -h 127.0.0.1 -p 6379 ping` before source processes and never starts Redis;
- Ubuntu source deployment is the sole production path;
- production prerequisites are Ubuntu 22.04/24.04 LTS x86_64, Node.js 22.x, pnpm 10.25.0, Nginx, and external MySQL 5.7.42/Redis/RocketMQ 5.x;
- release verification runs `pnpm verify:release` before an immutable release directory is activated;
- rollback only switches `/opt/a-share-analysis/current` to a prior complete release and restarts systemd services.
Remove the active Docker deployment link from `README.md` and `docs/index.md`.
- [x] **Step 2: Update mandatory engineering and workflow rules**
In code standards, replace the dual-deployment variable rule with:
```text
开发源码进程与 Ubuntu 生产源码部署复用同一变量契约;项目脚本不得安装、启动、停止或删除 Redis、MySQL、RocketMQ 等外部基础设施。
```
Replace `开发、测试、Docker 和生产环境` with `开发、测试和生产环境`. In workflow rules, require env/systemd/Nginx synchronization and immutable release-directory rollback; remove Compose/image language. State that `verify:release` is the source-release gate and that unavailable external infrastructure is a failed prerequisite, never a container fallback.
- [x] **Step 3: Update GOV-009 current records without falsifying history**
Revise PRD scope, R7, design configuration/deployment sections, automated test plan, current release notes, rollback, and architecture review to match actual source-only implementation. Add `source_only_deployment_implementation_plan` to `manifest.yaml`. Keep `status: reviewing`, `release: unreleased`, and the architecture confirmation completion gate.
In `qa/test-results.md`, preserve dated Docker validation as historical fact and add a later source-only section explaining it is superseded and no longer executable. Do not rewrite old commit results as if Docker was never tested.
If GOV-006's manifest presents its Docker approach as current, add only a dated `superseded_by` pointer to the GOV-009 source-only decision; do not rewrite its original PRD/design/test evidence.
- [x] **Step 4: Add the unreleased changelog decision**
At the top current section, record that the project removed Docker/Compose/image validation and now supports only Ubuntu source deployment with external infrastructure. Leave older entries about when Docker was added unchanged below it.
- [x] **Step 5: Run active-document policy tests and scan for contradictions**
Run:
```bash
pnpm test:environment-baseline
rg -n '双部署|同时支持 Docker|Compose 只|Docker Compose 生产|verify:docker|check:images' README.md docs/index.md docs/architecture docs/governance docs/deployment docs/features/GOV-009-application-scaffold-baseline package.json
```
Expected: tests pass. Search results may remain only in explicitly dated historical results or supersession explanations; no current instruction may expose a Docker command or claim Docker support.
- [x] **Step 6: Detect scope, commit, and push documentation alignment**
Run GitNexus `detect_changes(scope: "all")`, then:
```bash
git add README.md CHANGELOG.md docs
git commit -m "docs(GOV-009): 统一仅源码部署规范"
git push origin "$(git branch --show-current)"
```
---
### Task 5: Complete Verification, GitNexus, and Two Reviews
**Files:**
- Modify: `docs/features/GOV-009-application-scaffold-baseline/gitnexus/after.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/gitnexus/comparison.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/gitnexus/detected-changes.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/review/code-review.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/review/standards-review.md`
- Modify: `docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-design.md`
**Interfaces:**
- Consumes: the completed implementation, root verification scripts, GitNexus graph, and Review standards.
- Produces: final evidence for the deployment-policy adjustment while GOV-009 remains `reviewing/unreleased` pending user architecture confirmation.
- [x] **Step 1: Run focused tests and full source release verification**
Run without Docker:
```bash
pnpm test:deployment
pnpm test:environment-baseline
node --test server/tools/run-test-api.test.mjs
pnpm verify:release
```
Expected: all pass. `verify:release` must execute the full root verification, desktop/mobile Playwright checks, builds, and `verify:source`; it must not invoke Docker.
- [x] **Step 2: Perform visual verification at both configured viewports**
Use Playwright/browser screenshots at 1440x900 and 390x844. Confirm the page is nonblank, API health data renders, no content overlaps, and browser console/network contains no blocking error. Save screenshots under the existing ignored/output convention and record results, not binary artifacts, in `qa/test-results.md`.
- [x] **Step 3: Refresh GitNexus and record before/after evidence**
Run:
```bash
npx gitnexus analyze
npx gitnexus status
npm run governance:finish -- GOV-009 application-scaffold-baseline
```
Then use GitNexus `detect_changes(scope: "compare", base_ref: "cfcd7f13d9a6a35173d01bd8ca1458911190e70f")`. Record node/edge/flow counts, removed Docker verifier symbols, added source verifier symbols, and affected processes in the three GitNexus records. Do not commit `.gitnexus/`.
- [x] **Step 4: Conduct code Review**
Review for functional regressions, release-gate bypasses, unsafe process spawning, Redis failure semantics, missing build artifacts, and test gaps. Resolve every blocking finding, rerun affected checks, and finish `review/code-review.md` with the exact line:
```text
最终结论:passed
```
- [x] **Step 5: Conduct development-standards Review**
Review source-only policy consistency, Chinese comments for non-obvious logic, file responsibility, no secrets, MySQL 5.7 constraints, no production access, historical traceability, Chinese commits, Gitea push state, and the absence of a `v0.0.8` tag. Finish `review/standards-review.md` with the exact line:
```text
最终结论:passed
```
- [x] **Step 6: Re-run final verification after Review edits**
Run:
```bash
pnpm format:check
pnpm verify:release
git status --short
```
Expected: formatting and release verification pass. Only intended Review/evidence files remain uncommitted.
- [x] **Step 7: Detect final scope, commit, and push evidence**
Run GitNexus `detect_changes(scope: "all")`, verify no unexpected application flow changed, then:
```bash
git add docs/features/GOV-009-application-scaffold-baseline
git commit -m "docs(GOV-009): 封存仅源码部署复核证据"
git push origin "$(git branch --show-current)"
```
- [x] **Step 8: Confirm remote consistency without releasing**
Run:
```bash
git status --short --branch
git ls-remote --heads origin "$(git branch --show-current)"
git tag --list v0.0.8
```
Expected: worktree clean, local HEAD equals the remote branch SHA, and `v0.0.8` has no output. Present the implemented architecture and remaining GOV-009 completion gate to the user for the separately required confirmation.
---
## Self-Review Record
- Spec coverage: every confirmed deletion, external-service boundary, source gate, Ubuntu release rule, Redis failure behavior, historical evidence rule, Review requirement, and no-tag constraint maps to a task above.
- Placeholder scan: the plan contains no deferred implementation placeholders; code interfaces, commands, expected RED/GREEN results, and commit boundaries are explicit.
- Type and name consistency: `verifySourceDeployment`, `checkLocalRedis`, `runTestApi`, `test:deployment`, `verify:source`, and `verify:release` retain the same names across production, tests, and documentation tasks.
- Scope: this plan changes deployment policy and validation only; it does not add market features, user systems, infrastructure installation, database migrations, or RocketMQ message sending.
@@ -0,0 +1,38 @@
# 测试计划
## 自动化
- Node 22 与 pnpm 10 版本门禁测试。
- Web 与 Server 配置键、敏感值脱敏和条件必填测试。
- Web 禁止导入 Server 源码的边界测试。
- OpenAPI 生成与漂移检测测试。
- API、Scheduler、Worker 独立启动与关闭测试。
- Redis/MySQL/RocketMQ disabled 健康状态测试。
- RocketMQ 消息信封版本、幂等键和载荷校验测试。
- Schema 固定远程白名单、未知远程拒绝和 `api.env.local` 优先级测试。
- Schema 空库 captured 清单、摘要和历史目录不可覆盖测试。
- Web、Server 类型检查、单元测试和生产构建。
- 源码发布门禁检查 Docker 活动入口不存在、四类构建产物完整、systemd 最小权限和 Nginx Web/API 链路。
- API E2E 的 Redis TCP 预检覆盖可达与不可达,证明失败时不启动替代基础设施。
## 真实环境冒烟
- Redis `127.0.0.1:6379` 的 DB 0、1、2 分别只读 PING。
- 固定开发 MySQL 验证认证、5.7 服务端、数据库名、字符集、排序规则和 `+08:00` 会话时区。
- RocketMQ 验证 NameServer、Broker 和 Proxy 可达;不创建 Topic,不发送消息。
- 浏览器访问 Web 与 API 健康检查,无控制台阻断错误。
- `pnpm verify:release` 只执行源码发布链路,不调用 Docker。
## 安全验证
- Git 跟踪文件不得包含本地密码、开发库凭据、AI Key 或生产地址。
- Web 构建产物不得包含 Server env 键或消息契约。
- 连接错误和测试日志不得输出密码。
- Schema 测试必须拒绝非开发环境、非固定库名、未知远程主机、错误 MySQL 版本和字符规则;验证过程不得连接生产数据库。
- RocketMQ 保持禁用态或只读可达性检查,不创建 Topic、不发送或消费消息。
## 性能验证
- Web、API、Scheduler、Worker 必须分别完成生产构建,Scheduler/Worker 在持续运行和 SIGTERM 退出测试中不得异常自退。
- Playwright 桌面与移动链路验证应用外壳和真实 API 健康代理,记录构建耗时与产物体积,不把测试替代服务计入生产能力。
- 当前没有市场行情负载、数据库业务查询或 RocketMQ 消息收发,因此吞吐与延迟压测不适用;适用边界仅为脚手架启动、构建、生命周期和有限健康检查。
@@ -0,0 +1,217 @@
# 开发质量与前后端架构规范设计
- 功能编号: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`。
@@ -0,0 +1,73 @@
# 开发质量与前后端架构规范开发总结
- 功能编号:GOV-010
- 总结版本:0.1
- 日期:2026-08-13
- 发布状态:已随 `v0.0.8` 发布
## 原始开发需求
用户要求把安全性、性能优化、GitNexus 跨功能影响分析、基于真实重复的复用抽取和开发需求/完成需求/缺陷记录纳入强制开发规范与流程;后端参考成熟 NestJS 与 RuoYi 职责边界,按业务模块在模块内分层;前端参考 RuoYi Vue3 分离版的组织方式,统一封装 Axios,并在 `api` 目录按业务域管理接口。用户进一步确认 OpenAI 兼容仅指未来 AI Provider 的外部协议,浏览器请求继续使用 Axios,前后端架构规范采用独立文件维护。
## 需求与范围变化
- 需求确认过程中澄清了 `openapi-fetch`、OpenAPI 文档和 OpenAI 兼容 API 的职责:移除前端 `openapi-fetch` 执行器,但保留 `openapi-typescript` 生成契约;未来 AI Provider 不属于 GOV-010。
- 后端分层从“固定生成完整目录树”收敛为“业务模块内按需建立职责层”,避免为了目录外观创建空层或透传层。
- 当前 Vue 页面没有消费健康接口,因此本次只建立统一 request 和健康业务域 API 样例,没有制造页面调用链。
- 开发环境、MySQL、Redis、RocketMQ、API、Scheduler、Worker 和源码部署行为均不在本次修改范围;没有访问生产数据库或生产配置。
## 实际完成需求
| 需求 | 状态 | 实际结果与证据 |
|---|---|---|
| FR-001 GitNexus 直接、间接和跨模块影响 | 已完成 | `gitnexus/impact-plan.md` 与完成门禁要求记录消费者、执行流、风险和同步修改;开始流程会生成影响计划骨架。 |
| FR-002 安全策略与评估 | 已完成 | 设计、测试、代码 Review 模板和规范 Review 模板均有固定安全证据章节;请求错误测试覆盖内部地址、凭据和响应正文脱敏。 |
| FR-003 性能目标与验证 | 已完成 | 设计和测试计划记录包体、超时、重试及治理扫描边界;最终生产构建字节数在 `qa/test-results.md` 补充。 |
| FR-004 独立开发总结 | 已完成 | 新增本文件和通用模板,`governance:finish` 将其列为必备文件并校验七个固定章节。 |
| FR-005 后端业务模块内按需分层 | 已完成(规范) | 代码规范和系统架构明确 Controller、Service、Domain、Repository、Adapter、DTO 的职责与依赖方向;现有健康模块未为目录外观迁移。 |
| FR-006 统一 Axios 与业务域 API | 已完成 | 新增 `web/src/utils/request.ts` 和 `web/src/api/health/index.ts`;AST 边界拒绝页面、组件、Store 或 Composable 直接 HTTP。 |
| FR-007 保留 OpenAPI 类型 | 已完成 | 健康 API 使用生成的 `HealthResponseDto`,契约生成与校验流程保持不变,没有 `any` 回退。 |
| FR-008 真实重复后再抽取 | 已完成(规范与 Review 门禁) | 规范禁止预测性抽象;本次只抽取真实的统一 HTTP 边界,没有创建未被使用的后端层。 |
| FR-009 新依赖评估 | 已完成 | 设计记录 Axios 1.19.0、MIT、官方来源、替代、成本、维护与退出方式;最终 audit 和包体证据进入 QA。 |
| FR-010 自动阻断缺证据完成声明 | 已完成 | 治理测试覆盖缺文件、缺章节、空正文、裸占位词和未通过 Review;边界测试覆盖 HTTP 绕过。 |
当前页面仍未接入健康 API,后端 AI Provider 尚未实现,市场概览、用户、会员和订阅功能也未由 GOV-010 实现。这些均为明确非目标,不计作本功能完成项。
## 修复缺陷
本次没有修复既有市场业务缺陷,因为仓库尚处基础治理与脚手架阶段。本次修复的是工程治理缺口:此前开发总结不是独立必备证据、安全与性能章节缺少结构化门禁、前端请求库和业务 API 边界未按用户确认的 Axios 范式落实、项目边界无法阻断直接 HTTP 绕过。对应回归测试位于治理规则、请求封装、Vite 配置、健康 API 和项目边界测试中。
验证阶段使用 npm 官方审计端点发现 `@nestjs/swagger 11.4.6` 精确依赖的 `js-yaml 5.2.1` 存在 GHSA-pm4m-ph32-ghv5 高危拒绝服务漏洞;当前最新版 Swagger 仍锁定该版本。项目采用 pnpm 精确覆盖,仅把 `@nestjs/swagger>js-yaml` 更新到同补丁线修复版本 5.2.2,不影响其他 `js-yaml` 消费者。修复前 audit 失败输出与修复后 audit、OpenAPI、后端测试和构建结果已进入 QA 证据。
代码 Review 初审另发现完成门禁可接受正文中间的 `最终结论:passed`,已新增失败测试并修复为只接受最后一个非空行;治理测试最终为 10/10,处置记录见两份 Review。
## 未完成与延期项
- 最终全量测试、浏览器视觉回归、GitNexus 开发后对比和两类 Review 已完成,完成门禁已通过。
- AI Provider 延期到独立功能设计,届时兼容 OpenAI API 协议;本次没有预留虚假实现或前端密钥。
- 当前页面接入真实健康或市场概览 API 将随对应页面功能实施;本次不为了展示请求层而增加无产品价值调用。
- 后端新业务模块会在实际出现职责时遵循按需分层;现有健康模块未迁移,避免没有业务收益的结构调整。
- GOV-009 的实际架构复核已于 2026-08-17 获得用户确认;GOV-010 随同归入 `v0.0.8`。市场概览、AI Provider、用户体系及订阅能力仍按独立功能推进,不因本次治理发布视为已实现。
## 关键提交
| 提交 | 中文摘要 | 推送状态 |
|---|---|---|
| `a8dcd06` | `docs(GOV-010): 制定开发质量治理实施计划` | 已推送 `origin/main` |
| `e12c572` | `feat(GOV-010): 强制校验开发质量证据` | 已推送 `origin/main` |
| `3a22fde` | `docs(GOV-010): 完善安全性能与架构规范` | 已推送 `origin/main` |
| `4105336` | `refactor(GOV-010): 统一封装前端 Axios 请求` | 已推送 `origin/main` |
| `d2c1863` | `feat(GOV-010): 建立前端 API 分域边界` | 已推送 `origin/main` |
| `e992edc` | `fix(GOV-010): 修复 Swagger 传递依赖漏洞` | 已推送 `origin/main` |
| `f178fb4` | `feat(GOV-010): 完成开发质量与架构治理` | 已推送 `origin/main` |
| `a398bc4` | `docs(GOV-010): 更新最终 GitNexus 基线` | 已推送 `origin/main` |
每个阶段提交后均核对本地 `HEAD` 与 Gitea `refs/heads/main`;最终 GitNexus 基线提交 `a398bc4` 已推送。本次发布封存提交与 `v0.0.8` 标签继续按规范分别推送并核对远程 SHA。
## 验证证据
- 已完成的局部证据:治理测试最终 10 项通过;请求与配置测试 10 项通过;Web 测试 11 项通过;项目边界测试 16 项通过;Web/Server 类型检查、lint、格式和 OpenAPI 契约检查均通过。
- GitNexus 阶段检测:治理、规范和 Axios 请求层为 LOW;最终 compare 为 MEDIUM(35 个文件、163 个变更符号、1 条 `CreateRequestClient → ApiRequestError` 执行流),边界工具变化只在开发门禁执行,不进入生产运行时。最新状态、前后比较和 Review 已复核该结果。
- 安全证据:请求错误脱敏、取消语义、有限超时和 HTTP 边界已有单元测试;官方 audit、构建产物敏感字符串扫描和最终 Git diff 检查已保存于 `qa/test-results.md`。
- 性能证据:迁移前后 Web 构建均为 JS 163908 字节、CSS 805 字节;10 秒默认超时、无自动重试和不适用负载边界已保存于 `qa/test-results.md`。
- 完整测试、源码发布验证和桌面/移动视觉证据已保存于 `qa/` 与 `screenshots/iterations/`;代码 Review 和规范 Review 已保存于 `review/`。
@@ -0,0 +1,24 @@
# GitNexus 开发后基线
- 功能编号:GOV-010
- 完成前索引提交:`61f85e5`
- 最终索引提交:`38b731a`
- 当前工作提交:`38b731a`
## GitNexus 状态
```text
Repository: /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis
Indexed: 8/13/2026, 11:58:25 PM
Indexed commit: 38b731a
Current commit: 38b731a
Status: up-to-date
Nodes: 1,847
Edges: 2,522
Clusters: 49
Flows: 50
```
## 开发后检测
`gitnexus_detect_changes(scope="compare", base_ref="1c1b15e")`:35 个文件、163 个变更符号、1 条受影响执行流,风险 MEDIUM。详细内容见 `detected-changes.md` 和 `comparison.md`。
@@ -0,0 +1,26 @@
# GitNexus 开发前基线
- 功能编号:GOV-010
- 记录时间:2026年8月13日 GMT+8 22:12:32
- 分支:main
- 基线提交:bbda26fa4128
## 工作区
```text
(干净)
```
## GitNexus 状态
```text
Repository: /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis
Indexed: 8/13/2026, 9:36:14 PM
Indexed commit: bbda26f
Current commit: bbda26f
Status: ✅ up-to-date
```
## 后续人工分析
在修改代码前,将 GitNexus query、context、impact 的结论写入 `gitnexus/impact-plan.md`。高风险结果必须先获得用户确认。
@@ -0,0 +1,26 @@
# GOV-010 GitNexus 计划与实际影响比较
## 直接与间接影响
- 计划中的治理门禁符号已实际改变:`getRequiredFeatureFiles`、`getInvalidFeatureEvidence`、`finish.mjs` 和 `start.mjs` 的测试与完成流程均通过治理测试覆盖。
- 计划中的请求基础设施影响已实际发生:旧 `createApiClient`/`ApiRequestError` 调用方仅为旧测试;替换后的 `createRequestClient`、`ApiRequestError` 和健康 API 通过 11 项 Web 测试、类型检查、E2E 和构建验证。
- GitNexus compare 的唯一受影响运行流为 `CreateRequestClient → ApiRequestError`,与计划一致;边界校验是开发期执行流,未进入生产运行时。
## 跨模块同步修改
| 领域 | 计划结论 | 实际结果 | 是否偏差 |
|---|---|---|---|
| HTTP/OpenAPI | 保留路由、字段和生成 Schema,仅切换浏览器执行器 | 契约生成无漂移,健康 API 使用生成 DTO,Axios 只在统一 request | 否 |
| Web API/adapter | 新增健康域 API,保持 DTO 到 ViewModel 隔离 | `api/health/index.ts` 新增,页面仍未消费健康 API,adapter 未被无谓迁移 | 否 |
| RocketMQ | 不修改消息契约 | 未修改 | 否 |
| MySQL/Schema | 不修改结构,开发前基线只读开发库 | 全量 Schema 测试通过,未触碰生产库 | 否 |
| Redis | 不修改缓存键、TTL 或连接 | 只做本机 `PONG` 健康验证,未改代码或数据 | 否 |
| API/Scheduler/Worker | 不改变运行行为 | 后端测试和三进程构建通过,行为未改 | 否 |
| 配置/部署 | 沿用 Web API 根地址,不改变源码部署 | 源码发布门禁通过,无 Docker 变更 | 否 |
| 治理/边界工具 | 增加结构化证据和 HTTP 边界门禁 | 9 项治理、16 项边界测试通过 | 否 |
| 依赖 | 移除 `openapi-fetch`,新增 Axios;补传递依赖安全修复 | Axios 1.19.0;`js-yaml` 5.2.2 override;官方 audit 0 漏洞 | 仅增加安全修复 |
| 测试/视觉 | 完整测试、构建、E2E、双视口截图 | 全部通过,截图和无回归结论已保存 | 否 |
## 风险差异
相对基线 compare 输出 MEDIUM,而开发前单项影响多为 LOW/partial。差异来自新增的前端请求运行流和项目边界校验符号,不表示业务数据链路或三进程运行风险升级。复审阶段又收紧了 Review 最终结论校验,变更符号总数由 162 增至 163,仍只有同一条 `CreateRequestClient → ApiRequestError` 运行流受影响。`e992edc` 的传递依赖修复降低了安全风险,未改变 OpenAPI 或生产运行流。
@@ -0,0 +1,22 @@
# GOV-010 GitNexus 开发后变更检测
- 检测提交:`61f85e5`
- 检测方式:重新执行 `npx gitnexus analyze` 后调用 `gitnexus_detect_changes(scope="compare", base_ref="1c1b15e")`
- GitNexus 状态:1,827 nodes、2,502 edges、49 clusters、50 flows;索引提交与当前提交均为 `61f85e5`,状态 up-to-date。
## 检测结果
- 变更文件:35
- 变更符号:163(主要为治理文档章节、治理/边界工具符号及 Axios 请求测试/实现符号)
- 受影响执行流:1
- 风险:MEDIUM
受影响执行流为 `CreateRequestClient → ApiRequestError`,包含 `createRequestClient`、`toApiRequestError` 和 `ApiRequestError` 三步。它是本次 Axios 请求层迁移的预期运行时边界,已由 Web 单元测试、类型检查、E2E 和构建覆盖。
MEDIUM 还反映了项目边界验证流的变化:该工具增加了 Axios、fetch、业务 URL 和统一 request 的 AST 规则。它只在开发/发布门禁运行,不进入 API、Scheduler、Worker 或浏览器生产请求路径。
未检测到计划外的 RocketMQ 消息消费者、MySQL/Redis 数据访问、Schema 迁移或三进程运行流变化。GitNexus 对 Markdown 文档以章节符号记录,不能替代人工阅读,因此同步修改结论在 `comparison.md` 和 Review 中重复核对。
## v0.0.8 发布封存检测
2026-08-17 再次执行 `npx gitnexus detect-changes --repo a-share-analysis`:22 个已索引文档/版本文件、55 个文档符号、0 条受影响执行流,风险 LOW。本次只把已完成治理归入 `v0.0.8`;Axios、OpenAPI、HTTP 字段、MySQL、Redis、RocketMQ、API、Scheduler、Worker 和源码部署均无运行时同步变化。
@@ -0,0 +1,54 @@
# GitNexus 开发前影响计划
- 功能编号:GOV-010
- 基线提交:`bbda26fa41288d4ae1f37c3e1c14593d5d8e910e`
- 分析日期:2026-08-13
- 总体风险:LOW;因部分遍历结果标记为 `partial`,按 MEDIUM 验证强度实施交叉检查
## 查询与上下文
GitNexus 查询了三类概念:功能档案完成门禁、前端 HTTP/OpenAPI 健康检查链路、NestJS 模块与项目边界。关键上下文结果:
- `getRequiredFeatureFiles` 的直接使用者是 `tools/governance/finish.mjs` 和 `tools/governance/feature-record.test.mjs`。
- `createApiClient` 与 `ApiRequestError` 位于 `web/src/api/client.ts`,只有旧客户端测试直接依赖两者;当前 Vue 页面尚未调用健康接口,Playwright 的健康请求属于测试进程直连后端,不应迁移为浏览器业务 API 调用;依赖锁文件包含 `openapi-fetch`。
- 健康展示链路经过 `web/src/api/adapters/health.adapter.ts` 的 `toHealthViewModel`,需保留 DTO 到 ViewModel 的隔离。
- API 端由 `HealthController.getHealth` 调用 `HealthService.check`;本次不改后端路由和 DTO。
- 项目边界由 `verifyProjectBoundaries` 扫描 TypeScript 与 Vue 脚本,适合扩展前端 HTTP 边界规则。
## 直接与间接影响
- `getRequiredFeatureFiles`:GitNexus 风险 LOW;图谱遍历返回 0 个影响但上下文明确存在两个直接调用者,因此必须同步修改测试和完成门禁验证。
- `createApiClient`:风险 LOW、结果为 `partial`;静态引用确认只需迁移旧客户端测试并新增健康 API 样例,当前没有页面调用方需要改动。
- `ApiRequestError`:风险 LOW、结果为 `partial`;新 Axios 错误类型必须保持现有安全消息行为。
- `collectSourceFiles`:风险 LOW;边界扫描是开发验证路径,不影响生产执行流,但其测试 fixture 必须同步。
没有 HIGH 或 CRITICAL 结果,不需要额外风险批准。`partial` 结果不得解释为没有调用方,实施前后使用 `rg`、类型检查、测试和 `detect_changes` 交叉验证。
## 执行流影响
- 治理完成流程:必备文件与内容校验会改变 `governance:finish` 的通过条件。
- Web 健康请求脚手架:请求库、错误路径和类型引用变化;当前页面没有对应运行时请求流,后端健康检查与 Playwright 直连验证不变。
- OpenAPI 生成流程:生成工具与输出协议不变,前端仍消费 `schema.ts`,仅请求执行器由 `openapi-fetch` 改为 Axios。
- 项目边界验证流程:增加 Axios/fetch 使用位置检查,生产运行时不受影响。
## 跨模块同步修改
| 领域 | 是否修改 | 计划 |
|---|---|---|
| HTTP/OpenAPI | 是,文档与类型消费 | 保留后端 OpenAPI 输出和生成 Schema,不修改路由或字段 |
| Web 请求/API | 是 | 新建统一 Axios request、健康业务域 API,迁移调用方和测试 |
| Web adapter/ViewModel | 可能 | 仅调整导入或调用链,保持转换行为与类型边界 |
| RocketMQ 消息契约 | 否 | 本功能不修改消息协议或进程通信 |
| MySQL/迁移/Schema | 否 | 不修改结构;开发前只验证已发布 `v0.0.7` 基线 |
| Redis/缓存 | 否 | 不修改缓存键、TTL、连接或数据 |
| API/Scheduler/Worker | 否 | 不改变三个后端进程运行行为,只新增其架构规范 |
| 配置与部署 | 可能 | Axios 沿用现有 Web API 根地址;若变量名不变则无需改模板 |
| 治理工具 | 是 | 必备开发总结、结构化内容校验及错误信息 |
| 边界工具 | 是 | 限制前端直接 HTTP 调用并增加测试 |
| 文档与模板 | 是 | 更新代码规范、流程、追溯、PRD、Review、AGENTS 和模板 |
| 依赖与锁文件 | 是 | Web 删除 `openapi-fetch`,新增固定版本 Axios |
| 测试与视觉 QA | 是 | 补单元、边界、全量、构建体积和现有页面回归证据 |
## GitNexus 状态限制
CLI 在开发前运行后报告索引提交与当前 HEAD 均为 `bbda26f` 且状态最新。MCP 的 context 资源仍显示旧统计并提示落后 5 个提交,说明 MCP 资源缓存未同步;查询、符号上下文和影响结果仍能定位当前文件。开发后必须重新运行 CLI 分析、调用 `detect_changes`,并把该缓存差异记录在比较报告中。
@@ -0,0 +1,849 @@
# 开发质量与前后端架构规范实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 建立可自动执行的安全、性能、GitNexus 影响和开发总结门禁,并把前端请求脚手架迁移为使用 OpenAPI 类型的统一 Axios 分域 API 架构。
**Architecture:** 治理规则由纯函数负责档案结构和章节证据校验,`finish.mjs` 只负责编排;前端由 `utils/request.ts` 独占 Axios 实例,`api/<业务域>/index.ts` 暴露类型化 DTO,功能层不依赖 Axios 类型。后端只更新正式架构规范,不为尚未出现的业务职责创建空目录或透传层。
**Tech Stack:** Node.js 22.x、pnpm 10.25.0、TypeScript 5.9、Vue 3、Vite 6、Vitest、Axios 1.19.0、OpenAPI、NestJS、GitNexus、Node Test Runner。
## Global Constraints
- 开始实现前,开发前 Schema 基线和 `governance:start` 已完成;基线提交为 `1c1b15e7093e0e8b4acdc48ba59d92e57ac888f0`。
- 修改任何现有函数、类或方法前,必须对该符号执行 GitNexus upstream impact;HIGH 或 CRITICAL 必须先报告用户。
- 每项行为变化先写失败测试、确认按预期失败,再写最小实现并重构。
- Git 提交必须使用中文 Conventional Commit,并带 `GOV-010`;每次验证通过的提交立即精确推送 `origin/main`,禁止强推。
- 不触碰生产数据库、生产配置或生产数据;本功能不修改 MySQL、Redis 或 RocketMQ 运行状态。
- MySQL 继续固定 5.7.42、`utf8mb4`、`utf8mb4_general_ci` 和 `+08:00`;生产继续仅支持 Ubuntu 源码部署。
- 前端 HTTP 请求统一使用 Axios;OpenAPI 仅生成 TypeScript 契约;AI 兼容 OpenAI API 是独立的后端 Provider 协议。
- 禁止 `any` 代替已有 OpenAPI 类型;外部错误不得泄漏内部 URL、凭据、请求头或响应正文。
- 只在真实重复和稳定边界出现后抽取复用代码,不为满足目录外观创建空层。
- 当前 Vue 页面尚未消费健康 API;本次只迁移请求客户端脚手架并新增健康 API 分域样例,不把健康状态强行接入页面。
---
## File Structure
### 新建文件
- `docs/templates/development-summary-template.md`:独立开发总结模板。
- `web/src/utils/request.ts`:唯一 Axios 实例、类型化请求和错误归一化入口。
- `web/src/utils/request.test.ts`:Axios 封装的 URL、DTO 解包、超时、错误与取消测试。
- `web/src/api/health/index.ts`:健康业务域 API。
- `web/src/api/health/index.test.ts`:健康 API 的请求配置与生成类型测试。
- `docs/features/GOV-010-development-quality-architecture/development-summary.md`:实际完成事实。
- `docs/features/GOV-010-development-quality-architecture/gitnexus/detected-changes.md`:开发后影响检测。
- `docs/features/GOV-010-development-quality-architecture/gitnexus/after.md`:开发后图谱基线,由完成门禁生成后补充。
- `docs/features/GOV-010-development-quality-architecture/gitnexus/comparison.md`:计划与实际影响比较。
- `docs/features/GOV-010-development-quality-architecture/qa/test-results.md`:测试、安全、性能和构建体积证据。
- `docs/features/GOV-010-development-quality-architecture/qa/visual-qa.md`:桌面和移动视觉回归证据。
- `docs/features/GOV-010-development-quality-architecture/review/code-review.md`:代码 Review。
- `docs/features/GOV-010-development-quality-architecture/review/standards-review.md`:规范符合性 Review。
- `docs/features/GOV-010-development-quality-architecture/release-notes.md`:未发布变更说明。
### 修改文件
- `tools/governance/feature-record.mjs`:必备开发总结和结构化证据校验。
- `tools/governance/feature-record.test.mjs`:治理规则的正反例测试。
- `tools/governance/finish.mjs`:读取档案并执行证据门禁。
- `tools/governance/start.mjs`:为后续功能生成 GitNexus 影响计划骨架。
- `tools/boundaries/verify-project-boundaries.mjs`:前端 HTTP 请求边界校验。
- `tools/boundaries/verify-project-boundaries.test.mjs`:Axios、fetch、业务 URL 和合法分层测试。
- `web/package.json`、`pnpm-lock.yaml`:用 Axios 1.19.0 替换 `openapi-fetch`。
- `web/tsconfig.json`、`web/vite.config.ts`、`web/vitest.config.ts`:统一 `@/* -> web/src/*` 别名。
- `web/src/vite-config.test.ts`:别名和现有同源代理测试。
- `docs/governance/code-development-standards.md`:安全、性能、复用、前后端架构规范。
- `docs/governance/development-workflow.md`:GitNexus 同步修改分析、总结和 Review 流程。
- `docs/governance/documentation-traceability.md`:独立开发总结的档案位置和职责。
- `docs/governance/prd-standard.md`:安全、性能、关联模块和依赖评估输入。
- `docs/governance/review-standard.md`:两类 Review 的新增必查证据。
- `docs/templates/prd-template.md`、`docs/templates/code-review-template.md`、`docs/templates/standards-review-template.md`:新增必填章节和检查项。
- `docs/architecture/system-architecture.md`:模块内分层和 Axios/OpenAPI 数据流事实。
- `AGENTS.md`:开发代理入口强制要求。
- `CHANGELOG.md`:GOV-010 未发布变更。
- `docs/features/GOV-010-development-quality-architecture/manifest.yaml`:实施状态和总结入口。
### 删除文件
- `web/src/api/client.ts`:由 `utils/request.ts` 和业务域 API 取代。
- `web/src/api/client.test.ts`:由新请求封装和健康 API 测试取代。
---
### Task 1: 治理档案与证据校验
**实施状态:已完成。** 对应提交 `e12c572`,治理测试 9 项通过并已推送 Gitea。
**Files:**
- Modify: `tools/governance/feature-record.test.mjs`
- Modify: `tools/governance/feature-record.mjs`
- Modify: `tools/governance/finish.mjs`
- Modify: `tools/governance/start.mjs`
**Interfaces:**
- Consumes: `Map<string, string>`,键为功能目录内相对路径,值为完整 Markdown 内容。
- Produces: `getRequiredFeatureFiles(): string[]`,清单新增 `development-summary.md`。
- Produces: `getInvalidFeatureEvidence(featureReports: Map<string, string>): string[]`,返回 `文件:章节` 形式的问题,不抛出首个错误后停止。
- Produces: `buildImpactPlanTemplate(featureId: string): string`,生成包含影响范围、风险和同步修改清单的 Markdown 骨架。
- Completion behavior: `finish.mjs` 在文件存在校验后调用证据校验,并一次列出全部无效章节。
- [x] **Step 1: 先对现有治理符号执行 GitNexus 影响分析**
Run:
```text
gitnexus_impact(target="getRequiredFeatureFiles", direction="upstream", includeTests=true)
gitnexus_impact(target="getUnpassedReviewFiles", direction="upstream", includeTests=true)
```
Expected: LOW 或 MEDIUM;直接同步范围至少包含 `feature-record.test.mjs` 和 `finish.mjs`。若结果为 `partial`,记录限制并继续使用静态引用交叉核对。
- [x] **Step 2: 写治理规则失败测试**
在 `feature-record.test.mjs` 中加入以下结构化样例。完整有效档案必须包含:
```js
const validReports = new Map([
[
'development-summary.md',
`# 开发总结
## 原始开发需求
建立可自动执行的质量门禁。
## 需求与范围变化
范围未变化,仍只处理治理与请求脚手架。
## 实际完成需求
完成独立总结和证据校验。
## 修复缺陷
本次没有修复既有业务缺陷;只补足治理能力。
## 未完成与延期项
AI Provider 延期到独立功能,不属于本次范围。
## 关键提交
记录中文提交 SHA 与摘要。
## 验证证据
记录测试、构建和 Review 结果。
`,
],
['design.md', '# 设计\n\n## 安全策略与评估\n说明信任边界和残余风险。\n\n## 性能目标与评估\n说明预算和验证强度。\n'],
['test-plan.md', '# 测试\n\n## 安全验证\n验证脱敏错误。\n\n## 性能验证\n比较构建体积。\n'],
['gitnexus/impact-plan.md', '# 影响\n\n## 直接与间接影响\n列出消费者。\n\n## 跨模块同步修改\n逐项判断契约、缓存和进程。\n'],
['review/code-review.md', '# Review\n\n## 安全与残余风险\n证据充分。\n\n## 性能与资源影响\n增量可接受。\n\n## GitNexus 与同步修改\n实际影响符合计划。\n\n最终结论:passed\n'],
['review/standards-review.md', '# 规范 Review\n\n## 安全、性能与架构检查\n逐项符合。\n\n## GitNexus 与开发总结检查\n证据齐全。\n\n最终结论:passed\n'],
]);
```
断言:
```js
assert.ok(getRequiredFeatureFiles().includes('development-summary.md'));
assert.deepEqual(getInvalidFeatureEvidence(validReports), []);
```
再逐一删除章节、提供空正文、提供裸 `无`、裸 `不适用`、`N/A`,断言返回对应的 `文件:章节`。提供 `不适用:本功能不进入生产请求路径,边界仅为开发门禁。`,断言可以通过。
- [x] **Step 3: 运行测试确认按预期失败**
Run:
```bash
npm run test:governance
```
Expected: FAIL,原因是 `development-summary.md` 尚未在清单中,且 `getInvalidFeatureEvidence`、`buildImpactPlanTemplate` 尚未导出。
- [x] **Step 4: 实现最小 Markdown 章节校验**
在 `feature-record.mjs` 中保持单文件职责,加入固定规则:
```js
const REQUIRED_EVIDENCE_SECTIONS = Object.freeze({
'development-summary.md': [
'原始开发需求',
'需求与范围变化',
'实际完成需求',
'修复缺陷',
'未完成与延期项',
'关键提交',
'验证证据',
],
'design.md': ['安全策略与评估', '性能目标与评估'],
'test-plan.md': ['安全验证', '性能验证'],
'gitnexus/impact-plan.md': ['直接与间接影响', '跨模块同步修改'],
'review/code-review.md': ['安全与残余风险', '性能与资源影响', 'GitNexus 与同步修改'],
'review/standards-review.md': [
'安全、性能与架构检查',
'GitNexus 与开发总结检查',
],
});
```
章节解析允许标题前带数字序号,例如 `## 8. 安全策略与评估` 与 `## 安全策略与评估` 视为同一标题;正文截止下一个二级标题。有效正文至少包含一个非标题、非注释、非空白的说明行;若规范化后仅为 `无`、`不适用`、`N/A` 或 `none` 则无效。不要解析业务结论真伪,也不要依赖包含“安全”或“性能”的任意散文。
- [x] **Step 5: 让开始门禁生成影响计划骨架**
导出并测试:
```js
export function buildImpactPlanTemplate(featureId) {
return `# GitNexus 开发前影响计划
- 功能编号:${featureId}
- 总体风险:待分析
## 直接与间接影响
请记录 query、context、upstream impact、消费者和执行流。
## 跨模块同步修改
请逐项判断 HTTP/OpenAPI、Web API、消息契约、数据库、Redis、API、Scheduler、Worker、配置部署、测试和文档。
`;
}
```
`start.mjs` 在创建 `before.md` 的同一目录创建 `impact-plan.md`;若任一目标文件已存在则在写入前失败,禁止覆盖历史。GOV-010 已有人工影响计划,因此只影响后续功能。
- [x] **Step 6: 接入完成门禁**
`finish.mjs` 读取全部必备文件形成 `Map`,先报告缺失文件,再调用:
```js
const invalidEvidence = getInvalidFeatureEvidence(featureReports);
if (invalidEvidence.length > 0) {
throw new Error(`完成门禁未通过,证据章节缺失或说明无效:\n- ${invalidEvidence.join('\n- ')}`);
}
```
已发布 GOV-001 至 GOV-008 不批量修改;它们是不可变历史,也不再重新执行新的完成门禁。仍为 `unreleased` 的 GOV-009、FEAT-MO-001 以及后续档案,在将来完成时必须满足新规则。
- [x] **Step 7: 运行治理测试**
Run:
```bash
npm run test:governance
```
Expected: PASS,覆盖必备清单、有效章节、空章节、裸占位词、带理由不适用和影响计划骨架。
- [x] **Step 8: 检测变化并提交推送**
Run GitNexus `detect_changes(scope="all")`,确认只影响治理完成路径。然后:
```bash
git add tools/governance/feature-record.mjs tools/governance/feature-record.test.mjs tools/governance/finish.mjs tools/governance/start.mjs
git commit -m "feat(GOV-010): 强制校验开发质量证据"
git push origin main
```
Expected: 本地 HEAD 与 `refs/heads/main` 远程 SHA 一致。
---
### Task 2: 规范、模板与架构事实
**实施状态:已完成。** 对应提交 `3a22fde`,格式、治理和环境相关验证通过并已推送 Gitea。
**Files:**
- Create: `docs/templates/development-summary-template.md`
- Modify: `docs/governance/code-development-standards.md`
- Modify: `docs/governance/development-workflow.md`
- Modify: `docs/governance/documentation-traceability.md`
- Modify: `docs/governance/prd-standard.md`
- Modify: `docs/governance/review-standard.md`
- Modify: `docs/templates/prd-template.md`
- Modify: `docs/templates/code-review-template.md`
- Modify: `docs/templates/standards-review-template.md`
- Modify: `docs/architecture/system-architecture.md`
- Modify: `AGENTS.md`
- Modify: `CHANGELOG.md`
**Interfaces:**
- Consumes: Task 1 的固定章节名,模板标题必须逐字一致。
- Produces: 后续功能可直接复制的开发总结、安全、性能、GitNexus 和 Review 模板。
- Produces: 前端 Axios/OpenAPI 分工与后端业务模块内按需分层的正式架构事实。
- [x] **Step 1: 对入口规范和架构文档执行影响检查**
Run GitNexus 对 `AGENTS.md`、`code-development-standards.md`、`development-workflow.md` 和 `system-architecture.md` 文件执行 upstream impact。Expected: 文档变化不影响生产执行流;若工具只能返回文件级 LOW/partial,记录限制。
- [x] **Step 2: 建立与门禁完全一致的模板**
`development-summary-template.md` 必须包含 Task 1 的七个二级标题,并在每节说明应记录的事实。PRD 模板新增:
```markdown
## 安全需求与信任边界
## 性能目标与容量假设
## 关联模块与同步修改
## 新增依赖评估
```
代码 Review 模板新增 `安全与残余风险`、`性能与资源影响`、`GitNexus 与同步修改`;规范 Review 模板新增 `安全、性能与架构检查`、`GitNexus 与开发总结检查`。标题必须与 Task 1 校验规则一致。
- [x] **Step 3: 更新代码开发规范**
明确写入:
- 安全评估的资产、信任边界、认证授权、校验与注入、XSS/CSRF/CORS/SSRF、凭据、供应链、日志、保留、滥用和残余风险。
- 性能评估的延迟/吞吐/新鲜度、复杂度、MySQL 索引/N+1、Redis TTL/一致性/击穿、API 载荷、前端包体/渲染/图表、Worker 并发/幂等/背压、上游与 AI 超时/重试/批处理/成本。
- 出现真实重复并形成稳定职责后再抽取工具、Composable、组件或共享库;禁止凭感觉预抽象。
- 后端以业务模块为一级目录,模块内部按需建立 `controllers/services/dto/domain/repositories/adapters/types/utils`,禁止全局堆放和空透传层。
- 前端 `utils/request.ts` 独占 Axios;业务接口位于 `api/<业务域>/index.ts`;页面、组件、Store、Composable 禁止直接 HTTP;生成 OpenAPI 类型继续作为契约来源。
- 新依赖安装前记录用途、替代、安全、许可证、体积/成本、维护和退出方案。
- [x] **Step 4: 更新流程与追溯规范**
开发前流程要求 GitNexus 同时回答影响其他功能/模块和是否需要同步修改;缺陷修复不例外。开发后流程要求先填写开发总结,再做两类 Review。追溯树加入:
```text
├── development-summary.md
```
并明确 PRD、开发总结、release notes 三者分别记录目标、实际完成和面向版本使用者的变化。
- [x] **Step 5: 更新系统架构与代理入口**
`system-architecture.md` 增加 Axios/OpenAPI 数据流和业务模块内分层;修正当前仓库结构中不存在的顶层 `contracts/` 表述,使用实际的 `server/openapi`、`server/libs/http-contracts` 和 `server/libs/message-contracts`。`AGENTS.md` 增加强制安全/性能、GitNexus 同步修改、独立开发总结、前后端架构边界。`CHANGELOG.md` 的 Unreleased 增加 GOV-010 条目。
- [x] **Step 6: 校验标题与格式**
Run:
```bash
rg -n "^## (原始开发需求|需求与范围变化|实际完成需求|修复缺陷|未完成与延期项|关键提交|验证证据|安全策略与评估|性能目标与评估|安全验证|性能验证|直接与间接影响|跨模块同步修改|安全与残余风险|性能与资源影响|GitNexus 与同步修改|安全、性能与架构检查|GitNexus 与开发总结检查)$" docs AGENTS.md
pnpm exec prettier --check AGENTS.md CHANGELOG.md docs/governance docs/templates docs/architecture/system-architecture.md
npm run test:governance
```
Expected: 所有门禁标题均出现在对应模板或 GOV-010 档案中,格式与治理测试通过。
- [x] **Step 7: 检测变化并提交推送**
Run GitNexus `detect_changes(scope="all")`,然后:
```bash
git add AGENTS.md CHANGELOG.md docs/governance docs/templates docs/architecture/system-architecture.md
git commit -m "docs(GOV-010): 完善安全性能与架构规范"
git push origin main
```
---
### Task 3: Axios 请求封装与路径别名
**实施状态:已完成。** 对应提交 `4105336`,请求、配置、类型、lint 和格式验证通过并已推送 Gitea。
**Files:**
- Create: `web/src/utils/request.test.ts`
- Create: `web/src/utils/request.ts`
- Modify: `web/package.json`
- Modify: `pnpm-lock.yaml`
- Modify: `web/tsconfig.json`
- Modify: `web/vite.config.ts`
- Modify: `web/vitest.config.ts`
- Modify: `web/src/vite-config.test.ts`
- Delete: `web/src/api/client.ts`
- Delete: `web/src/api/client.test.ts`
**Interfaces:**
- Produces: `type RequestErrorKind = 'network' | 'http' | 'unknown'`。
- Produces: `class ApiRequestError extends Error { kind: RequestErrorKind; status?: number }`。
- Produces: `interface RequestClientOptions { baseURL: string; timeoutMs?: number; adapter?: AxiosAdapter }`。
- Produces: `type RequestClient = <TData>(config: AxiosRequestConfig) => Promise<TData>`。
- Produces: `createRequestClient(options: RequestClientOptions): RequestClient`。
- Produces: 默认导出 `request`,其 base URL 为 `import.meta.env.VITE_API_BASE_URL || ''`,默认超时 `10_000` 毫秒。
- Produces: `@/*` 同时在 TypeScript、Vite 和 Vitest 解析为 `web/src/*`。
- [x] **Step 1: 对旧请求符号和 Vite 配置执行影响分析**
Run:
```text
gitnexus_impact(target="createApiClient", direction="upstream", includeTests=true)
gitnexus_impact(target="ApiRequestError", direction="upstream", includeTests=true)
gitnexus_impact(target="readDevelopmentPublicEnv", direction="upstream", includeTests=true)
```
Expected: 旧请求符号风险 LOW/partial,直接引用仅旧测试;Vite 配置影响开发服务器和配置测试,保持现有 `/api` 代理。
- [x] **Step 2: 记录依赖评估和构建基线**
在后续 `qa/test-results.md` 预留并最终记录:Axios 1.19.0、MIT、官方仓库、替代项 `fetch/openapi-fetch`、选择原因、退出方式。当前构建基线记录为 JS `163908` 字节、CSS `805` 字节;最终构建使用实际产物重新测量。依赖元数据查询若使用 npm,指定任务临时缓存,避免本机 `~/.npm` 的既有权限问题:
```bash
npm_config_cache=/tmp/a-share-analysis-gov010-npm-cache pnpm view axios version license repository.url --json
```
- [x] **Step 3: 安装 Axios 并移除旧请求库**
Run:
```bash
pnpm --filter @a-share-analysis/web remove openapi-fetch
pnpm --filter @a-share-analysis/web add axios@1.19.0
```
Expected: `web/package.json` 只保留 Axios 作为浏览器 HTTP 请求库,锁文件不再含 `openapi-fetch`。
- [x] **Step 4: 写 Axios 封装失败测试**
使用自定义 `AxiosAdapter` 返回确定响应,覆盖:
```ts
const request = createRequestClient({
baseURL: 'http://127.0.0.1:3000/',
timeoutMs: 10_000,
adapter: async (config) => ({
data: healthyDto,
status: 200,
statusText: 'OK',
headers: {},
config,
}),
});
await expect(
request<HealthResponseDto>({ url: '/api/v1/health', method: 'get' }),
).resolves.toEqual(healthyDto);
```
另外让 adapter 抛出包含 `mysql://root:secret@internal` 的 `AxiosError`,断言最终错误只含 `API 请求失败,请稍后重试`、`kind` 和非敏感 `status`。使用已取消的 `AbortController.signal` 断言取消错误保持 `axios.isCancel(error) === true`。
- [x] **Step 5: 运行 Web 测试确认失败**
Run:
```bash
pnpm --filter @a-share-analysis/web test -- src/utils/request.test.ts
```
Expected: FAIL,原因是 `web/src/utils/request.ts` 尚不存在。
- [x] **Step 6: 实现类型化 request 包装器**
核心行为:
```ts
export function createRequestClient({
baseURL,
timeoutMs = 10_000,
adapter,
}: RequestClientOptions): RequestClient {
const client = axios.create({
baseURL: baseURL.replace(/\/$/, ''),
timeout: timeoutMs,
adapter,
});
client.interceptors.request.use((config) => config);
return async <TData>(config: AxiosRequestConfig) => {
try {
const response = await client.request<TData>(config);
return response.data;
} catch (error) {
if (axios.isCancel(error)) throw error;
throw toApiRequestError(error);
}
};
}
```
请求拦截器保留为后续认证扩展点,但不提前实现 Token 刷新。`toApiRequestError` 不保存原始错误消息、URL、请求头或响应正文。HTTP 状态只允许保存数字状态码。
- [x] **Step 7: 增加 `@` 别名并保留现有代理**
- `web/tsconfig.json`: `baseUrl: "."`,`paths: { "@/*": ["src/*"] }`。
- `web/vite.config.ts`: `resolve.alias['@'] = path.resolve(webDirectory, 'src')`。
- `web/vitest.config.ts`: 使用 `fileURLToPath(new URL('./src', import.meta.url))` 配置同一别名。
- `vite-config.test.ts`: 同时断言 `resolve.alias` 和原有 `/api` 代理,禁止迁移时破坏同源策略。
- [x] **Step 8: 删除旧客户端并运行局部验证**
Run:
```bash
rg -n "openapi-fetch|createApiClient|src/api/client" web pnpm-lock.yaml
pnpm --filter @a-share-analysis/web test -- src/utils/request.test.ts src/vite-config.test.ts
pnpm --filter @a-share-analysis/web typecheck
```
Expected: `rg` 无匹配;请求与 Vite 测试、类型检查通过。
- [x] **Step 9: 检测变化并提交推送**
Run GitNexus `detect_changes(scope="all")`,确认只影响 Web 请求基础设施与配置。然后:
```bash
git add web/src/utils web/src/api/client.ts web/src/api/client.test.ts web/package.json web/tsconfig.json web/vite.config.ts web/vitest.config.ts web/src/vite-config.test.ts pnpm-lock.yaml
git commit -m "refactor(GOV-010): 统一封装前端 Axios 请求"
git push origin main
```
---
### Task 4: 健康 API 分域与 HTTP 架构边界
**实施状态:已完成。** 对应提交 `d2c1863`,边界测试 16 项、Web 测试 11 项及契约验证通过并已推送 Gitea。
**Files:**
- Create: `web/src/api/health/index.test.ts`
- Create: `web/src/api/health/index.ts`
- Modify: `tools/boundaries/verify-project-boundaries.test.mjs`
- Modify: `tools/boundaries/verify-project-boundaries.mjs`
**Interfaces:**
- Consumes: Task 3 默认导出 `request<TData>(config): Promise<TData>`。
- Consumes: `components['schemas']['HealthResponseDto']` from `web/src/api/generated/schema.ts`。
- Produces: `getHealth(signal?: AbortSignal): Promise<HealthResponseDto>`。
- Boundary: 只有 `web/src/utils/request.ts` 可以导入 `axios` 或创建 Axios 实例;`web/src` 的其他运行时代码禁止调用全局 `fetch`。
- Boundary: `/api/...` 业务路径字符串只能出现在 `web/src/api/` 或 `web/src/utils/request.ts`;测试和自动生成文件按各自 fixture 验证,不放宽生产源码。
- [x] **Step 1: 对边界校验符号执行影响分析**
Run:
```text
gitnexus_impact(target="collectSourceFiles", direction="upstream", includeTests=true)
gitnexus_impact(target="verifyProjectBoundaries", direction="upstream", includeTests=true)
```
Expected: LOW;只影响项目验证和其测试,不进入线上执行流。
- [x] **Step 2: 写健康 API 失败测试**
使用 Vitest mock `@/utils/request`:
```ts
vi.mock('@/utils/request', () => ({ default: vi.fn() }));
await getHealth(signal);
expect(request).toHaveBeenCalledWith({
url: '/api/v1/health',
method: 'get',
signal,
});
```
让 mock 返回完整 `HealthResponseDto`,并通过类型断言证明 `getHealth` 返回 DTO 而不是 `AxiosResponse`。
- [x] **Step 3: 写边界失败测试**
fixture 覆盖以下违规:
- Vue 页面 `import axios from 'axios'`。
- Store 中 `fetch('/api/v1/health')`。
- Composable 中 `axios.create()`。
- 页面中把 `'/api/v1/health'` 传给自定义调用函数。
- `web/src/api/health/index.ts` 自己导入 Axios 而不使用 `@/utils/request`。
合法 fixture 包含 `utils/request.ts` 导入 Axios、`api/health/index.ts` 导入统一 request、页面只导入 `getHealth`。继续保留 Web 禁止导入 Server 和内部消息契约测试。
- [x] **Step 4: 运行测试确认失败**
Run:
```bash
pnpm --filter @a-share-analysis/web test -- src/api/health/index.test.ts
npm run test:boundaries
```
Expected: 健康 API 测试因文件不存在失败;边界违规 fixture 因当前校验未识别 Axios/fetch 而失败。
- [x] **Step 5: 实现健康业务域 API**
```ts
import type { components } from '@/api/generated/schema';
import request from '@/utils/request';
export type HealthResponseDto = components['schemas']['HealthResponseDto'];
/** 健康接口只返回 OpenAPI DTO,不把 Axios 响应对象扩散到功能层。 */
export function getHealth(signal?: AbortSignal): Promise<HealthResponseDto> {
return request<HealthResponseDto>({
url: '/api/v1/health',
method: 'get',
signal,
});
}
```
保留现有 `api/adapters/health.adapter.ts`;它负责 DTO 到 ViewModel,不移动到全局工具目录,也不接入当前页面。
- [x] **Step 6: 实现 AST 边界校验**
在现有 TypeScript AST 遍历中收集:
- `axios` 的静态/动态导入和 require。
- 标识符为 `fetch` 的调用。
- Axios 命名空间的 `create/get/post/put/patch/delete/request` 调用。
- 调用参数中的 `/api` 绝对业务路径字符串。
此外,对 `web/src/api/<业务域>/` 下非测试、非 `generated` 的运行时代码建立正向约束:文件只要声明业务 API 路径,就必须静态导入 `@/utils/request`,不得通过其他本地包装器绕开统一入口。
按 `path.relative(webSourceRoot, sourcePath)` 判断允许位置,错误格式必须包含源码路径和违规种类。不要扫描注释或普通展示文本;业务 URL 只检查 CallExpression 参数中的字符串字面量。
- [x] **Step 7: 运行局部与契约验证**
Run:
```bash
pnpm --filter @a-share-analysis/web test -- src/api/health/index.test.ts src/api/adapters/health.adapter.test.ts
npm run test:boundaries
pnpm check:contracts
pnpm typecheck
```
Expected: 全部 PASS;OpenAPI 输出无业务字段变化,Web 仍不依赖 Server 源码。
- [x] **Step 8: 检测变化并提交推送**
Run GitNexus `detect_changes(scope="all")`,然后:
```bash
git add web/src/api/health tools/boundaries/verify-project-boundaries.mjs tools/boundaries/verify-project-boundaries.test.mjs
git commit -m "feat(GOV-010): 建立前端 API 分域边界"
git push origin main
```
---
### Task 5: GOV-010 档案、依赖评估与开发总结
**实施状态:已完成。** 开发总结、发布说明、依赖评估和档案状态已补齐;安全审计发现并通过 `e992edc` 修复 Swagger 的 `js-yaml` 传递依赖漏洞,Review 初审发现的结论行校验绕过也已通过测试先行修复。
**Files:**
- Create: `docs/features/GOV-010-development-quality-architecture/development-summary.md`
- Create: `docs/features/GOV-010-development-quality-architecture/release-notes.md`
- Modify: `docs/features/GOV-010-development-quality-architecture/manifest.yaml`
- Modify: `docs/features/GOV-010-development-quality-architecture/design.md`
- Modify: `docs/features/GOV-010-development-quality-architecture/test-plan.md`
- Modify: `docs/features/GOV-010-development-quality-architecture/implementation-plan.md`
**Interfaces:**
- Consumes: Task 1 的固定开发总结章节和 Task 2 模板。
- Produces: 与实际代码、依赖版本、范围变化和测试结果一致的功能档案。
- [x] **Step 1: 对照 Git diff 更新实际完成事实**
`development-summary.md` 必须逐条列出 FR-001 至 FR-010 的实际状态;原始需求和需求变化分别记录。明确写出:当前页面仍未接入健康 API、AI Provider 未实现、后端现有健康模块没有为目录外观迁移。
同时把已批准档案的章节标题规范化为 Task 1 的门禁标题:设计使用 `安全策略与评估`、`性能目标与评估`,测试计划使用 `安全验证`、`性能验证`,GitNexus 影响计划使用 `直接与间接影响`、`跨模块同步修改`。只调整标题和组织,不改变用户已经批准的结论。
- [x] **Step 2: 完成安全与依赖评估**
在设计和总结中记录 Axios 1.19.0、MIT、官方来源、锁文件、替代方案、前端体积增量、维护状态和可回退到原生 fetch 的退出方式。运行:
```bash
pnpm audit --prod
git diff --check
git status --short
```
若 audit 报告风险,先按可利用性和影响评估,Important 以上不得进入 passed Review;不得为了清零数字盲目升级无关依赖。
- [x] **Step 3: 完成性能证据**
构建后记录实际 JS/CSS 文件字节数,与 Task 3 基线 `163908/805` 比较;确认 request 没有默认重试,默认超时为 10 秒。治理校验只在开发/发布路径运行,不做生产负载测试,并在“不适用”结论中写清边界。
- [x] **Step 4: 更新清单与发布说明**
`manifest.yaml` 状态改为 `verifying`,保留 `release: unreleased`。`release-notes.md` 说明治理门禁、架构规范和 Axios 迁移,不宣称市场概览、AI 或用户功能已完成。
- [x] **Step 5: 校验档案内容**
Run:
```bash
npm run test:governance
pnpm exec prettier --check docs/features/GOV-010-development-quality-architecture
git diff --check
```
Expected: PASS,且开发总结不存在空章节或无解释占位词。
- [x] **Step 6: 检测变化并提交推送**
Run GitNexus `detect_changes(scope="all")`,然后:
```bash
git add docs/features/GOV-010-development-quality-architecture
git commit -m "docs(GOV-010): 记录开发需求与完成结果"
git push origin main
```
---
### Task 6: 全量验证、视觉回归与 GitNexus 对比
**实施状态:已完成。** 全量契约、lint、格式、类型、测试、构建、E2E、源码发布、audit、视觉截图和 GitNexus compare 证据已写入 `qa/` 与 `gitnexus/`。
**Files:**
- Create: `docs/features/GOV-010-development-quality-architecture/qa/test-results.md`
- Create: `docs/features/GOV-010-development-quality-architecture/qa/visual-qa.md`
- Create: `docs/features/GOV-010-development-quality-architecture/gitnexus/detected-changes.md`
- Create: `docs/features/GOV-010-development-quality-architecture/gitnexus/comparison.md`
- Create or update: `docs/features/GOV-010-development-quality-architecture/gitnexus/after.md`
- Create: `docs/features/GOV-010-development-quality-architecture/screenshots/iterations/app-shell-desktop-1440x900-<sha>.png`
- Create: `docs/features/GOV-010-development-quality-architecture/screenshots/iterations/app-shell-mobile-390x844-<sha>.png`
**Interfaces:**
- Consumes: Tasks 1-5 的完整实现和档案。
- Produces: 最新、可复现的测试、安全、性能、视觉和 GitNexus 证据。
- [x] **Step 1: 执行全量非浏览器验证**
Run:
```bash
pnpm check:contracts
pnpm lint
pnpm format:check
pnpm typecheck
pnpm test
pnpm build
```
Expected: 全部退出码 0。任何失败先按 systematic-debugging 查根因并修复,不能只在报告中标记忽略。
- [x] **Step 2: 检查构建产物和敏感信息**
Run:
```bash
wc -c web/dist/assets/*.js web/dist/assets/*.css
rg -n "MYSQL_PASSWORD|AI_API_KEY|Root@|mysql://root:|Authorization: Bearer" web/dist || true
pnpm audit --prod
```
Expected: 构建产物不含敏感标记;记录实际包体增量和 audit 结论。
- [x] **Step 3: 执行浏览器与源码发布验证**
确认本机 Redis 可用后运行:
```bash
pnpm verify:e2e
pnpm verify:release
```
Expected: 桌面和移动 Chromium 均通过,API 健康契约通过,源码部署门禁通过;不启动 Docker 或替代基础设施。
- [x] **Step 4: 保存同视口视觉证据**
使用 Playwright 截取 1440x900 和 390x844 的应用外壳;检查页面可见、无横向溢出、无控制台 error/warning、标题和主内容不重叠。因为本次不改 UI,视觉结论应为“无可观察回归”,而不是宣称新增页面设计。
- [x] **Step 5: 运行 GitNexus 开发后检测**
Run:
```bash
npx gitnexus analyze
npx gitnexus status
```
调用 `gitnexus_detect_changes(scope="compare", base_ref="1c1b15e")`,记录变更符号、执行流、风险和工具限制。`comparison.md` 逐项对照开发前同步修改表,特别确认 HTTP 字段、RocketMQ、MySQL、Redis、Scheduler 和 Worker 未发生计划外变化。
- [x] **Step 6: 填写 QA 与 GitNexus 报告**
`test-results.md` 记录命令、时间、退出码、关键输出、Axios 依赖评估、安全扫描和包体数据;`visual-qa.md` 链接两张截图并记录视口与结论;`detected-changes.md` 和 `comparison.md` 不得只写“通过”。
- [x] **Step 7: 执行完成门禁的预检**
在 Review 尚未标记 passed 前,`governance:finish` 应明确只因 Review 或尚缺 Review 报告失败,不能因开发总结、安全、性能或影响章节失败。记录预检结果,但不要伪造 passed Review。
---
### Task 7: 双 Review、完成门禁与最终推送
**实施状态:已完成。** 两份自审报告最终结论均为 `passed`,最终门禁已通过;`f178fb4` 已提交并推送,收尾 GitNexus 统计另以文档提交记录。
**Files:**
- Create: `docs/features/GOV-010-development-quality-architecture/review/code-review.md`
- Create: `docs/features/GOV-010-development-quality-architecture/review/standards-review.md`
- Modify: all files implicated by Review findings
- Modify: `docs/features/GOV-010-development-quality-architecture/development-summary.md`
- Modify: `docs/features/GOV-010-development-quality-architecture/manifest.yaml`
- Modify: `docs/features/GOV-010-development-quality-architecture/qa/test-results.md`
- Modify: `docs/features/GOV-010-development-quality-architecture/gitnexus/*`
**Interfaces:**
- Consumes: 完整 Git diff、PRD、设计、实施计划、QA 和 GitNexus 证据。
- Produces: 两份 findings-first Review;只有 Critical 和 Important 全部关闭后才能以独占末行写 `最终结论:passed`。
- Produces: 通过 `governance:finish` 的 GOV-010 功能档案,但仍保持 `release: unreleased`,除非用户另行确认版本发布。
- [x] **Step 1: 使用代码 Review 流程审查实际实现**
按严重程度先列发现,检查请求错误脱敏、取消语义、类型边界、URL/HTTP 绕过、门禁误判、安全和性能证据、测试真实性。没有发现时明确写“未发现 Critical/Important/Minor”,并列残余风险和测试边界。
- [x] **Step 2: 使用规范 Review 逐条审查**
检查中文注释、文件拆分、真实重复后抽象、后端按需分层、Axios/API 分域、OpenAPI 类型、GitNexus 同步修改、开发总结、中文提交和 Gitea 推送。不得把模板勾选框直接当证据,需引用文件和命令。
- [x] **Step 3: 修复所有 Critical 和 Important**
每个修复先补失败测试并重跑受影响验证;更新 GitNexus 开发后报告和 Review 处置。Minor 可延期,但必须记录理由与后续功能编号。
- [x] **Step 4: 运行最终完整验证**
Run:
```bash
pnpm verify:release
npm run governance:finish -- GOV-010 development-quality-architecture
git diff --check
git status --short
```
Expected: 所有命令通过;`governance:finish` 验证独立开发总结、证据章节和双 Review。
- [x] **Step 5: 提交前 GitNexus 检测**
调用 `gitnexus_detect_changes(scope="all")`,确认实际影响与 `comparison.md` 一致;发现计划外进程时停止提交,先补设计、测试和用户风险说明。
- [x] **Step 6: 中文提交并立即推送**
```bash
git add AGENTS.md CHANGELOG.md docs tools web server/openapi/openapi.json pnpm-lock.yaml package.json
git commit -m "feat(GOV-010): 完成开发质量与架构治理"
git push origin main
```
不使用 `git add .`,避免把本地 env、索引或无关文件纳入提交。推送后核对:
```bash
git rev-parse HEAD
git ls-remote origin refs/heads/main
npx gitnexus status
```
Expected: 本地与远程 main SHA 一致;GitNexus 若因最终提交过期,运行 `npx gitnexus analyze`,单独以中文文档提交更新最终统计并再次推送。
- [x] **Step 7: 保持未发布状态**
GOV-010 完成开发和 Review 后可将 `manifest.yaml` 状态设为 `reviewing` 或 `approved_for_release`(若现有状态机不支持后者则保持 `reviewing`),但 `release` 继续为 `unreleased`,不创建 `v0.0.8` 或更高标签。版本发布仍需结合 GOV-009 架构复核和用户后续确认。
@@ -0,0 +1,19 @@
id: GOV-010
name: 开发质量与前后端架构规范
slug: development-quality-architecture
status: released
owner: project
created_at: 2026-08-13
prd: prd.md
requirements: requirements.md
design: design.md
implementation_plan: implementation-plan.md
test_plan: test-plan.md
development_summary: development-summary.md
gitnexus_before: gitnexus/before.md
gitnexus_impact: gitnexus/impact-plan.md
gitnexus_after: gitnexus/after.md
gitnexus_comparison: gitnexus/comparison.md
code_review: review/code-review.md
standards_review: review/standards-review.md
release: v0.0.8
@@ -0,0 +1,113 @@
# 开发质量与前后端架构规范 PRD
- 功能编号:GOV-010
- PRD 版本:0.1
- 状态:approved
- 日期:2026-08-13
## 背景与问题
现有仓库已经建立 PRD、GitNexus 双门禁、测试、Review、中文提交和 Gitea 推送流程,但安全与性能检查仍偏原则化,开发总结没有独立强制文件,GitNexus 开发前报告也没有强制回答跨模块同步修改问题。前后端基础工程已经能够运行,但后端业务模块的分层方式、前端 Axios 请求封装和 API 分域方式尚未成为可执行规范。
若仅补充文字约定,新功能仍可能遗漏安全边界、性能目标、关联模块修改和实际完成情况;若过早强制所有模块创建固定目录,又会产生无意义的透传层和碎片化文件。因此需要在可自动验证的关键证据与按实际职责演进的代码结构之间建立边界。
## 目标用户与使用场景
- 项目开发者在开始功能或缺陷修复前,能够识别直接、间接和跨进程影响。
- 实现者在设计、编码和验证阶段持续检查安全与性能,而不是在发布前临时补结论。
- Review 者能够从独立开发总结中核对原始需求、需求变化、完成项、缺陷和验证证据。
- 前端开发者使用统一 Axios 封装和业务域 API 文件,不在页面中散落请求细节。
- 后端开发者以业务模块为一级边界,在模块内部按真实职责分层。
## 产品目标
- 将安全、性能、跨模块影响和同步修改分析纳入功能全生命周期。
- 为每个功能档案增加独立且强制的 `development-summary.md`。
- 建立可阅读、可演进、不过度拆分的前后端架构规则。
- 用模板、测试和完成门禁验证关键要求,避免规范只停留在文字层面。
- 将现有前端请求客户端脚手架迁移到 Axios,并补充健康 API 分域样例,使基础代码在新规范生效时立即合规。
## 非目标
- 不实现市场概览业务功能、用户体系、付费、会员或订阅。
- 不实现后端 AI Provider;兼容 OpenAI API 的 AI 接入继续作为独立后端功能规划。
- 不为每个后端模块强制生成完整目录树。
- 不引入全局 Controller 或 Service 目录。
- 不照搬 RuoYi 的弱类型 Axios 示例或 `any` 参数。
- 不在本功能中变更 HTTP 接口业务字段、数据库结构、Redis 数据、RocketMQ 契约或生产部署方式。
## 用户流程
1. 开发者完成上一发布版本的开发库 Schema 基线门禁。
2. 运行 `governance:start` 刷新 GitNexus,并记录功能、模块、进程和契约影响。
3. 在设计和测试计划中明确安全策略、残余风险、性能目标和验证方法。
4. 按前后端架构边界实施,以失败测试驱动行为变化。
5. 开发后运行验证和 GitNexus 变更检测,填写独立开发总结。
6. 代码 Review 与规范 Review 核对需求完成度、安全、性能、同步修改和架构边界。
7. `governance:finish` 对必备文件和必填证据执行门禁。
## 功能需求
| 编号 | 优先级 | 需求 | 可观察结果 |
|---|---|---|---|
| FR-001 | Must | 开发前评估功能和缺陷的直接、间接及跨模块影响 | 影响计划明确列出受影响消费者、执行流、风险和同步修改清单 |
| FR-002 | Must | 对代码安全进行完整策略设计与评估 | 设计、测试和 Review 均有适用的安全结论、证据与残余风险 |
| FR-003 | Must | 对性能目标和风险进行设计与验证 | 设计包含目标和风险,测试计划包含与风险相称的验证方法 |
| FR-004 | Must | 独立记录开发总结 | 每个新功能档案包含通过结构校验的 `development-summary.md` |
| FR-005 | Must | 后端按业务模块垂直组织并在模块内按需分层 | Review 能从目录、依赖和职责证明模块边界合理且没有凑目录 |
| FR-006 | Must | 前端使用统一 Axios 封装和业务域 API 文件 | 页面、组件和 Store 无直接 Axios、fetch 或 URL 拼接 |
| FR-007 | Must | 保留 OpenAPI 生成类型 | Axios API 函数使用由后端 OpenAPI 生成的 TypeScript 请求或响应类型 |
| FR-008 | Must | 只在出现真实重复后抽取工具或组件 | Review 记录抽取依据,或说明代码尚不足以形成稳定复用边界 |
| FR-009 | Must | 新增依赖先完成评估 | 设计记录用途、替代方案、安全、体积、维护和退出风险 |
| FR-010 | Must | 自动化阻断缺证据的完成声明 | 缺文件、空章节、无理由“不适用”或未通过 Review 时门禁失败 |
## 数据与口径
本功能不处理行情或用户数据。治理数据以功能编号为主键,以 Git 提交、GitNexus 报告、测试输出和 Review 记录为证据来源。`development-summary.md` 记录实际完成事实,不替代 PRD、设计、发布说明或 Git 历史。
## 状态与异常
- GitNexus 索引过期时必须先重新分析,再生成影响计划。
- GitNexus MCP 依赖遍历返回 `partial` 或不可用时,必须记录限制,并以符号上下文、执行流、静态引用和 Git diff 交叉验证,不能将零结果解释为无影响。
- 安全或性能不适用时必须给出具体原因和适用边界;空白、`无`、`不涉及`等无解释内容不能通过。
- HIGH 或 CRITICAL 影响必须在编辑前告知用户并取得确认。
- Axios 请求错误必须转换为稳定错误,不得把内部地址、凭据或上游原始错误直接展示给用户。
## 权限、合规与安全
- 治理检查只读取仓库和开发环境证据,不触碰生产数据库或生产配置。
- 前端不得获得 AI、数据库、Redis、RocketMQ 或数据源密钥。
- Axios 日志和错误不得泄露请求头、凭据、内部地址或敏感响应。
- 新增依赖必须核对来源、维护状态、许可证、已知风险和锁文件变化。
## 成功指标
- 新功能档案缺少开发总结或必填章节时,自动化测试稳定失败。
- 前端直接从页面、组件或 Store 使用 Axios/fetch 时,边界校验稳定失败。
- 健康 API 样例经 Axios API 分域层完成,类型检查、测试和构建通过;现有页面虽然尚未消费健康接口,仍需完成视觉回归以证明迁移没有旁路影响。
- 两类 Review 均能引用安全、性能、GitNexus 同步修改和开发总结证据。
## 验收标准
- Given 一个缺少 `development-summary.md` 的功能档案,When 执行完成门禁,Then 门禁明确指出缺失文件。
- Given 开发总结缺少原始需求、完成需求、修复缺陷或验证证据,When 执行结构校验,Then 校验失败并指出缺失章节。
- Given 安全或性能章节写成无解释的“不适用”,When 执行结构校验,Then 校验失败。
- Given Vue 页面直接导入 Axios 或调用 `fetch`,When 执行项目边界校验,Then 校验失败。
- Given 业务 API 文件调用统一 request 封装,When 执行边界校验与类型检查,Then 校验通过。
- Given 健康检查发生网络或后端错误,When 前端请求失败,Then 调用者收到脱敏且可分类的稳定错误。
- Given 一个小型后端模块只有 Controller 与 Service,When 其不存在 Repository 或 Adapter 职责,Then Review 不要求创建空目录或透传层。
## 风险与依赖
- 严格内容校验可能误伤合理的“不适用”,因此模板提供说明格式,校验只要求理由和边界,不按关键词判断业务结论。
- Axios 迁移会改变请求返回与错误对象,需要测试锁定业务 API 只返回 DTO、不泄漏 `AxiosResponse`。
- OpenAPI 生成类型与 Axios 的泛型需要建立明确映射,避免恢复手写重复 DTO。
- 架构规则若全部交给目录 lint 会过度僵化,因此后端职责分层主要由 Review 执行,前端 HTTP 边界则适合自动校验。
## 发布范围与回退触发条件
本次发布包含规范、模板、治理校验、边界测试及现有前端请求层迁移。若门禁阻断合法功能且不能通过补充明确证据解决,或 Axios 迁移导致现有健康页面行为回归,则整体回退 GOV-010 代码与规范提交;不修改已发布历史档案。
## 变更记录
- 2026-08-13:根据用户确认建立初版,明确独立开发总结、后端模块内分层、Axios 封装和自动门禁。
@@ -0,0 +1,50 @@
# GOV-010 测试与质量证据
- 功能编号:GOV-010
- 验证提交:`61f85e5`
- 验证日期:2026-08-13
## 全量命令
以下命令按顺序执行,均退出码为 0:
| 命令 | 结果 | 关键证据 |
|---|---|---|
| `pnpm check:contracts` | passed | OpenAPI 与生成 TypeScript 契约无漂移;项目边界验证通过 |
| `pnpm lint` | passed | Web 与 Server ESLint 无错误 |
| `pnpm format:check` | passed | 全仓 Prettier 格式通过 |
| `pnpm typecheck` | passed | Web、Vite 配置和 Server TypeScript 检查通过 |
| `pnpm test` | passed | runtime 2、governance 9、MySQL 2、环境 10、Schema 28、contracts 3、boundaries 16、deployment 6、Web 11、Server 30 + API 预检 2 |
| `pnpm build` | passed | Web Vite 构建;API、Scheduler、Worker 三进程 Nest 构建 |
| `pnpm verify:e2e` | passed | Chromium 桌面和移动 4/4 通过 |
| `pnpm verify:source` | passed | 源码发布产物与 systemd/Nginx 配置通过 |
## 安全验证
- `redis-cli -h 127.0.0.1 -p 6379 ping` 返回 `PONG`;只验证开发机本地 Redis 可达,不读取生产配置或数据。
- 构建产物扫描 `MYSQL_PASSWORD|AI_API_KEY|Root@|mysql://root:|Authorization: Bearer` 未发现匹配。
- 修复前官方 npm audit 发现 `server>@nestjs/swagger>js-yaml@5.2.1` 的 GHSA-pm4m-ph32-ghv5 High 拒绝服务漏洞;`@nestjs/swagger@11.4.6` 仍精确依赖 5.2.1。
- 提交 `e992edc` 使用 pnpm 项目级精确 override 将 `@nestjs/swagger>js-yaml` 固定到修复版本 `5.2.2`。`pnpm why js-yaml --prod -r` 和解析路径检查均确认实际版本 5.2.2。
- 修复后 `pnpm audit --prod --registry=https://registry.npmjs.org/` 返回 `No known vulnerabilities found`。
- 取消请求、网络错误和 HTTP 错误脱敏由 `web/src/utils/request.test.ts` 覆盖;错误不保留原始 URL、请求头、响应正文或连接串。
- 本功能不新增认证 Cookie、远程 HTML、动态 SQL、服务端 URL 抓取或生产数据库访问,因此 CSRF、XSS、SQL 注入和 SSRF 的运行攻击测试不适用;后续触及这些边界必须重新评估。
## 性能验证
- Web 构建基线(Axios 迁移前):JS `163908` 字节,CSS `805` 字节。
- 当前 Web 构建:`web/dist/assets/index-BjClxDN-.js` `163908` 字节,`web/dist/assets/index-13WJH6XV.css` `805` 字节;本次页面未接入健康 API,产物体积无增量。
- `request.ts` 默认超时为 10 秒,不启用自动重试;测试覆盖超时配置和取消语义。
- 治理与边界扫描只在开发/发布验证运行,不进入线上请求路径;当前仓库规模不需要负载测试。市场查询、MySQL 索引、Redis TTL、RocketMQ 吞吐、Worker 并发和图表渲染均未被本功能改变,后续业务功能需单独设定目标。
## 视觉与构建附加证据
- 桌面截图:`screenshots/iterations/app-shell-desktop-1440x900-61f85e5.png`,实际浏览器 DOM 视口 1440×900。
- 移动截图:`screenshots/iterations/app-shell-mobile-61f85e5.png`,实际浏览器 DOM 视口 390×844。
- 两个视口均有可见 `main` 和页面标题,无横向溢出;浏览器错误/警告日志为空。截图只证明本次请求基础设施迁移没有造成外壳回归,不代表市场概览 UI 已实现。
## v0.0.8 发布封存验证(2026-08-17)
- GOV-009 与 GOV-010 完成门禁均通过;`pnpm verify:release` 以 Node.js 22.22.0、pnpm 10.25.0 完整通过。
- 最终计数为治理 10、MySQL 2、环境 10、Schema 28、契约 3、边界 16、部署 6、Web 11、Server 30、API 预检 2、Playwright 4,全部通过且无失败。
- Web 与 API/Scheduler/Worker 构建、源码产物、systemd/Nginx 一致性均通过;本次仅改变发布文档和状态,不改变 Axios、OpenAPI 或后端运行行为。
- 安全边界与 2026-08-13 Review 一致:不访问生产配置或数据库,不输出凭据,不写入 Redis/MySQL,不启用 RocketMQ 收发。
@@ -0,0 +1,19 @@
# GOV-010 视觉回归记录
- 功能编号:GOV-010
- 页面:应用基础外壳
- 结论:无可观察回归
## 桌面
- E2E 与实际浏览器截图视口:Chromium 1440×900,`verify:e2e` 通过。
- 截图:[app-shell-desktop-1440x900-61f85e5.png](/Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis/docs/features/GOV-010-development-quality-architecture/screenshots/iterations/app-shell-desktop-1440x900-61f85e5.png)
- 检查:标题“ A 股市场分析工具 ”可见,`main` 可见,无横向溢出,无控制台 error/warning。
## 移动
- E2E 目标视口:Chromium 390×844,`verify:e2e` 通过。
- 截图:[app-shell-mobile-61f85e5.png](/Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis/docs/features/GOV-010-development-quality-architecture/screenshots/iterations/app-shell-mobile-61f85e5.png)
- 检查:标题和 `main` 可见,无横向溢出,无控制台 error/warning。
截图底部可能出现浏览器容器黑色区域,不属于页面 DOM;页面断言以实际 viewport、DOM 和 E2E 结果为准。本次没有修改页面布局或交互,因此结论是“无可观察回归”,不是新增市场概览设计验收。
@@ -0,0 +1,24 @@
# GOV-010 发布说明
- 状态:已随 `v0.0.8` 发布
- 发布日期:2026-08-17
## 新增
- 新功能档案必须提供独立开发总结,以及安全、性能、GitNexus 同步修改和 Review 证据。
- 前端新增统一 Axios 请求封装和 `api/<业务域>/index.ts` 分域边界,健康 API 作为类型化样例。
- 项目边界校验可阻断运行时代码绕过统一 request 直接使用 Axios、fetch 或业务 API URL。
## 调整
- 后端正式采用业务模块为一级目录、模块内部按真实职责分层的规范,不要求空目录或透传层。
- 前端继续使用 OpenAPI 生成 TypeScript 类型,但 HTTP 执行器由 `openapi-fetch` 调整为 Axios 1.19.0。
- 开发流程要求功能和缺陷修复在编码前评估跨功能、跨模块和跨进程同步修改,完成后记录实际需求、缺陷、安全、性能与 GitNexus 证据。
## 安全修复
- 将 `@nestjs/swagger` 精确依赖的 `js-yaml` 从存在 GHSA-pm4m-ph32-ghv5 的 5.2.1 覆盖到修复版本 5.2.2;不改变 Swagger 或 OpenAPI 业务契约。
## 范围说明
本变更不实现市场概览、AI Provider、用户、会员或订阅功能,不改变 HTTP 业务字段、MySQL Schema、Redis、RocketMQ、API/Scheduler/Worker 行为或 Ubuntu 源码部署方式。当前页面仍未消费健康 API。
@@ -0,0 +1,72 @@
# 工程需求
## R1 GitNexus 开发前影响分析
- 功能和缺陷修复使用同一套开发前门禁,不得以“仅修 Bug”为由跳过。
- 分析必须覆盖相关概念查询、关键符号上下文、上游影响、直接与间接消费者、受影响执行流和风险等级。
- 必须逐项判断 HTTP/OpenAPI、Web API 与适配器、消息契约、数据库迁移与 Schema、Redis、Scheduler、Worker、环境与部署、测试和文档是否需要同步修改。
- HIGH 或 CRITICAL 结果必须在编辑前报告用户;`partial`、索引过期或工具不可用必须说明限制并补充交叉证据。
- 开发后 `detect_changes` 必须比较计划影响与实际影响,计划外变化必须解释、补设计或回退。
## R2 安全设计与评估
- 每个功能在 `design.md` 中识别资产、数据、信任边界、攻击面、缓解措施和残余风险。
- 按适用性检查认证授权、输入校验、SQL/命令/模板注入、XSS、CSRF、CORS、SSRF、限流、凭据、敏感数据、日志、错误、依赖供应链、数据保留和滥用场景。
- AI 与外部数据源还需检查提示词与事实边界、密钥隔离、上游内容、超时重试、成本和不可用降级。
- `test-plan.md` 必须给出安全验证方法;代码 Review 必须记录实际证据和未消除风险。
- 不适用项必须说明“不适用于什么、为什么、适用边界是什么”,禁止用空白或无解释短语通过。
## R3 性能设计与评估
- 每个功能说明延迟、吞吐、数据新鲜度或资源预算中适用的目标。
- 按适用性评估数据量与算法复杂度、MySQL 查询和索引、N+1、Redis 目的/TTL/一致性/击穿、分页和响应体、前端包体/渲染/长列表/图表、Scheduler/Worker 并发/幂等/背压、外部数据源与 AI 的超时/重试/批处理/成本。
- 高风险路径必须提供 benchmark、profile 或负载测试证据;普通文档或低频管理逻辑可说明无需负载测试的理由。
- 性能优化不得牺牲数据口径、可观察性、安全或 MySQL 5.7 兼容性。
## R4 独立开发总结
- 每个新功能档案必须有独立 `development-summary.md`,不得合并到 `release-notes.md`。
- 必备章节为原始开发需求、需求与范围变化、实际完成需求、修复缺陷、未完成与延期项、关键提交、验证证据。
- 没有缺陷时也要写明本次未修复缺陷及判断依据;不能删除该章节。
- 开发总结描述实际完成事实,PRD 描述目标,发布说明面向版本使用者,三者职责不得混淆。
- `governance:finish` 必须验证文件存在、非空和必备章节有效。
## R5 后端模块架构
- 后端以业务模块为一级目录,模块内部按实际职责建立 `controllers`、`services`、`dto`、`domain`、`repositories`、`adapters`、`types`、`utils`。
- 小模块不强制凑齐目录;没有独立职责时不得增加只做转发的层。
- Controller 只负责 HTTP 协议、边界参数和响应;Service 编排用例;Domain 保存纯业务规则与模型;Repository 描述持久化端口;Adapter 实现 MySQL、Redis、RocketMQ 和外部数据源边界。
- DTO、领域模型和数据库实体必须分离;基础设施实现依赖领域端口,领域不得反向依赖 NestJS、TypeORM、Redis 或 RocketMQ SDK。
- 禁止在应用级全局目录堆放全部 Controller 或 Service;跨模块共享只在出现稳定复用边界后进入 `libs`。
- 后端架构参考 RuoYi 的职责清晰性与优秀 NestJS 模块实践,不照搬 Java 分层或制造形式化目录。
## R6 前端请求与模块架构
- 前端实际 HTTP 请求统一使用 Axios,`web/src/utils/request.ts` 是唯一 Axios 实例、拦截器和通用错误处理入口。
- 所有业务接口放在 `web/src/api/<业务域>/index.ts`,API 文件调用统一 request,不自行创建 Axios 实例。
- 页面、组件、Composable 和 Store 禁止直接导入 Axios、调用 `fetch`、拼接业务 URL 或依赖 `AxiosResponse`。
- 保留 `openapi-typescript` 和 `web/src/api/generated/schema.ts`;生成类型是 HTTP 契约来源,API 函数不得以 `any` 取代可用的生成类型。
- API 函数向调用者返回类型化 DTO 或明确业务结果,不把 Axios 库类型扩散到功能层;DTO 到 ViewModel 的转换位于对应功能适配层。
- request 封装统一处理 base URL、超时、请求头、取消信号、网络错误、HTTP 错误和后端标准错误;认证刷新暂不实现,只保留可测试扩展点。
## R7 抽象与依赖治理
- 重复代码或功能只有在至少出现真实复用、职责稳定且抽取能降低维护风险时才进入工具、组件或公共模块。
- 仅名称相似、预判未来复用或减少文件行数,不构成抽取依据。
- 新依赖安装前必须在设计中记录用途、现有替代、版本、维护状态、安全与许可证、前端体积或服务端运行成本和退出方式。
- 本次使用 Axios 替代 `openapi-fetch`,保留 `openapi-typescript`;两者用途必须在规范和架构文档中区分。
## R8 自动门禁与 Review
- 治理工具必须用测试先行补充必备文件与章节校验。
- 安全、性能、影响分析、同步修改和开发总结证据必须进入代码 Review 与规范符合性 Review 模板。
- 自动校验必须覆盖缺文件、空内容、缺章节、无解释不适用和未通过 Review;不得用难以维护的业务关键词判断结论真伪。
- 前端边界校验必须基于 TypeScript/Vue 语法结构检查导入和调用,避免简单字符串扫描被注释或别名绕过。
- 后端按需分层不能由固定目录清单强制,交由架构规范和结构化 Review 检查。
## R9 兼容与非功能约束
- 不修改现有 HTTP OpenAPI 业务结构、RocketMQ 消息结构或数据库 Schema。
- 继续遵守 Node.js 22、pnpm 10、MySQL 5.7.42、`utf8mb4_general_ci`、源码部署和项目专用 Gitea 约束。
- 前端 Axios 迁移必须保持健康页可观察行为、脱敏错误、类型检查和生产构建不回归。
- AI 兼容 OpenAI API 是后端 Provider 协议要求,与本次前端 Axios 请求封装相互独立。
@@ -0,0 +1,63 @@
# GOV-010 代码 Review
- 功能编号:GOV-010
- reviewer_type:self
- reviewer:实现代理结构化自审
- 基线提交:`1c1b15e`
- 审查提交:工作区当前变更,基于已推送 `61f85e5` 加上待提交的 Review 修复
- 日期:2026-08-13
## 审查范围
审查 PRD、设计、实施计划、37 个代码/配置变更文件、开发总结、QA、GitNexus 报告及回退说明。重点覆盖 Axios 错误边界、AST HTTP 门禁、治理证据门禁、依赖安全、OpenAPI 契约和测试真实性。
## 发现
### 已关闭的重要问题
| 严重程度 | 位置 | 问题 | 影响 | 处理 |
|---|---|---|---|---|
| Important | `tools/governance/feature-record.mjs:getUnpassedReviewFiles` | 原实现只要文档任意位置出现 `最终结论:passed` 就会通过,后续追加 `changes_required` 可绕过完成门禁。 | 可能发布未通过 Review 的功能,属于治理安全缺口。 | 先新增失败测试复现,再改为只接受最后一个非空行精确等于 `最终结论:passed`;治理测试由 9 项增至 10 项并全部通过。 |
### 当前未发现的问题
未发现 Critical、未关闭的 Important 或阻塞性 Minor。请求层没有把原始 Axios error、URL、请求头或响应正文放入错误对象;取消请求保留 Axios cancel 语义;业务 API 使用生成 DTO;页面和 Store 没有直接 HTTP 调用。
## 测试缺口
当前页面尚未消费健康 API,因此没有真实页面数据适配链路测试;这属于本次明确非目标。Axios 运行时响应 Schema 校验也未引入,后续高风险市场接口应按数据风险决定是否增加。治理扫描、构建和 E2E 已覆盖当前变更边界。
## 安全与残余风险
- 统一 request 将网络/HTTP 错误转换为固定中文消息,只保留分类和数字状态码;取消错误不被误报为服务故障。
- 官方 audit 曾发现 `js-yaml 5.2.1` High 漏洞,已由 `e992edc` 精确覆盖到 `5.2.2`,修复后 audit 为 0 vulnerabilities。
- AST 边界阻止运行时代码绕过 Axios/request 约定,但静态门禁不替代人工审查,也不做运行时响应校验;这些是已记录的残余风险。
## 性能与资源影响
- Web JS/CSS 产物与迁移前基线均为 163908/805 字节;默认超时 10 秒且无自动重试,避免行情刷新请求放大。
- Axios 增加依赖维护成本,但统一拦截器、取消和错误边界;本次不改变数据库、缓存、消息或 Worker 吞吐。
- 生产构建、全量测试和 E2E 均通过;当前治理扫描只在开发/发布命令执行。
## GitNexus 与同步修改
开发后重新索引为 1,827 nodes、2,502 edges、50 flows;相对 `1c1b15e` compare 为 35 文件、163 符号、1 条受影响执行流、MEDIUM。唯一运行流是 `CreateRequestClient → ApiRequestError`,与计划一致;边界校验 MEDIUM 变化只在开发门禁执行。逐项核对确认 HTTP/OpenAPI 字段、MySQL、Redis、RocketMQ、API/Scheduler/Worker、部署均无计划外变化。
## 修复与复审
- `e992edc`:修复 `js-yaml` 传递依赖漏洞,已推送 Gitea。
- 待提交修复:Review 结论必须位于最后一个非空行,失败测试和通过测试均已执行。
- 修复后未发现新的 Critical/Important;最终完整验证、E2E、audit、契约和格式证据仍有效,Review 报告创建后再运行完成门禁。
## 最终结论
最终结论:passed
## v0.0.8 发布封存复核
- 复核日期:2026-08-17
- 本次只把已完成并通过 Review 的 GOV-010 归入 `v0.0.8`,没有修改 Axios 请求行为、OpenAPI 契约、后端分层代码或依赖版本。
- 安全与性能结论没有变化:错误脱敏、有限超时、无自动重试、传递依赖修复和包体证据继续有效;本次文档状态变化不引入运行时资源开销。
- GitNexus 影响仅为发布追溯文档;HTTP/OpenAPI、MySQL、Redis、RocketMQ、API、Scheduler、Worker 和部署无需同步修改。
最终结论:passed
@@ -0,0 +1,48 @@
# GOV-010 开发规范符合性 Review
- 功能编号:GOV-010
- reviewer_type:self
- reviewer:实现代理结构化自审
- 审查提交:工作区当前变更,基于已推送 `61f85e5` 加上待提交的 Review 修复
- 日期:2026-08-13
## 检查结果
- [x] 必要中文注释准确且没有逐行废话注释。
- [x] 文件按稳定职责拆分,适合连续阅读,没有过度碎片化。
- [x] 命名、类型、单位和时间语义明确。
- [x] 错误处理、日志、脱敏和降级符合规范。
- [x] 安全策略、性能目标、验证证据和残余风险完整。
- [x] 前端 Axios/API 分域与后端业务模块内按需分层符合规范。
- [x] 复用抽取基于真实重复,新增依赖已完成用途、安全、许可证、成本和退出评估。
- [x] 测试先行证据、构建和视觉验证齐全。
- [x] GitNexus 开发前后报告和实际变更检测齐全。
- [x] GitNexus 已评估其他功能、模块和所需同步修改,实际变化符合计划。
- [x] 独立开发总结完整记录需求、范围变化、完成项、缺陷、延期项、提交和验证证据。
- [x] PRD、设计、发布说明和回退说明一致。
- [x] 提交使用中文 Conventional Commit 并关联功能编号。
- [x] 未使用 GitHub,未擅自配置或推送远程仓库。
## 不符合项与处置
初审发现 Review 最终结论校验允许“passed”出现在正文中间,已按测试先行修复为最后非空行校验;没有遗留不符合项。历史已发布档案未改写;在本次审查时 GOV-010 保持 `unreleased`。
## 安全、性能与架构检查
安全:Axios 错误脱敏、传递依赖 High 漏洞修复、构建产物敏感标记扫描和官方 audit 均有证据。性能:请求无自动重试、10 秒有限超时、包体已测量;不适用的行情/数据库/消息负载项均记录了边界。后端规范采用业务模块内按需分层,不创建空目录;前端 request 独占 Axios,业务 API 分域并使用 OpenAPI 生成类型。
## GitNexus 与开发总结检查
`gitnexus/before.md`、`impact-plan.md`、`detected-changes.md`、`after.md` 和 `comparison.md` 已互相对应;最新 compare 为 MEDIUM、163 变更符号、1 条预期请求执行流。`development-summary.md` 七个固定章节均有实际内容,并明确当前页面、AI Provider、市场业务和后端健康模块的未实施边界。治理测试 10/10 通过,完成门禁将在本报告最终结论落在末行后执行。
## 最终结论
最终结论:passed
## v0.0.8 发布封存复核
- GOV-009 架构确认门禁已于 2026-08-17 满足,GOV-010 的 `released/v0.0.8` 状态与开发总结、发布说明和 CHANGELOG 一致。
- 原 Review 中 `unreleased` 是确认前的真实历史状态;本节记录后续发布决定,不反向改写当时审查事实。
- 最终完成门禁、全量源码发布验证、GitNexus 变更检测、中文提交、Gitea 分支推送和精确标签推送按发布流程重新执行。
最终结论:passed
@@ -0,0 +1,22 @@
# 回退说明
GOV-010 不修改数据库结构或数据,不操作 Redis,不创建 RocketMQ Topic,也不触碰生产配置。回退对象仅包括规范、模板、治理校验、前端边界规则、Axios 请求实现和依赖锁文件。
## 代码回退
- 使用中文 Conventional Commit 新建回退提交,禁止重写 Gitea 历史、强推或移动既有标签。
- 整体回退时同时恢复 `openapi-fetch` 依赖、旧请求客户端、调用方、测试和锁文件,避免请求实现与规范不一致。
- 若只回退治理内容,必须同时回退新增必备文件、章节校验、模板和 Review 检查项,不能留下无法满足的门禁。
- 已经按 GOV-010 建立的功能档案与开发总结属于历史证据,不删除;规则回退通过后续治理记录说明。
## 验证
- 回退后重新执行 OpenAPI 生成、项目边界测试、Web 单元测试、类型检查、构建和 Playwright 回归。
- 执行 `governance:finish` 相关测试,确认门禁清单与模板一致。
- 运行 GitNexus 变更检测并记录回退实际影响。
## 触发条件
- Axios 迁移导致现有健康页面请求、错误处理或生产构建无法恢复。
- 新门禁持续阻断具有充分证据的合法功能,且无法通过修正规则消除误判。
- 前端边界校验产生无法接受的 Vue/TypeScript 误报。
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

@@ -0,0 +1,61 @@
# 测试计划
## 1. 治理门禁测试
- 验证新功能档案必须包含独立 `development-summary.md`。
- 验证开发总结缺少任一必备章节、章节正文为空或只有无解释占位词时失败。
- 验证设计、测试计划、GitNexus 影响计划和两类 Review 的安全、性能、同步修改证据校验。
- 验证有具体理由与边界的“不适用”可以通过,防止强迫所有功能执行无意义负载或攻击测试。
- 验证错误输出包含文件和章节,便于开发者修复。
## 2. 前端边界测试
- 拒绝 API 目录外直接导入 `axios`、创建 Axios 实例或调用全局 `fetch`。
- 拒绝业务 API 文件自行创建 Axios 实例或绕过 `@/utils/request`。
- 允许 `utils/request.ts` 使用 Axios,允许 `api/<业务域>/index.ts` 调用统一 request。
- 覆盖 `.ts`、Vue `script`/`script setup`、动态导入和路径别名,避免简单字符串规则误判或漏检。
- 继续验证 Web 不依赖 Server 源码、内部 RocketMQ 消息不进入生成契约。
## 3. Axios 请求测试
- 基础 URL 去除重复斜线并正确请求 `/api/v1/health`。
- 成功响应只返回类型化 DTO,不暴露 `AxiosResponse`。
- 网络错误和 HTTP 错误转换为不泄漏地址、凭据和原始响应的稳定错误。
- `AbortSignal` 取消保持可识别的取消语义,不被当成普通服务故障。
- 默认超时有限且可测试;不启用自动重试。
- 健康 DTO 继续经 adapter 转换成现有 `HealthViewModel`,未知状态仍被拒绝。
## 4. 契约与架构验证
- 重新生成 OpenAPI 与前端类型,确认无非预期契约漂移。
- TypeScript 编译证明 Axios API 包装使用生成响应类型且无 `any` 回退。
- Review 检查后端规范采用业务模块内按需分层,没有要求空目录或透传层。
- Review 检查依赖方向、DTO/Domain/Entity 边界和新增依赖评估。
## 5. 安全验证
- 对错误样本植入数据库连接串、内网地址和伪密钥,断言用户错误不包含这些内容。
- 检查 Web 源码与构建产物不包含服务端配置键或密钥。
- 检查 Axios 来源、锁定版本、许可证与已知依赖风险;保存不含凭据的结果。
- Git diff 与秘密扫描确认没有 `.env`、Token、密码或生产数据。
- 本功能不引入认证 Cookie、远程 HTML、动态 SQL 或服务端 URL 抓取,因此 CSRF、XSS、SQL 注入和 SSRF 的运行攻击测试不适用;后续触及对应边界的功能必须重新评估。
## 6. 性能验证
- 比较迁移前后 Web 生产构建产物大小,记录 Axios 引入的实际增量。
- 验证请求封装没有默认重试和无上限超时。
- 治理工具在当前仓库运行一次并记录耗时;其不进入生产请求路径,不执行负载测试。
- 本功能不改变数据库查询、缓存读写、消息并发、行情计算或图表渲染,因此这些性能测试不适用;后续业务功能需各自提供目标和证据。
## 7. 全量验证
- `pnpm check:contracts`
- `pnpm lint`
- `pnpm format:check`
- `pnpm typecheck`
- `pnpm test`
- `pnpm build`
- `pnpm verify:e2e`
- `pnpm verify:release`
- 桌面与移动视口视觉截图和页面控制台检查。
- `gitnexus_detect_changes`、重新索引和前后对比。
@@ -0,0 +1,74 @@
# Node 与 MySQL 系列版本约束设计
- 功能编号:GOV-011
- 设计状态:已获用户方向确认,等待书面规格复核
- 日期:2026-08-17
## 设计决策
采用真实系列校验,而不是只改文案或增加最低补丁版本:Node.js 通过语义版本解析后要求 `major === 22`;MySQL 客户端、mysqldump 和服务端要求版本字符串满足 `5.7.<非负整数>`,允许 `-log` 等既有后缀。用户已明确选择完整 5.7.x,不设置 5.7.9 等最低补丁版本。
历史 QA、Schema manifest 和已发布功能档案中的 5.7.42、22.11.0、22.22.0 是真实验证事实,不改写。只有当前生效的代码注释、错误提示、架构规范和部署前置条件统一改为系列口径。
## 代码边界
### Node.js
`tools/runtime/verify-runtime.mjs` 已经只校验 Node 主版本 22,不需要修改生产判断。测试补充 22 系列内边界以及 21/23 拒绝,注释和当前文档明确写成 22.x。pnpm 继续按 10.x 校验,不属于本次变化。
### Schema 工具
`assertMysql57Metadata` 继续作为唯一 Schema 版本判断入口,但服务端正则从精确 5.7.42 收敛为与两个客户端相同的 5.7.x 规则。历史真实/captured_empty manifest 仍保存实际版本并由同一入口验证;不改 manifest 格式,不重写历史目录。
### API 健康检查
`MysqlHealthClient.check` 接受 5.7.x,继续逐项校验目标库、`utf8mb4`、`utf8mb4_general_ci` 和 `+08:00`。成功详情使用查询返回的实际版本,例如 `MySQL 5.7.41 / a_share_analysis_dev / +08:00`;失败提示统一为“需要 MySQL 5.7.x”。
### 配置与 TypeORM
`MysqlRuntimeConfig` 和 `buildTypeOrmOptions` 没有版本字段或版本分支,只需把说明性注释由 5.7.42 修正为 5.7.x。连接选项、`synchronize: false`、迁移策略和字符规则保持不变。
## GitNexus 影响
- `assertMysql57Metadata`:CRITICAL,5 个直接调用方、10 个受影响符号和 5 组流程,覆盖 captured/captured_empty 产物、历史目录验证、当前发布基线、基线生成和 `governance:start`。
- `MysqlHealthClient`:LOW,4 个直接依赖、7 个受影响符号和 1 组 API 装配流程。
- `assertSupportedRuntime`:LOW,只有运行时测试直接调用,0 条业务流程。
CRITICAL 来自 Schema 门禁的中心位置,不代表改动复杂。实施必须先增加精确失败用例,再完整回归 Schema 28 项及治理前后门禁;如出现历史 manifest 失效或非 5.7 版本被放行,立即停止并回退。
## 跨模块同步修改
- HTTP/OpenAPI:响应结构不变,仅健康 `detail` 文本显示实际版本;无需重新定义 DTO。
- Web API:不修改请求函数或 adapter;现有健康展示把 detail 当普通文本。
- 消息、Redis、Scheduler、Worker:无行为变化。
- 数据库:不修改 Schema、迁移、查询范围或凭据,只放宽补丁版本判断。
- 部署:继续仅支持 Ubuntu 源码部署,前置条件改写为 Node.js 22.x、MySQL 5.7.x。
- 测试与文档:运行时、Schema、健康客户端、架构规范、开发规范、本地和生产部署手册同步更新。
## 错误处理
- 版本为空、格式异常或系列不符时立即失败,并只输出检测到的版本字符串。
- 版本符合 5.7.x 但字符集、排序规则、库名或时区不符时,保持现有专用错误,不把问题误报为版本错误。
- 不捕获或降级版本错误,不因个人部署场景跳过生产启动校验。
## 安全策略与评估
资产和信任边界不变:Node 版本来自本机运行时;MySQL 版本来自客户端 `--version` 和只读元数据查询。固定正则只接受数字版本与既有后缀,不执行输入。数据库凭据继续由忽略的本地 env 或生产 EnvironmentFile 注入,错误和健康详情不输出账号、密码或地址。
残余风险是 MySQL 5.7 不同补丁可能存在已知缺陷;用户已明确接受系列级约束,项目不承诺补丁级兼容矩阵。字符规则、SQL 5.7 能力上限和迁移测试继续作为实际兼容门禁。
## 性能目标与评估
版本判断是启动或治理阶段的常数时间字符串匹配,健康检查仍只执行一次既有元数据查询。无新增网络调用、重试、数据库扫描、缓存操作或消息流,因此无需负载测试;目标是全量验证前后构建体积和运行流程不变。
## 测试设计
1. RED:新增 Schema 用例要求 5.7.41 通过,确认当前精确 5.7.42 实现失败。
2. GREEN:服务端版本改为 5.7.x 后,验证 5.7.0、5.7.41、5.7.42-log 通过,5.6.51 与 8.0.40 拒绝。
3. RED/GREEN:健康客户端先新增 5.7.41 成功详情断言,再修改实现;保留 8.0 拒绝和字符/排序规则/时区失败用例。
4. Node:补充 22.0.0、22.x 高补丁和 21/23 边界,验证现有实现无需行为变更。
5. 回归:运行 runtime、Schema、MySQL 规范、Server、全量 `pnpm verify:release` 和两个 Review 门禁。
## 回退
若系列校验导致历史基线失效或错误放行非 5.7 服务端,以新的中文回退提交恢复精确判断并同步恢复当前文档;禁止改写已推送历史。功能不涉及数据库结构或数据,因此无数据回滚。
@@ -0,0 +1,62 @@
# GOV-011 开发总结
- 功能编号:GOV-011
- 日期:2026-08-17
- 当前状态:已随 v0.0.9 发布
## 原始开发需求
用户要求 Node.js 和 MySQL 不绑定具体小版本:Node.js 使用 22.x,MySQL 使用完整 5.7.x,不设置最低补丁版本。`utf8mb4`、`utf8mb4_general_ci` 和东八区时区等既有严格约束继续保留;历史证据中的实际版本不得改写。
## 需求与范围变化
- Node 生产判断原本已经按主版本 22 校验,本次只补充系列内/外特征测试,没有改写生产逻辑。
- MySQL 服务端从精确 5.7.42 调整为合法 5.7.x,客户端和 mysqldump 原有 5.7.x 约束保持不变。
- 健康详情从硬编码 patch 改为服务端元数据中的三段版本;`-log` 等附加文本不回显。
- 现行架构、开发规范、本地/Ubuntu 部署手册统一为系列口径;v0.0.8 CHANGELOG、历史 QA、Schema manifest 和已发布档案继续保存真实 5.7.42、22.11.0、22.22.0。
- 用户确认当前开发库无业务结构并授权本次跳过 v0.0.8 Schema 备份。该决定只形成 GOV-011 一次性例外,不增加通用跳过开关。
## 实际完成需求
| 需求 | 状态 | 实际结果 |
|---|---|---|
| Node.js 22.x 系列约束 | 已完成 | 覆盖 22.0.0、常规 22.x、带后缀 22.x 与 21/23 边界;生产判断保持 `major === 22`。 |
| MySQL 服务端完整 5.7.x | 已完成 | Schema 元数据接受 5.7.0、5.7.41、5.7.42-log,拒绝 5.6、8.0 和无效格式。 |
| 健康检查实际版本 | 已完成 | `5.7.41-log` 返回 `MySQL 5.7.41 / ...`;DTO 与查询结构不变。 |
| 字符规则和时区保持严格 | 已完成 | `utf8mb4`、`utf8mb4_general_ci`、库名和 `+08:00` 失败用例全部保留并扩充。 |
| 当前规范统一系列口径 | 已完成 | 架构、开发规范、本地开发、Ubuntu 生产和说明性代码注释已更新。 |
| 历史证据保持原样 | 已完成 | 未批量改写历史功能档案、QA、Schema 基线或 v0.0.8 发布事实。 |
## 修复缺陷
- 修复 Schema 服务端校验把开发机实际 5.7.42 当作唯一合法 patch 的约束错误。
- 修复 API 健康检查拒绝其他合法 5.7.x 且成功详情硬编码 5.7.42 的问题。
- 修复当前架构、开发规范和部署手册将补丁版本误写成跨环境强制基线的问题。
- 完整 Schema 回归发现一处测试仍断言旧错误文案,已同步为 `5.7.x` 并重新验证。
## 未完成与延期项
- 本功能没有数据库结构、迁移或数据变更,因此不存在数据回滚或真实 Schema 导出结果。
- v0.0.8 Schema 基线没有生成。`verify:release`、`schema:verify` 和 `governance:finish` 会在该缺失条件失败;这是用户已接受的追溯风险,不代表其他测试通过,也不会延伸到后续功能。
- 不建立 MySQL 各 patch 的自动兼容矩阵;未来遇到特定补丁缺陷时通过独立功能或 ADR 决定是否提高最低版本。
## 关键提交
| 提交 | 中文摘要 | 推送状态 |
|---|---|---|
| `426870b` | `docs(GOV-011): 制定运行时系列版本实施计划` | 已推送 Gitea |
| `c8277ef` | `test(GOV-011): 补充 Node 22 系列边界验证` | 已推送 Gitea |
| `54499f0` | `fix(GOV-011): 放宽 MySQL 服务端为完整 5.7 系列` | 已推送 Gitea |
| `dc8da80` | `fix(GOV-011): 支持 MySQL 5.7 系列健康检查` | 已推送 Gitea |
| `cce77aa` | `docs(GOV-011): 统一运行时系列版本口径` | 已推送 Gitea |
| `7478a96` | `docs(GOV-011): 完成系列版本验证与审查` | 已推送 Gitea |
| `88e2fdf` | `chore(GOV-011): 发布 v0.0.9 系列版本约束` | 已推送 Gitea,`v0.0.9` 指向该提交 |
## 验证证据
- TDD:Schema 的 5.7.0/5.7.41 成功用例先被旧精确判断拒绝;健康检查的 5.7.41-log 用例先被旧实现拒绝,随后最小修改转绿。
- 排除已授权严格发布基线用例后,Schema 28/28;runtime 3/3、governance 10/10、MySQL 2/2、环境 10/10、契约 3/3、边界 16/16、部署 6/6、Web 11/11、Server 30/30、API 预检 2/2。
- lint、格式、类型检查、OpenAPI 契约、Web/Server 构建、Playwright 4/4 和源码发布验证通过。
- GitNexus 相对 v0.0.8 检测为 23 个文件、70 个符号、11 条受影响流程、HIGH;运行流仅落在既定 Schema 与健康检查边界,详见 `gitnexus/`。
- 依赖审计为 0 已知漏洞,Redis 返回 `PONG`;两张视觉截图无溢出或控制台错误。
- Gitea `refs/heads/main` 与发布提交 `88e2fdffc8c71dd682405c148a81953a8dcee9d6` 一致;带注释标签对象为 `4d1553b68587a6218416bf0279494d720bb37161`,解引用后指向同一发布提交。
@@ -0,0 +1,17 @@
# GitNexus 开发后基线
- 索引提交:`88e2fdf`
- 索引时间:2026-08-17 17:58(Asia/Shanghai)
- 状态:up-to-date
- 节点:2090
- 关系:2767
- 集群:49
- 执行流:50
## 工作区状态
实现、验证和发布提交均已推送 `origin/main`,`v0.0.9` 已精确推送并指向 `88e2fdf`。本次索引刷新只自动更新 `AGENTS.md` 计数,随后与发布引用一起进入追溯提交。
## 运行边界
开发后新增或变化的运行流程仍只有 Schema 治理和 API 健康装配。Web 页面、Scheduler、Worker、Redis 与 RocketMQ 没有新增执行流。
@@ -0,0 +1,29 @@
# GitNexus 开发前基线
- 功能编号:GOV-011
- 记录时间:2026年08月17日 16:57:31 CST
- 分支:main
- 基线提交:`9e858090966e`
- 创建方式:用户授权跳过 v0.0.8 Schema 备份后,按 `governance:start` 输出结构手工留痕
## 工作区
```text
(干净)
```
## GitNexus 状态
```text
Repository: /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis
Indexed commit: 9e85809
Current commit: 9e85809
Status: up-to-date
Nodes: 1,957
Edges: 2,634
Flows: 50
```
## Schema 门禁例外
未运行成功的原因、用户决定、禁止伪造边界和残余风险见 `../schema-baseline-waiver.md`。本记录不表示 `governance:start` 自动门禁通过。
@@ -0,0 +1,29 @@
# GitNexus 前后对比
- before:1894 个符号、2569 条关系、50 条流程(GOV-011 启动记录)
- after:2090 个节点、2767 条关系、50 条流程(`88e2fdf`)
- 相对 v0.0.8 detect-changes:23 个文件、70 个符号、11 条受影响流程、HIGH
## 差异解释
节点与关系增长主要来自 GOV-011 新增功能档案、实施计划、测试名称和当前规范标题。执行流总数仍为 50,没有出现新的生产流程。HIGH 风险由 Schema 中心函数的多条既有调用链贡献,和开发前 CRITICAL 评估方向一致。
## 跨模块核对
| 模块 | 结论 |
|---|---|
| HTTP/OpenAPI | DTO 和字段不变;健康 `detail` 文本显示实际 patch。 |
| Web API | 请求函数、adapter 和页面均未修改。 |
| 消息 | RocketMQ 契约、Topic、Group 和 Adapter 未修改。 |
| 数据库 | 不改 Schema、迁移、数据和查询范围;只放宽版本判断。 |
| Redis | 无代码和配置变化。 |
| API | MySQL 健康版本判断和详情变化,完整 Server 回归通过。 |
| Scheduler | 无行为变化,构建和进程测试通过。 |
| Worker | 无行为变化,构建和进程测试通过。 |
| 部署 | 拓扑不变,只把前置 MySQL 文案改为 5.7.x。 |
| 测试 | 新增系列边界、实际版本详情和当前文档契约。 |
| 文档 | 架构、规范、部署和功能档案同步更新;历史证据保留。 |
## 风险结论
没有发现计划外模块影响。残余风险是不同 MySQL 5.7 patch 自身可能存在缺陷,以及 v0.0.8 缺少可验证 Schema 基线;前者由真实迁移/查询验证控制,后者由用户接受的一次性例外记录控制。
@@ -0,0 +1,34 @@
# GitNexus 实际变更检测
- 比较基线:`v0.0.8` / `9e85809`
- 实现提交:`cce77aa`
- 结果:23 个文件、70 个符号、11 条受影响流程
- 风险:HIGH
## 变更符号
核心运行时符号为:
- `assertMysql57Metadata`
- `runBaselineGeneration`
- `MysqlHealthClient`
- `MysqlHealthClient.check`
- `createMysqlHealthClient`
- `assertSupportedRuntime` 只新增测试,没有生产实现变化
其余符号主要来自架构、规范、部署和 GOV-011 功能档案的 Markdown 标题,以及治理测试中的局部变量。
## 受影响执行流
- `RunBaselineGeneration → RequireExactValue`
- `AssertCurrentReleasedBaselinePublished → RequireExactValue`
- `BuildCapturedArtifacts → RequireExactValue`
- `AssertCurrentReleasedBaseline → RequireExactValue`
- `RunCommandLine` 到 `RequireExactValue`、`IsEnabled`、`ParseManifest`、`AssertExactFileSet`、`BuildManifest` 和 `ParseEnvironmentFile`
- `UseFactory → MysqlHealthClient`
HIGH 来自 Schema 中心入口映射到多条治理流程,不是新增网络、数据库写入或消息链路。排除用户已授权的 v0.0.8 基线缺失用例后,Schema 28 项全部通过;API 健康、Server 测试、类型和构建也全部通过。
## 范围结论
实际变化与开发前影响计划一致。没有新的 HTTP 字段、OpenAPI DTO、Web API、Redis、RocketMQ、Scheduler、Worker、数据库 Schema 或部署拓扑变化。
@@ -0,0 +1,39 @@
# GitNexus 开发前影响计划
- 功能编号:GOV-011
- 基线提交:`9e858090966e`
- 总体风险:CRITICAL(Schema 门禁中心符号)
## 直接与间接影响
### `assertMysql57Metadata`
- 风险:CRITICAL。
- 直接调用方:5 个,包括 Schema 测试、captured、captured_empty、历史目录验证和基线生成。
- 间接影响:10 个符号、5 组流程;深度 2 包含当前发布基线验证和远程发布核对,深度 3 到达 `governance:start`。
- 控制:测试先行,系列内/外边界、历史 manifest、当前发布门禁和生成路径完整回归。
### `MysqlHealthClient`
- 风险:LOW。
- 直接依赖:4 个;总计 7 个受影响符号、1 组 API 装配流程。
- 控制:健康客户端测试覆盖实际版本详情、8.x 拒绝和字符/时区边界,API DTO 不变。
### `assertSupportedRuntime`
- 风险:LOW。
- 只有运行时测试 1 个直接调用者,0 条业务流程;现有实现已按主版本 22 校验。
- 控制:只补系列边界测试和现行文档,不改变生产判断。
## 跨模块同步修改
- HTTP/OpenAPI:结构不变,健康 detail 文本显示实际 5.7.x;不改 DTO。
- Web API:无需修改,现有 adapter 透传 detail。
- 消息、Redis、Scheduler、Worker:无影响。
- 数据库:只调整版本判断,不改 Schema、迁移、查询或数据。
- 配置部署:注释和前置条件改为 Node.js 22.x、MySQL 5.7.x;源码部署方式不变。
- 测试文档:runtime、Schema、健康客户端、MySQL 规范、架构、开发规范和部署手册同步修改;历史已发布事实不改写。
## 高风险处置
若 Schema 历史清单验证失败、5.6/8.x 被放行、字符规则校验被绕过或 `governance:start` 相关回归失败,立即停止实施并恢复到基线提交的行为。提交前必须执行 GitNexus detect-changes 并确认实际执行流未超出本计划。
@@ -0,0 +1,521 @@
# GOV-011 Node 与 MySQL 系列版本约束实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 将当前生效的运行时约束统一为 Node.js 22.x 与完整 MySQL 5.7.x,同时保留数据库字符规则、时区、安全边界和历史版本证据。
**Architecture:** Node.js 继续由现有语义版本解析器按主版本判断,只补充特征测试。Schema 工具和 API 健康检查分别在既有职责边界内识别 MySQL 5.7.x,不新增共享版本工具,避免在只有两个简单且上下文不同的判断点时提前抽象;健康详情从服务端返回值提取实际三段版本。现行架构、开发规范和部署文档同步采用系列口径,历史 QA、Schema 清单和已发布档案保持原样。
**Tech Stack:** Node.js 22.x、pnpm 10.25.0、Node.js 内置测试运行器、TypeScript 5.9.3、Vitest 3.2.7、NestJS 11、mysql2 3.23.3、MySQL 5.7.x、GitNexus、Git/Gitea。
## Global Constraints
- Node.js 接受格式合法的 22.x,拒绝 21.x、23.x 和无效版本;pnpm 继续使用既有 10.x 门禁。
- MySQL 客户端、mysqldump 客户端、服务端和健康检查接受完整 5.7.x,不设置最低 patch,不接受 5.6.x、8.x 或 MariaDB。
- 数据库字符集固定 `utf8mb4`,排序规则固定 `utf8mb4_general_ci`,会话时区固定 `+08:00`。
- Schema 基线只允许 `APP_ENV=development`、数据库 `a_share_analysis_dev` 和代码内固定开发主机白名单;禁止连接、探测或读取生产数据库。
- 不修改数据库 Schema、迁移、数据、连接账号、网络、HTTP DTO、OpenAPI 字段、Web API、Redis、RocketMQ、Scheduler 或 Worker 行为。
- 历史 QA、Schema manifest 和已发布功能档案中的 `5.7.42`、`22.11.0`、`22.22.0` 是实际证据,不得批量改写。
- 版本判断使用固定格式匹配,不执行版本字符串,不拼接 SQL,不把连接地址、账号或密码写入错误和健康详情。
- 不新增依赖;关键版本口径、安全边界和架构取舍使用准确中文注释,不做逐行翻译式注释。
- 每个行为修改遵循 RED-GREEN:先证明旧精确补丁判断失败,再写最小实现并执行局部与完整回归。
- 修改关键符号前复核既有 GitNexus impact;提交前执行 GitNexus detect-changes,确认影响没有超出已批准范围。
- 每个提交使用中文 Conventional Commit 并带 `GOV-011`,验证后立即推送当前分支到项目 Gitea,禁止强推。
- v0.0.8 Schema 基线按 `schema-baseline-waiver.md` 执行一次性例外:不得伪造 N/A、空库清单或空 SQL,也不得修改治理工具增加通用跳过能力。
---
### Task 1: 锁定 Node.js 22.x 现有行为
**Files:**
- Modify: `tools/runtime/verify-runtime.test.mjs`
**Interfaces:**
- Consumes: `assertSupportedRuntime({ nodeVersion, pnpmVersion })`。
- Produces: Node.js 22 系列内边界、相邻主版本和无效格式的特征测试。
- Preserves: `tools/runtime/verify-runtime.mjs` 的生产判断和 pnpm 10.x 约束。
- [ ] **Step 1: 补充 Node.js 系列边界测试**
将现有 Node 成功样本扩展为系列内多个版本,并把相邻失败样本明确为 21.x 与 23.x:
```js
test('接受完整 Node.js 22.x 并拒绝相邻主版本', () => {
for (const nodeVersion of ['22.0.0', '22.11.0', '22.99.123-beta.1+build.7']) {
assert.doesNotThrow(() =>
assertSupportedRuntime({ nodeVersion, pnpmVersion: '10.25.0' }),
);
}
for (const nodeVersion of ['21.7.3', '23.0.0']) {
assert.throws(
() => assertSupportedRuntime({ nodeVersion, pnpmVersion: '10.25.0' }),
/Node\.js 必须为 22\.x/,
);
}
});
```
保留 `v22`、空字符串、非数字 pnpm 等既有无效格式测试,不改变 `parseVersion` 的输入格式契约。
- [ ] **Step 2: 运行特征测试并确认现有实现已满足**
Run: `pnpm test:runtime`
Expected: PASS。该任务是对已存在的 22.x 行为补证,不修改生产代码,也不制造无意义的 RED。
- [ ] **Step 3: 提交并推送 Node 特征测试**
```bash
git add tools/runtime/verify-runtime.test.mjs
git commit -m "test(GOV-011): 补充 Node 22 系列边界验证"
git push origin main
```
Expected: 推送成功,本地 `HEAD` 与 Gitea `refs/heads/main` 一致。
---
### Task 2: 让 Schema 元数据接受完整 MySQL 5.7.x
**Files:**
- Modify: `tools/database/schema-baseline.test.mjs`
- Modify: `tools/database/schema-baseline.mjs`
**Interfaces:**
- Consumes: `assertMysql57Metadata(metadata)` 及既有 `MysqlMetadata` 形状。
- Produces: 客户端、mysqldump 和服务端统一的 `5.7.<非负整数>` 系列判断。
- Preserves: `databaseCharset === 'utf8mb4'`、`databaseCollation === 'utf8mb4_general_ci'`、历史 manifest 格式和所有 Schema 安全门禁。
- [ ] **Step 1: 写入服务端 5.7.x 失败测试**
把现有“5.7.41 必须失败”改成系列内成功断言,并补齐最低 patch、后缀及上下系列边界:
```js
test('接受完整 MySQL 5.7.x 并保持固定数据库字符规则', () => {
for (const serverVersion of ['5.7.0', '5.7.41', '5.7.42-log']) {
assert.doesNotThrow(() => assertMysql57Metadata({ ...validMetadata, serverVersion }));
}
for (const serverVersion of ['5.6.51', '8.0.40', '5.7', '5.7.x', '']) {
assert.throws(
() => assertMysql57Metadata({ ...validMetadata, serverVersion }),
/MySQL 服务端必须为 5\.7\.x/,
);
}
assert.throws(
() => assertMysql57Metadata({ ...validMetadata, mysqlClientVersion: '8.0.40' }),
/mysql 客户端必须为 5\.7\.x/,
);
assert.throws(
() => assertMysql57Metadata({ ...validMetadata, databaseCollation: 'utf8mb4_bin' }),
/utf8mb4_general_ci/,
);
});
```
- [ ] **Step 2: 运行定向测试并确认 RED**
Run: `node --test --test-name-pattern='完整 MySQL 5.7.x' tools/database/schema-baseline.test.mjs`
Expected: FAIL,`5.7.0` 或 `5.7.41` 被当前精确 `5.7.42` 服务端判断拒绝;失败原因不得来自测试语法或夹具。
- [ ] **Step 3: 最小修改服务端系列判断**
将 `assertMysql57Metadata` 中服务端判断改为与两个客户端相同的系列格式,并更新注释与错误信息:
```js
/**
* mysql、mysqldump 与服务端统一接受完整 5.7.x;字符集和排序规则仍按精确值校验,
* 避免放宽 patch 版本时意外放宽数据库结构兼容边界。
*/
export function assertMysql57Metadata(metadata) {
// 两个既有客户端判断保持不变。
if (!/^5\.7\.\d+(?:[-+].*)?$/.test(metadata.serverVersion ?? '')) {
throw new Error(`MySQL 服务端必须为 5.7.x,实际 ${metadata.serverVersion || '(空)'}`);
}
// 既有字符集和排序规则精确校验保持不变。
}
```
实际编辑只替换服务端正则、对应注释和错误文案,不复制或重排函数内其他校验。
- [ ] **Step 4: 运行 Schema 局部与完整回归**
Run: `node --test --test-name-pattern='完整 MySQL 5.7.x' tools/database/schema-baseline.test.mjs`
Expected: PASS。
Run: `pnpm test:schema-baseline && pnpm test:mysql-baseline && pnpm test:governance`
Expected: PASS。历史 `captured`、`captured_empty`、N/A、当前发布门禁、生成入口和远程核对测试均无回归;测试不得访问真实数据库。
- [ ] **Step 5: 提交并推送 Schema 系列判断**
在提交前执行 GitNexus detect-changes,确认只影响已记录的 Schema 生成、验证和治理调用链,然后:
```bash
git add tools/database/schema-baseline.mjs tools/database/schema-baseline.test.mjs
git commit -m "fix(GOV-011): 放宽 MySQL 服务端为完整 5.7 系列"
git push origin main
```
Expected: 推送成功且没有新增 Schema 文件或数据库连接副作用。
---
### Task 3: 健康检查返回实际 MySQL 5.7.x 版本
**Files:**
- Modify: `server/libs/infrastructure/src/health-clients.test.ts`
- Modify: `server/libs/infrastructure/src/mysql-health.client.ts`
**Interfaces:**
- Consumes: `MysqlHealthClient.check(): Promise<DependencyHealthDto>` 与 `MYSQL_HEALTH_QUERY`。
- Produces: 5.7.x 成功结果 `MySQL <实际三段版本> / <database> / +08:00`。
- Preserves: `DependencyHealthDto` 结构、只读元数据查询、数据库名、字符集、排序规则、时区校验和最多两个连接的池配置。
- [ ] **Step 1: 写入健康检查 5.7.41 失败测试**
将成功夹具改为 `5.7.41-log`,断言详情来自返回值;移除“5.7.41 必须失败”的旧断言,增加 5.6 与 8.0 边界:
```ts
await expect(client.check()).resolves.toEqual({
status: 'healthy',
detail: 'MySQL 5.7.41 / a_share_analysis_dev / +08:00',
});
for (const version of ['5.6.51', '8.0.40', '5.7', '5.7.x']) {
await expect(createClient({ version }).check()).rejects.toThrow(/MySQL 5\.7\.x/);
}
```
保留库名、`utf8mb4`、`utf8mb4_general_ci` 和 `+08:00` 漂移失败断言;如当前测试缺少字符集或时区样本,在同一测试中分别补入:
```ts
await expect(createClient({ charset: 'utf8' }).check()).rejects.toThrow(/utf8mb4/);
await expect(createClient({ timezone: 'SYSTEM' }).check()).rejects.toThrow(/\+08:00/);
```
- [ ] **Step 2: 运行定向测试并确认 RED**
Run: `pnpm --filter @a-share-analysis/server exec vitest run libs/infrastructure/src/health-clients.test.ts`
Expected: FAIL,当前实现拒绝 `5.7.41-log` 或仍返回硬编码的 `MySQL 5.7.42`。
- [ ] **Step 3: 最小实现系列判断和实际版本详情**
在 `MysqlHealthClient.check` 中只解析一次版本,并使用捕获到的三段版本构造安全详情:
```ts
const versionMatch = /^(5\.7\.\d+)(?:[-+].*)?$/.exec(row.version);
if (!versionMatch) {
throw new Error('MySQL 5.7.x 版本要求未满足');
}
return {
status: 'healthy',
detail: `MySQL ${versionMatch[1]} / ${row.databaseName} / ${row.timezone}`,
};
```
这里不回显 `-log` 等服务端后缀,避免把厂商或构建附加文本直接带到用户界面;显示的三段版本仍来自服务端元数据,不再硬编码 patch。
同步把健康池注释中的 `5.7.42` 改为 `5.7.x`,连接参数不变。
- [ ] **Step 4: 运行后端局部与完整回归**
Run: `pnpm --filter @a-share-analysis/server exec vitest run libs/infrastructure/src/health-clients.test.ts`
Expected: PASS。
Run: `pnpm --filter @a-share-analysis/server test && pnpm --filter @a-share-analysis/server typecheck && pnpm --filter @a-share-analysis/server build`
Expected: PASS;OpenAPI DTO 和生成文件无变化。
- [ ] **Step 5: 提交并推送健康检查变化**
在提交前执行 GitNexus detect-changes,确认影响仅进入 API 健康装配流程,然后:
```bash
git add server/libs/infrastructure/src/mysql-health.client.ts server/libs/infrastructure/src/health-clients.test.ts
git commit -m "fix(GOV-011): 支持 MySQL 5.7 系列健康检查"
git push origin main
```
Expected: 推送成功,健康响应结构没有契约漂移。
---
### Task 4: 统一现行代码注释与规范部署口径
**Files:**
- Modify: `tools/governance/environment-baseline.test.mjs`
- Modify: `server/libs/config/src/runtime-config.ts`
- Modify: `server/libs/infrastructure/src/typeorm-options.ts`
- Modify: `docs/architecture/system-architecture.md`
- Modify: `docs/governance/code-development-standards.md`
- Modify: `docs/deployment/local-development.md`
- Modify: `docs/deployment/ubuntu-source-production.md`
**Interfaces:**
- Consumes: GOV-011 已确认的现行版本文字边界。
- Produces: 可机器验证的 Node.js 22.x / MySQL 5.7.x 当前规范。
- Preserves: pnpm 10.25.0、Ubuntu 源码部署、systemd、Nginx、Redis、RocketMQ 和环境变量模板。
- [ ] **Step 1: 先把文档契约测试改为系列口径**
将环境基线测试的现行文档检查从精确 `5.7.42` 改为 `5.7.x`,并显式拒绝当前文档继续写死 patch:
```js
for (const document of [local, source]) {
assert.match(document, /MySQL 5\.7\.x/);
assert.doesNotMatch(document, /MySQL 5\.7\.42/);
}
```
再读取系统架构和代码开发规范,执行相同断言;测试只扫描这四份当前生效文档,不扫描 `docs/features/`、`database/schema-baselines/` 或历史 QA。
- [ ] **Step 2: 运行环境契约并确认 RED**
Run: `pnpm test:environment-baseline`
Expected: FAIL,现行文档仍包含 `MySQL 5.7.42`。
- [ ] **Step 3: 更新代码说明性注释**
把以下当前注释统一为 `MySQL 5.7.x`:
- `MysqlRuntimeConfig` 的兼容口径说明。
- `buildTypeOrmOptions` 的 MySQL 基线说明。
- `createMysqlHealthClient` 的会话时区说明。
- `assertMysql57Metadata` 的客户端/服务端系列说明。
不修改类型字段、连接选项、`synchronize: false`、迁移配置或配置解析行为。
- [ ] **Step 4: 更新四份当前生效文档**
逐项修改:
- 系统架构:开发、测试和生产统一使用 MySQL 5.7.x,禁止 5.6、8.x、MariaDB 代替验证;不再禁止其他 5.7 patch。
- 代码开发规范:Node.js 22.x 和 MySQL 5.7.x 是系列约束;字符集、排序规则和时区仍为精确值。
- 本地开发:外部 MySQL 使用 5.7.x,固定开发库与主机白名单不变。
- Ubuntu 生产:管理员提供 Node.js 22.x 与外部 MySQL 5.7.x,项目仍只验证、不安装基础设施。
历史功能档案、QA、Schema manifest 和既有版本记录不修改。
- [ ] **Step 5: 运行文档契约与格式验证**
Run: `pnpm test:environment-baseline && pnpm test:deployment && pnpm format:check`
Expected: PASS。
Run: `rg -n "MySQL 5\.7\.42" docs/architecture docs/governance docs/deployment server/libs tools/database/schema-baseline.mjs`
Expected: 当前生效代码和文档无精确 `MySQL 5.7.42` 口径;若命中测试夹具中的真实输入版本,只核对其用途,不改写真实样本。
- [ ] **Step 6: 提交并推送规范同步**
```bash
git add tools/governance/environment-baseline.test.mjs \
server/libs/config/src/runtime-config.ts \
server/libs/infrastructure/src/typeorm-options.ts \
server/libs/infrastructure/src/mysql-health.client.ts \
tools/database/schema-baseline.mjs \
docs/architecture/system-architecture.md \
docs/governance/code-development-standards.md \
docs/deployment/local-development.md \
docs/deployment/ubuntu-source-production.md
git commit -m "docs(GOV-011): 统一运行时系列版本口径"
git push origin main
```
Expected: 推送成功;`git diff --name-only` 不包含任何历史功能档案或 Schema 基线文件。
---
### Task 5: 补齐功能档案和全量验证证据
**Files:**
- Create: `docs/features/GOV-011-runtime-version-series/test-plan.md`
- Create: `docs/features/GOV-011-runtime-version-series/development-summary.md`
- Create: `docs/features/GOV-011-runtime-version-series/gitnexus/detected-changes.md`
- Create: `docs/features/GOV-011-runtime-version-series/gitnexus/after.md`
- Create: `docs/features/GOV-011-runtime-version-series/gitnexus/comparison.md`
- Create: `docs/features/GOV-011-runtime-version-series/qa/test-results.md`
- Create: `docs/features/GOV-011-runtime-version-series/qa/visual-qa.md`
- Create: `docs/features/GOV-011-runtime-version-series/review/code-review.md`
- Create: `docs/features/GOV-011-runtime-version-series/review/standards-review.md`
- Create: `docs/features/GOV-011-runtime-version-series/release-notes.md`
- Create: `docs/features/GOV-011-runtime-version-series/rollback.md`
- Modify: `docs/features/GOV-011-runtime-version-series/manifest.yaml`
**Interfaces:**
- Consumes: Tasks 1-4 的测试结果、提交 SHA、GitNexus before/impact 与一次性 Schema 例外。
- Produces: `governance:finish` 所需的完整、可审查功能档案。
- [ ] **Step 1: 编写测试计划和开发总结骨架**
`test-plan.md` 必须明确列出:
- Node 22.0.0、其他 22.x、21.x、23.x 和无效格式。
- MySQL 5.7.0、5.7.41、5.7.42-log、5.6.51、8.0.40 和无效格式。
- 字符集、排序规则、库名、时区与固定开发安全边界回归。
- HTTP/OpenAPI 无结构变化验证;消息、Redis、Scheduler、Worker 不受影响的边界验证。
- 安全验证:无生产数据库访问、无凭据泄漏、固定格式匹配、依赖未变化。
- 性能验证:无新增查询/任务/重试,版本匹配为常数时间;无需负载测试的原因和边界。
- 全量 `pnpm verify:release`、桌面/移动视觉回归及源码部署验证。
`development-summary.md` 必须用七个固定二级标题记录原始开发需求、范围变化、实际完成需求、修复缺陷、未完成与延期项、关键提交和验证证据;“没有数据库变更”必须写明原因与边界,不能只写“不适用”。
- [ ] **Step 2: 执行局部和全量验证**
依次运行并把命令、退出码、关键计数和日期保存到 `qa/test-results.md`:
```bash
pnpm test:runtime
pnpm test:schema-baseline
pnpm --filter @a-share-analysis/server exec vitest run libs/infrastructure/src/health-clients.test.ts
pnpm test:environment-baseline
pnpm check:contracts
pnpm lint
pnpm format:check
pnpm typecheck
pnpm test
pnpm build
pnpm verify:e2e
pnpm verify:release
git diff --check
```
Expected: 除 `pnpm verify:release` 因已授权的 v0.0.8 Schema 基线缺失而失败外,其余命令 PASS;`pnpm check:contracts` 执行后 OpenAPI 和 Web 生成类型没有非预期差异。必须继续手工执行 `verify:release` 在 Schema 失败点之后的构建、E2E 和源码发布门禁。
- [ ] **Step 3: 完成视觉验证**
启动 Web/API 的本地开发服务,复用既有 Playwright 桌面与移动视口检查首页健康展示及控制台;GOV-011 不改变页面布局,`qa/visual-qa.md` 仍须保存运行命令、视口、截图路径、控制台结果和“不发生视觉变化”的证据。服务结束后确认没有遗留进程。
- [ ] **Step 4: 执行 GitNexus 开发后检测与比较**
先执行 GitNexus detect-changes,保存受影响符号、执行流和风险到 `gitnexus/detected-changes.md`;再运行:
```bash
npx gitnexus analyze
npx gitnexus status
```
将开发后节点、关系、流程、工作区摘要写入 `gitnexus/after.md`,把 before/after 差异和以下逐项结论写入 `gitnexus/comparison.md`:HTTP/OpenAPI、Web API、消息、数据库、Redis、API、Scheduler、Worker、部署、测试、文档。若出现计划外 HIGH/CRITICAL 风险或新的执行流,停止发布并回到影响分析。
- [ ] **Step 5: 记录 Schema 例外门禁证据**
运行:
```bash
pnpm schema:verify
pnpm governance:finish GOV-011 runtime-version-series
```
Expected: 两者均因 `database/schema-baselines/v0.0.8` 缺失而失败。把完整错误摘要和退出码写入 `qa/test-results.md`,并引用 `schema-baseline-waiver.md`;不得把预期失败写成通过,也不得生成伪造基线。
随后手工执行 `governance:finish` 在 Schema 失败前要求的治理、MySQL、环境和 Schema 测试,并人工核对全部必备档案、证据章节和 Review 末行。该一次性例外只替代 v0.0.8 基线存在性,不替代任何测试、GitNexus、Review、提交或推送门禁。
- [ ] **Step 6: 完成两类 Review**
`review/code-review.md` 先列发现,按严重度记录文件/行、影响和处置;必须包含“安全与残余风险”“性能与资源影响”“GitNexus 与同步修改”。`review/standards-review.md` 逐项核对注释、职责拆分、TDD、规范、历史证据、中文提交、Gitea 推送和一次性例外边界;必须包含“安全、性能与架构检查”“GitNexus 与开发总结检查”。
只有所有重要问题关闭后,两份报告最后一个非空行才写:
```text
最终结论:passed
```
- [ ] **Step 7: 提交并推送完整验证档案**
```bash
git add docs/features/GOV-011-runtime-version-series
git commit -m "docs(GOV-011): 完成系列版本验证与审查"
git push origin main
```
Expected: 推送成功,远程包含完整功能档案;提交前 GitNexus detect-changes 已保存且实际范围与影响计划一致。
---
### Task 6: 发布 v0.0.9 并封存追溯状态
**Files:**
- Modify: `VERSION`
- Modify: `CHANGELOG.md`
- Modify: `docs/index.md`
- Modify: `docs/features/GOV-011-runtime-version-series/manifest.yaml`
- Modify: `docs/features/GOV-011-runtime-version-series/development-summary.md`
- Modify: `docs/features/GOV-011-runtime-version-series/release-notes.md`
- Modify: `docs/features/GOV-011-runtime-version-series/qa/test-results.md`
- Modify: `docs/features/GOV-011-runtime-version-series/review/code-review.md`
- Modify: `docs/features/GOV-011-runtime-version-series/review/standards-review.md`
**Interfaces:**
- Consumes: 已通过的代码、测试、Review、GitNexus 证据与用户确认的一次性 Schema 例外。
- Produces: 发布提交、Gitea `main` 与带注释标签 `v0.0.9`。
- [ ] **Step 1: 更新版本和发布文档**
将 `VERSION` 更新为 `0.0.9`;`CHANGELOG.md` 和 `docs/index.md` 记录 GOV-011 的实际完成范围、Schema 一次性例外和历史证据不改写原则。`manifest.yaml` 更新为 `status: released`、`release: v0.0.9`,并补齐实施计划、测试、开发总结、GitNexus、Review 文件引用。
- [ ] **Step 2: 执行发布前最终验证**
Run: `pnpm verify:release`
Expected: 因已授权的一次性例外,在 v0.0.8 Schema 严格发布基线检查处失败;失败点之前的门禁和手工补跑的后续构建、E2E、源码发布验证必须全部通过,且真实结果写入 QA。
Run: `git diff --check && git status --short && git log -1 --oneline`
Expected: 只有预期发布文档变更,格式无错误;提交前再次执行 GitNexus detect-changes。
按 Task 5 重跑 `pnpm schema:verify` 和 `pnpm governance:finish GOV-011 runtime-version-series`,Expected 仍是已记录的一次性例外失败;确认没有新增或变化的失败原因。
- [ ] **Step 3: 创建并推送发布封存提交**
```bash
git add VERSION CHANGELOG.md docs/index.md docs/features/GOV-011-runtime-version-series
git commit -m "chore(GOV-011): 发布 v0.0.9 系列版本约束"
git push origin main
```
Expected: 推送成功,本地 `HEAD`、`origin/main` 和 Gitea `refs/heads/main` SHA 一致。
- [ ] **Step 4: 创建并精确推送标签**
```bash
git tag -a v0.0.9 -m "发布 v0.0.9:统一 Node 与 MySQL 系列版本约束"
git push origin refs/tags/v0.0.9
```
Expected: Gitea `refs/tags/v0.0.9^{}` 指向发布封存提交;不使用 `git push --tags`,不覆盖未知远程标签。
- [ ] **Step 5: 最终核对并封存实际 SHA**
将最终分支提交和标签 SHA 回填到 `development-summary.md` 与 `qa/test-results.md` 时,使用新的中文文档提交并立即推送;如回填会使标签不再指向最终文档提交,则明确记录“标签指向发布封存提交、追溯回填位于后续文档提交”,不得移动已推送标签。
---
## 计划自审
- 规格覆盖:FR-001 至 FR-005、全部验收标准、安全、性能、历史证据和一次性 Schema 例外均有对应任务。
- 影响覆盖:`assertMysql57Metadata` 的 CRITICAL 调用链由 Task 2 完整回归;`MysqlHealthClient` 与 `assertSupportedRuntime` 分别由 Task 3 和 Task 1 覆盖。
- 类型一致性:计划只消费既有 `assertSupportedRuntime`、`assertMysql57Metadata`、`MysqlHealthClient.check` 和 `DependencyHealthDto`,没有新增跨任务接口或命名漂移。
- 范围控制:不新增依赖、不改 DTO/生成契约、不改数据库结构、不接触生产数据库、不批量改写历史证据。
- 占位符检查:未发现待补内容、跨任务省略引用或无验证方式的实现步骤;每个代码行为都有精确测试命令和预期结果。
- 回退可行:功能只修改判断、详情文字、注释和文档;出现历史基线失效或错误放行时,可用中文回退提交恢复基线行为,不需要数据回滚。
@@ -0,0 +1,21 @@
id: GOV-011
name: Node 与 MySQL 系列版本约束
slug: runtime-version-series
status: released
owner: project
created_at: 2026-08-17
prd: prd.md
requirements: requirements.md
design: design.md
implementation_plan: implementation-plan.md
test_plan: test-plan.md
development_summary: development-summary.md
schema_baseline_waiver: schema-baseline-waiver.md
gitnexus_before: gitnexus/before.md
gitnexus_impact: gitnexus/impact-plan.md
gitnexus_detected_changes: gitnexus/detected-changes.md
gitnexus_after: gitnexus/after.md
gitnexus_comparison: gitnexus/comparison.md
code_review: review/code-review.md
standards_review: review/standards-review.md
release: v0.0.9
@@ -0,0 +1,33 @@
# Node 与 MySQL 系列版本约束 PRD
- 功能编号:GOV-011
- 状态:设计复核
- 日期:2026-08-17
## 背景
项目目标基线一直是 Node.js 22.x 与 MySQL 5.7.x,但部分实现、错误提示和现行规范把实际开发环境的 MySQL 5.7.42 写成了唯一允许的补丁版本。Node 运行时已经按 22 主版本校验,只是历史验证记录会显示实际使用的 22.11.0 或 22.22.0。用户明确说明本项目主要由本人部署,不需要锁定某个补丁版本,希望现行口径统一为系列版本。
## 目标
- Node.js 接受全部格式合法的 22.x,拒绝其他主版本。
- MySQL 客户端、mysqldump、服务端和运行时健康检查接受全部格式合法的 5.7.x,拒绝 5.6.x、8.x 及其他系列。
- 字符集 `utf8mb4`、排序规则 `utf8mb4_general_ci`、会话时区 `+08:00`、固定开发库和主机白名单继续严格校验。
- 健康结果展示服务端返回的实际版本,不再硬编码 5.7.42。
- 当前规范统一使用系列口径,历史 QA、Schema 清单和已发布档案继续保留当时真实补丁版本。
## 非目标
- 不升级 Node、MySQL、pnpm、数据库驱动或 ORM。
- 不修改数据库结构、数据、账号、网络或部署方式。
- 不支持 Node 23、MySQL 8.x、MariaDB 或其他“兼容 MySQL”数据库。
- 不为各补丁版本建立兼容矩阵或自动安装运行时。
## 验收标准
1. Node 22.0.0、22.11.0 和带预发布/构建后缀的合法 22.x 版本通过;21.x、23.x 和无效格式拒绝。
2. MySQL 5.7.0、5.7.41、5.7.42-log 等合法 5.7.x 通过;5.6.x、8.0.x 和无效格式拒绝。
3. MySQL 5.7.x 即使版本通过,字符集、排序规则、库名或时区错误仍拒绝。
4. 既有 v0.0.5 至 v0.0.7 Schema 历史清单继续验证,不被改写。
5. 健康详情包含实际服务端版本;不泄漏连接地址、账号或密码。
6. 全量测试、构建、Playwright、源码发布门禁和两类 Review 通过。
@@ -0,0 +1,71 @@
# GOV-011 测试与质量证据
- 验证提交:`cce77aa`
- 验证日期:2026-08-17
- 运行时:Node.js 22.11.0、pnpm 10.25.0
## RED-GREEN 证据
| 行为 | RED | GREEN |
|---|---|---|
| Schema 接受完整 5.7.x | `5.7.0` 被旧实现以“必须为 5.7.42”拒绝 | 系列内/外定向测试 2/2 通过 |
| 健康检查接受 5.7.41-log | 旧实现拒绝并输出 5.7.42 文案 | 健康客户端 5/5 通过,详情为 `MySQL 5.7.41 / ...` |
| 当前文档采用系列口径 | 架构/规范 0/2,部署文档测试 9/10 | MySQL 2/2、环境 10/10、部署 6/6 |
## 自动化验证
| 命令或测试组 | 结果 | 关键证据 |
|---|---|---|
| `pnpm check:runtime` | passed | Node.js 22.11.0、pnpm 10.25.0 |
| `pnpm check:contracts` | passed | OpenAPI 与 Web 生成类型无漂移,项目边界通过 |
| `pnpm lint` | passed | Web/Server ESLint 无错误 |
| `pnpm format:check` | passed | 全仓 Prettier 通过 |
| `pnpm typecheck` | passed | Web、Vite 和 Server TypeScript 通过 |
| runtime | 3/3 | 22.x 系列与相邻主版本 |
| governance | 10/10 | 功能档案和 Review 门禁 |
| MySQL 规范 | 2/2 | 当前架构/规范使用 5.7.x |
| 环境 | 10/10 | 部署手册使用 5.7.x,其他环境边界保持 |
| Schema(跳过严格发布基线) | 28/28 | 生成、验证、历史 manifest 和字符规则回归 |
| contracts | 3/3 | 生成契约跟踪与漂移阻断 |
| boundaries | 16/16 | 前后端与 HTTP 边界 |
| deployment | 6/6 | 唯一 Ubuntu 源码发布边界 |
| Web | 11/11 | 请求、adapter 与外壳 |
| Server | 30/30 | API、配置、基础设施和进程 |
| API 预检 | 2/2 | Redis 可达/不可达分支 |
| `pnpm build` | passed | Web、API、Scheduler、Worker 构建成功 |
| `pnpm verify:e2e` | 4/4 | Chromium 桌面/移动页面和健康 API |
| `pnpm verify:source` | passed | 构建产物、systemd、Nginx 一致 |
## 一次性例外失败证据
`pnpm verify:release` 退出码非 0。它依次通过 runtime、契约、lint、格式、类型以及 Schema 之前的测试,随后在 Schema 第 28 个严格发布基线用例失败;实际错误为缺少 `database/schema-baselines/v0.0.8`。Schema 总计 29 项,其中 28 项通过、1 项为该已知失败。
`pnpm schema:verify` 在直接目录校验处失败;`pnpm governance:finish GOV-011 runtime-version-series` 在其前置 `test:schema-baseline` 的严格发布基线用例处失败。两者根因都是同一个 v0.0.8 目录缺失条件。原因、用户授权和禁止伪造边界见 `schema-baseline-waiver.md`;其余等价门禁已逐项执行并保存上表证据。
## 安全证据
- `pnpm audit --prod --registry=https://registry.npmjs.org/`:`No known vulnerabilities found`。
- `redis-cli -h 127.0.0.1 -p 6379 ping`:`PONG`,只验证本机开发 Redis。
- 构建产物扫描只命中 `MYSQL_PASSWORD`、`AI_API_KEY` 等配置键和必填错误文案,没有真实值、连接串或 Authorization 头。
- 本次没有新增依赖、SQL、命令执行、数据库写入、生产连接或外部网络请求。
- 健康详情只返回三段版本、库名和时区,不返回原始后缀、地址、账号或密码。
## 性能证据
- Web JS:163908 字节;CSS:805 字节,与 v0.0.8 记录一致。
- 健康检查仍为一次元数据查询,连接池上限 2;无重试、扫描、缓存或消息增量。
- Schema 与 runtime 判断只在启动/治理阶段执行常数时间正则匹配,不进入行情请求热路径。
## GitNexus 证据
- 发布后 after:2090 节点、2767 关系、49 集群、50 流程,索引 `88e2fdf` 为 up-to-date。
- compare:23 文件、70 符号、11 流程、HIGH;运行影响仅在既有 Schema 与 API 健康路径。
- `AGENTS.md` 的 GitNexus 计数在实现和发布两次 `analyze` 中由 2004/2681 更新为 2015/2692,再更新为 2090/2767。
## 发布引用
- 发布提交:`88e2fdffc8c71dd682405c148a81953a8dcee9d6`。
- Gitea `refs/heads/main`:发布时与上述提交一致。
- 带注释标签对象:`4d1553b68587a6218416bf0279494d720bb37161`。
- Gitea `refs/tags/v0.0.9^{}`:`88e2fdffc8c71dd682405c148a81953a8dcee9d6`。
- 标签只精确推送一次,未使用批量标签推送、强推或移动标签。
@@ -0,0 +1,21 @@
# GOV-011 视觉回归记录
- 页面:应用工程基础外壳
- 变更类型:后端版本判断、测试、注释和文档;无页面样式或交互修改
- 结论:无可观察视觉回归
## 桌面
- Chromium 视口:1440×900
- 截图:[app-shell-desktop-1440x900-cce77aa.png](/Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis/docs/features/GOV-011-runtime-version-series/screenshots/iterations/app-shell-desktop-1440x900-cce77aa.png)
- 检查:`main` 可见,标题正常,无横向溢出,控制台 warning/error 为空。
## 移动
- Chromium 视口:390×844
- 截图:[app-shell-mobile-390x844-cce77aa.png](/Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis/docs/features/GOV-011-runtime-version-series/screenshots/iterations/app-shell-mobile-390x844-cce77aa.png)
- 检查:标题与主内容正常换行和留白,无横向溢出、遮挡或裁切,控制台 warning/error 为空。
## 自动化证据
`pnpm verify:e2e` 在 desktop-chromium 与 mobile-chromium 共执行 4 项,全部通过;覆盖页面可见性、横向溢出、运行时错误和同源 `/api/v1/health` 契约。截图生成后测试 API 与 Vite 服务均通过 SIGINT 关闭,端口 3000/5173 无遗留监听。
@@ -0,0 +1,24 @@
# GOV-011 发布说明
- 发布版本:v0.0.9
- 状态:已发布
- 发布日期:2026-08-17
- 发布提交:`88e2fdffc8c71dd682405c148a81953a8dcee9d6`
- 标签:`v0.0.9`(带注释标签,解引用后指向发布提交)
## 调整
- Node.js 运行时约束明确为完整 22.x,不绑定 minor 或 patch。
- MySQL 客户端、mysqldump、服务端和 API 健康检查统一接受完整 5.7.x,不设置最低 patch。
- MySQL 健康详情显示服务端实际三段版本,不再硬编码 5.7.42。
- 系统架构、代码开发规范、本地开发和 Ubuntu 源码部署手册统一使用系列版本口径。
## 保持不变
- `utf8mb4`、`utf8mb4_general_ci`、`+08:00`、固定开发库和主机白名单继续严格校验。
- HTTP/OpenAPI 响应结构、Web API、Redis、RocketMQ、Scheduler、Worker、数据库 Schema 和源码部署拓扑不变。
- 历史 QA、Schema 清单、CHANGELOG 历史版本和已发布功能档案继续记录当时真实 patch。
## 已知例外
v0.0.8 没有开发库 Schema 基线。用户确认开发库为空并授权 GOV-011 一次性跳过;仓库没有伪造基线或增加通用绕过开关。该例外导致 `verify:release`、`schema:verify` 和 `governance:finish` 在同一基线存在性检查失败,其他门禁已逐项执行并留证。
@@ -0,0 +1,22 @@
# Node 与 MySQL 系列版本约束需求
## 功能需求
- FR-001:运行时门禁必须以主版本 22 判断 Node.js,不绑定 minor 或 patch。
- FR-002:Schema 生成与验证必须以 major/minor 5.7 判断 mysql 客户端、mysqldump 客户端和 MySQL 服务端,不绑定 patch。
- FR-003:API MySQL 健康检查必须接受任意 5.7.x,并在成功详情中显示实际版本。
- FR-004:MySQL 5.7.x 系列校验不得放宽数据库名、字符集、排序规则、时区或开发环境安全边界。
- FR-005:现行架构、开发规范和部署手册必须使用 Node.js 22.x、MySQL 5.7.x;历史证据中的实际版本不批量改写。
## 质量需求
- 必须测试系列内至少两个不同补丁版本和系列外上下边界。
- 必须遵循 RED → GREEN:先让 5.7.41 被精确 5.7.42 校验拒绝,再实施系列校验。
- `assertMysql57Metadata` 的 GitNexus 风险为 CRITICAL,必须完整回归 Schema 生成、历史验证、当前发布基线和治理启动相关测试。
- 不新增依赖,不增加生产请求、数据库查询或后台任务。
## 安全与性能
- 版本字符串只做固定格式匹配,不执行命令、不拼接 SQL。
- 数据库访问仍限于既有只读元数据查询;本功能不连接生产数据库。
- 运行时只增加常数时间字符串判断,不产生可测量的吞吐或内存影响。
@@ -0,0 +1,52 @@
# GOV-011 代码 Review
- reviewer_type:self
- reviewer:当前实现代理结构化自审
- 基线:`v0.0.8` / `9e85809`
- 审查实现:`cce77aa`
- 日期:2026-08-17
## 审查范围
审查 Node 特征测试、Schema 元数据校验、MySQL 健康客户端、治理测试、现行架构/规范/部署文档、GitNexus 影响和一次性 Schema 例外。重点检查版本格式、错误边界、历史清单兼容、健康信息泄漏和门禁真实性。
## 发现
### 已关闭问题
| 严重程度 | 位置 | 问题 | 处置 |
|---|---|---|---|
| Important | `tools/database/schema-baseline.test.mjs` 历史清单篡改测试 | 完整回归仍断言旧的“服务端必须为 5.7.42”文案,导致生产实现转为系列口径后测试失败。 | 更新为 `5.7.x` 断言;排除已授权发布基线用例后 Schema 28/28。 |
| Minor | `implementation-plan.md` 全量门禁预期 | 原计划把 `verify:release` 写为 PASS,但该命令包含必然触发一次性 Schema 例外的测试。 | 修正文档为真实失败并要求手工执行其余等价门禁。 |
### 未发现问题
未发现未关闭的 Critical、Important 或阻塞性 Minor。服务端正则只接受 `5.7.<数字>` 与 `-`/`+` 后缀;5.6、8.0、无 patch 和文字 patch 均拒绝。字符集、排序规则、库名、时区和生产数据库边界没有放宽。
## 测试缺口
没有针对每个 MySQL 5.7 patch 建立真实数据库兼容矩阵;这是用户明确接受的系列版本策略。本次使用纯函数、固定元数据和现有集成测试验证判断边界,不证明第三方数据库每个 patch 都没有厂商缺陷。首次真实迁移和查询仍必须在目标 5.7.x 环境验证。
## 安全与残余风险
- 版本字符串不执行、不进入 SQL;健康详情不回显原始后缀、地址、账号或密码。
- Schema 入口仍固定 development、开发库和主机白名单;本次未连接生产数据库。
- 残余风险一是不同 5.7 patch 的已知缺陷,二是 v0.0.8 缺少可验证 Schema 基线。前者由真实部署验证控制,后者由用户授权的一次性例外承担。
## 性能与资源影响
- 只增加常数时间正则捕获,没有新增查询、网络、重试、缓存、任务或依赖。
- 健康查询次数和连接池上限不变;Web 构建体积与 v0.0.8 一致。
- 不进入行情采集、分析、Redis、RocketMQ 或图表热路径,无需负载测试。
## GitNexus 与同步修改
开发前 `assertMysql57Metadata` 为 CRITICAL,5 个直接调用方、10 个受影响符号、5 组流程;`MysqlHealthClient` 为 LOW。开发后相对 v0.0.8 为 HIGH、23 文件、70 符号、11 流程,运行影响均属于计划中的 Schema 与 API 健康路径。HTTP/OpenAPI、Web API、消息、数据库 Schema、Redis、Scheduler、Worker 和部署拓扑没有计划外修改。
## v0.0.9 发布封存复核
- 发布只增加版本、CHANGELOG、索引和功能状态,不修改运行时判断、健康查询或数据库边界。
- 一次性 Schema 例外、HIGH GitNexus 风险和手工等价门禁证据均保留,没有改写为全量门禁通过。
- 发布标签必须指向通过上述 Review 的封存提交,并与 Gitea 远程引用核对。
最终结论:passed
@@ -0,0 +1,39 @@
# GOV-011 开发规范符合性 Review
- reviewer_type:self
- reviewer:当前实现代理结构化自审
- 审查提交:`cce77aa`
- 日期:2026-08-17
## 检查结果
- [x] PRD、需求、设计、实施计划、测试计划、开发总结、QA、GitNexus、Review、发布与回退资料齐全。
- [x] 修改关键符号前执行 GitNexus 上游影响分析,提交前执行 detect-changes。
- [x] HIGH/CRITICAL 风险已向用户说明,并以完整 Schema 与健康回归控制。
- [x] 行为修改遵循 RED-GREEN,测试失败原因来自旧实现而非语法或夹具。
- [x] 关键版本口径和安全边界使用准确中文注释,没有逐行复述。
- [x] 未新增依赖、预测性抽象、空分层或过度文件拆分。
- [x] 没有修改前端 Axios/API 分域、后端业务模块分层或 OpenAPI DTO。
- [x] 所有阶段提交使用中文 Conventional Commit 和 GOV-011,并立即推送 Gitea。
- [x] 没有使用 GitHub、强推、生产数据库或真实凭据。
- [x] 历史 QA、Schema 清单和已发布档案保持原样。
## 不符合项与处置
完成门禁无法通过 v0.0.8 Schema 基线存在性校验。该项不是静默忽略:用户在开发前明确确认当前开发库为空并要求本次跳过,仓库保存 `schema-baseline-waiver.md`,实际失败命令和风险写入 QA。没有修改治理工具,也没有伪造 `not_applicable`、`captured_empty` 或空 SQL。除此之外未发现未处置的不符合项。
## 安全、性能与架构检查
安全边界保持固定开发环境、库名、主机白名单、字符集、排序规则和时区;健康输出已脱敏,依赖审计 0 漏洞。性能只增加常数时间字符串匹配,查询、连接池、构建体积和执行流数量没有增加。架构仍为 Vue 3 Web 与 NestJS API/Scheduler/Worker 独立项目、Ubuntu 源码部署和外部 MySQL/Redis/RocketMQ。
## GitNexus 与开发总结检查
before、impact-plan、detected-changes、after、comparison 互相对应;最终索引为 2015 节点、2692 关系、50 流程。开发总结包含七个固定章节,明确原始需求、范围变化、实际完成、缺陷、延期、提交和验证证据;HIGH 风险与一次性 Schema 例外均有具体边界,不以空占位通过门禁。
## v0.0.9 发布封存复核
- VERSION、CHANGELOG、文档索引、manifest、开发总结和发布说明的 v0.0.9 状态必须一致。
- 发布提交和标签分别精确推送;禁止强推、批量推送标签或移动已发布标签。
- 历史 v0.0.8 的 5.7.42 事实不因当前系列口径反向改写。
最终结论:passed
@@ -0,0 +1,24 @@
# GOV-011 回退说明
GOV-011 不修改数据库结构、迁移或数据,不写 Redis,不操作 RocketMQ,也不修改生产配置。回退只涉及版本判断、健康详情、测试、注释和当前规范文档。
## 触发条件
- 合法 MySQL 5.7.x 被错误拒绝,或 5.6/8.x 被错误放行。
- 历史 captured/captured_empty manifest 无法验证。
- 健康接口泄漏原始版本后缀或返回错误 patch。
- 系列判断导致 Schema 生成、治理启动或 API 启动出现无法修复的回归。
## 回退步骤
1. 使用新的中文 Conventional Commit 恢复 `assertMysql57Metadata` 和 `MysqlHealthClient` 到上一已验证行为;禁止重写 Gitea 历史、强推或移动已发布标签。
2. 同步恢复对应测试、代码注释和当前架构/部署文档,避免实现与规范不一致。
3. 不改写已经发布的 GOV-011 档案;通过后续回退记录说明原因、范围和提交。
4. 因无数据库结构或数据变化,不执行数据库回滚。
## 回退验证
- 重新执行 runtime、Schema、MySQL 规范、环境、Server 健康、类型和构建测试。
- 执行 OpenAPI 契约、Playwright 双视口和源码发布验证。
- 运行 GitNexus impact、detect-changes 与 analyze,记录回退实际流程影响。
- v0.0.8 Schema 一次性例外仍只作为历史事实存在,不因代码回退生成伪造基线。
@@ -0,0 +1,22 @@
# v0.0.8 Schema 基线一次性例外
- 功能编号:GOV-011
- 日期:2026-08-17
- 适用范围:仅 GOV-011 开发启动
## 事实记录
按常规流程执行 `pnpm schema:baseline` 时,本机因不存在 MySQL 5.7 `mysql`/`mysqldump` 客户端而在执行 `mysql --version` 前失败,未连接数据库、未生成目录或半成品;随后 `schema:verify` 因 `database/schema-baselines/v0.0.8` 不存在而按设计阻断。
用户确认当前开发库没有业务结构,并明确要求本次先跳过备份。GOV-011 只调整 Node/MySQL 版本系列判断,不创建表、迁移或数据,不读取生产数据库。
## 处理决定
- 不伪造 `not_applicable`、`captured_empty`、空 SQL、版本信息或校验摘要。
- 不修改 `governance:start` 或 Schema 工具增加通用跳过开关。
- 手工保存与 `governance:start` 同等的 GitNexus before/impact 文档,并在 GOV-011 Review 中核对本例外。
- 本例外不自动适用于后续功能;下一次需要 Schema 基线时仍应提供可验证的 MySQL 5.7.x 客户端或由用户再次明确决定。
## 风险
缺少 v0.0.8 Schema 基线意味着无法用仓库证据证明当时开发库为空。该风险由用户接受;GOV-011 不修改数据库,不能借本例外执行任何 Schema 或数据写入。
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More