Files
a-share-analysis/docs/features/GOV-009-application-scaffold-baseline/implementation-plan.md
T

30 KiB
Raw Blame History

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、域名和空主机被拒绝。期望值直接使用固定路径和错误类型,不复用实现常量。

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: 实现固定配置解析与白名单

在代码内使用不可变集合,不读取动态白名单变量:

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 为空时调用:

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:

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
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 只包含:

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:

const app = createApp(App);
installAppProviders(app);
app.mount('#app');

Vite envDir 指向 ../deploy/env/development,开发模式通过 --mode web 加载 web.env.local;生产构建只接受部署注入的 VITE_ 值。样式仅建立字体、颜色 token、页面高度和可访问焦点基线,不提前设计市场概览。

  • Step 4: 运行单测、类型和构建

Run:

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 配置接口固定:

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:

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 内部契约
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 明确:

{
  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 和文档追溯。两份报告必须包含精确行:

最终结论: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:架构复核文档已生成,正在向用户论证并等待确认。
  • Task 8 Step 7:未执行;用户确认前禁止创建或推送 v0.0.8。
  • Task 8 Step 8:开发后图谱已刷新到 95b8611;最终档案提交后还需再次刷新并核对远端。

Docker 后续执行口径

用户于 2026-08-13 决定:Docker 暂不作为后续日常开发与阶段验收的必跑项,待核心功能完整后再决定是否保留 Docker 部署。现有 Docker/Compose 文件与本次已通过的历史验证不删除;后续日常执行 pnpm verify,只有最终交付且用户确认继续采用 Docker 时才执行 pnpm verify:docker 或 pnpm verify:release。