24 KiB
市场综合概览 TDX 直连实施计划
For agentic workers: REQUIRED SUB-SKILL: Use
superpowers:executing-plansto implement this plan task-by-task with review checkpoints.
Goal: 使用 Nest API 直接读取本机 TDX 隧道,在 Vue 3 首页提供可独立降级的市场综合概览。
Architecture: API 服务通过固定的 127.0.0.1:17710 TDX HTTP 客户端读取只读行情,将 TDX 原始字段映射为版本化市场概览 DTO。首页按摘要、指数、宽度、板块和资金拆分请求,通过 Axios API 文件消费 Nest 接口;浏览器不直接连接 TDX。
Tech Stack: Vue 3、Vue Router、Pinia、Naive UI、Dart Sass、NestJS 11、TypeScript 5.9、Node.js 22.x 内置 fetch、OpenAPI/Swagger、Vitest、Playwright。
Global Constraints
- Node 使用
22.x,MySQL 兼容5.7.x,字符集排序规则为utf8mb4_general_ci。 - TDX 只读访问固定到服务端
http://127.0.0.1:17710/,不得由请求参数传入任意 URL。 - TDX 不可用时显示
unavailable,不得使用离线样本或伪造实时行情回退。 - 前端业务请求只能位于
web/src/api/<业务域>/index.ts,统一调用web/src/utils/request.ts的 Axios 封装。 - 业务代码必须提供准确中文注释;不以原子化为目的过度拆分文件。
- 本功能不启用 MySQL、Redis、RocketMQ、AI、用户体系、交易指令或公网采集链路。
- 不提交 SSH 地址、Tailscale 地址、密钥、密码、
.env、真实原始 TDX 载荷或生产数据。 - 修改符号前必须完成 GitNexus 影响分析;提交前必须执行 GitNexus 变更检测。
- 每个提交使用中文 Conventional Commit,并立即推送当前分支到项目 Gitea。
文件地图
后端
- Modify:
server/libs/config/src/runtime-config.ts,增加 API 专属 TDX 地址和超时配置及严格校验。 - Modify:
deploy/env/development/api.env.example,增加不含凭据的TDX_BASE_URL与TDX_TIMEOUT_MS模板。 - Create:
server/apps/api/src/market-overview/tdx/tdx.types.ts,记录已验证的 TDX 请求、响应和错误类型。 - Create:
server/apps/api/src/market-overview/tdx/tdx.client.ts,封装固定地址、超时、响应大小和脱敏错误。 - Create:
server/apps/api/src/market-overview/tdx/tdx.mapper.ts,转换 TDX 字段和数据口径。 - Create:
server/apps/api/src/market-overview/market-overview.dto.ts,定义 OpenAPI/HTTP 响应 DTO。 - Create:
server/apps/api/src/market-overview/market-overview.service.ts,并行获取模块数据并生成统一快照元数据。 - Create:
server/apps/api/src/market-overview/market-overview.controller.ts,提供五个只读接口。 - Create:
server/apps/api/src/market-overview/market-overview.module.ts,装配 TDX 客户端、服务和控制器。 - Modify:
server/apps/api/src/api.module.ts,注册市场概览模块并注入 API 配置。 - Modify:
server/tools/export-openapi.ts,让 OpenAPI 生成器包含市场概览控制器及其测试替身。 - Modify:
server/openapi/openapi.json,提交生成后的契约。 - Create:
server/apps/api/src/market-overview/tdx/tdx.client.test.ts,测试 TDX 请求、超时、网络错误和响应上限。 - Create:
server/apps/api/src/market-overview/tdx/tdx.mapper.test.ts,测试字段映射、单位和缺失字段。 - Create:
server/apps/api/src/market-overview/market-overview.service.test.ts,测试并行接口、快照时间和模块级降级。 - Create:
server/apps/api/test/market-overview.e2e-spec.ts,测试 HTTP 状态、响应结构和错误映射。
前端
- Modify:
web/src/api/generated/schema.ts,由 OpenAPI 生成命令更新。 - Create:
web/src/types/market-overview.ts,定义页面消费的类型别名和显示状态。 - Create:
web/src/api/market-overview/index.ts,集中封装五个 Axios 请求。 - Create:
web/src/views/market-overview/useMarketOverview.ts,管理并行加载、刷新、模块状态和分析偏好本地存储。 - Create:
web/src/views/market-overview/MarketOverviewPage.vue,组织首屏布局和页面级状态。 - Create:
web/src/views/market-overview/components/MarketConclusion.vue,显示结论、交易状态、更新时间和来源。 - Create:
web/src/views/market-overview/components/MarketDrivers.vue,显示驱动与风险证据。 - Create:
web/src/views/market-overview/components/IndexOverview.vue,显示可点击核心指数。 - Create:
web/src/views/market-overview/components/MarketBreadth.vue,显示涨跌分布、宽度和量能。 - Create:
web/src/views/market-overview/components/SectorOverview.vue,显示可点击板块排行。 - Create:
web/src/views/market-overview/components/FundTrend.vue,显示资金趋势和不可用状态。 - Modify:
web/src/app/router.ts,将/指向市场概览页面。 - Modify:
web/src/app/App.vue与web/src/styles/index.scss,更新应用壳和响应式页面基础样式。 - Create:
web/src/api/market-overview/index.test.ts,测试 API 路径、方法、参数和错误脱敏。 - Create:
web/src/views/market-overview/useMarketOverview.test.ts,测试并行加载、刷新和偏好保存。 - Modify:
web/src/app/App.test.ts,改为验证市场概览首屏语义和状态入口。 - Modify:
web/tests/smoke.spec.ts,增加桌面、窄屏、模块降级和无水平溢出验证。
功能档案
- Modify:
docs/features/FEAT-MO-001-market-overview/requirements.md,同步 TDX 直连和分模块接口范围。 - Modify:
docs/features/FEAT-MO-001-market-overview/design.md,链接本设计并移除旧的样本默认表述。 - Modify:
docs/features/FEAT-MO-001-market-overview/implementation-plan.md,更新为已执行任务索引。 - Modify:
docs/features/FEAT-MO-001-market-overview/test-plan.md,加入 TDX 联调、模块降级、安全和性能证据。 - Create:
docs/features/FEAT-MO-001-market-overview/development-summary.md,记录原始需求、实际完成、缺陷、延期项、提交和验证证据。 - Create:
docs/features/FEAT-MO-001-market-overview/review/code-review.md,记录代码 Review 结论和残余风险。 - Create:
docs/features/FEAT-MO-001-market-overview/review/standards-review.md,记录开发规范符合性 Review。 - Create:
docs/features/FEAT-MO-001-market-overview/tdx-smoke-report.md,只保存脱敏的真实 TDX 字段完整性、耗时和错误分类。
Task 1: 开发门禁、工作区和 TDX 协议基线
Files:
- Modify:
docs/features/FEAT-MO-001-market-overview/gitnexus/impact-plan.md - Create:
docs/features/FEAT-MO-001-market-overview/gitnexus/implementation-baseline.md - Create:
docs/features/FEAT-MO-001-market-overview/tdx-smoke-report.md
Interfaces:
-
Consumes: 已确认设计文档、现有 Tailscale SSH 隧道、开发环境 API 配置。
-
Produces: 新分支和工作区、GitNexus 影响证据、TDX 只读请求方法及脱敏字段基线。
-
Step 1: 创建隔离工作区并确认远程状态
git fetch origin main
git worktree add .worktrees/feat-mo-001-tdx-overview -b codex/feat-mo-001-tdx-overview origin/main
git -C .worktrees/feat-mo-001-tdx-overview status --short --branch
预期:新工作区基于已推送的 9a965fa,不携带主工作区的 AGENTS.md 未提交修改。
- Step 2: 执行开发前门禁并记录结果
pnpm schema:baseline
pnpm schema:verify
npx gitnexus analyze
npx gitnexus impact --repo /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis --scope upstream "ApiModule.register"
npx gitnexus impact --repo /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis --scope upstream "createAppRouter"
npx gitnexus impact --repo /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis --scope upstream "createRequestClient"
预期:Schema 命令只读取开发环境;若本机缺少 MySQL 5.7.x 客户端,沿用已确认的 FEAT-MO-001 一次性 waiver 记录失败,不伪造基线。任何 HIGH/CRITICAL 影响先记录并暂停代码修改。
- Step 3: 用当前 TDX 隧道执行最小只读协议请求
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 返回的公开错误信息调整为仓库文档支持的只读方法,并把最终方法名写入 tdx.types.ts 和冒烟报告。
- Step 4: 提交门禁和协议基线
git add docs/features/FEAT-MO-001-market-overview/gitnexus docs/features/FEAT-MO-001-market-overview/tdx-smoke-report.md
git commit -m "docs(FEAT-MO-001): 建立TDX概览开发基线"
git push -u origin codex/feat-mo-001-tdx-overview
预期:提交只包含治理和脱敏报告,不包含真实 TDX 原始 JSON。
Task 2: 配置和 TDX 客户端
Files:
- Modify:
server/libs/config/src/runtime-config.ts - Modify:
deploy/env/development/api.env.example - Create:
server/apps/api/src/market-overview/tdx/tdx.types.ts - Create:
server/apps/api/src/market-overview/tdx/tdx.client.ts - Create:
server/apps/api/src/market-overview/tdx/tdx.client.test.ts
Interfaces:
-
Consumes: Task 1 的已验证只读请求方法和字段基线。
-
Produces:
ApiRuntimeConfig.tdx、TdxClient.request<TResponse>()、TdxClientError。 -
Step 1: 先写配置和客户端失败测试
it('拒绝非本机 TDX 地址', () => {
expect(() => loadApiConfig({ ...validEnv, TDX_BASE_URL: 'http://example.test' })).toThrow(
'TDX_BASE_URL 必须指向本机回环地址',
);
});
it('将 TDX 超时转换为脱敏错误', async () => {
const client = createTdxClient({ baseUrl: 'http://127.0.0.1:17710', timeoutMs: 50 }, timeoutFetch);
await expect(client.request('get_market_data', { stock_list: ['600519.SH'] })).rejects.toMatchObject({
kind: 'timeout',
});
});
- Step 2: 运行定向测试确认失败
pnpm --filter @a-share-analysis/server exec vitest run apps/api/src/market-overview/tdx/tdx.client.test.ts
预期:因配置字段、客户端工厂和错误类型不存在而失败。
- Step 3: 实现最小配置和客户端
ApiRuntimeConfig 增加:
tdx: Readonly<{
baseUrl: 'http://127.0.0.1:17710';
timeoutMs: number;
}>;
TdxClient 暴露:
interface TdxClient {
request<TResponse>(method: string, params: Record<string, unknown>): Promise<TResponse>;
}
客户端使用 Node 22 内置 fetch,固定 POST /、JSON-RPC 请求体、连接/读取超时和 1 MiB 响应上限;只抛出 timeout、network、protocol、unavailable 四类错误,禁止把 URL、请求头或原始正文放入错误对象。
- Step 4: 运行定向测试确认通过
pnpm --filter @a-share-analysis/server exec vitest run apps/api/src/market-overview/tdx/tdx.client.test.ts
pnpm --filter @a-share-analysis/server typecheck
- Step 5: 提交并推送
git add server/libs/config/src/runtime-config.ts deploy/env/development/api.env.example server/apps/api/src/market-overview/tdx
git commit -m "feat(FEAT-MO-001): 增加TDX直连客户端"
git push
Task 3: 市场概览 DTO、映射和分模块 API
Files:
- Create:
server/apps/api/src/market-overview/tdx/tdx.mapper.ts - Create:
server/apps/api/src/market-overview/tdx/tdx.mapper.test.ts - Create:
server/apps/api/src/market-overview/market-overview.dto.ts - Create:
server/apps/api/src/market-overview/market-overview.service.ts - Create:
server/apps/api/src/market-overview/market-overview.service.test.ts - Create:
server/apps/api/src/market-overview/market-overview.controller.ts - Create:
server/apps/api/src/market-overview/market-overview.module.ts - Modify:
server/apps/api/src/api.module.ts - Create:
server/apps/api/test/market-overview.e2e-spec.ts
Interfaces:
-
Consumes:
TdxClient.request<TResponse>()和ApiRuntimeConfig.tdx。 -
Produces:
GET /api/v1/market-overview/{summary,indices,breadth,sectors,funds},统一响应元数据和模块数据。 -
Step 1: 写 DTO 和映射失败测试
it('将涨跌字段转换为 A 股红涨绿跌口径并保留百分比', () => {
expect(mapIndexQuote({ code: '000001', name: '上证指数', price: 3380.12, change: 28.4 })).toEqual({
code: '000001', name: '上证指数', price: 3380.12, changePercent: 0.86, direction: 'up',
});
});
it('缺少板块数据时返回 partial 而不是抛出整页错误', async () => {
const response = await service.getSectors();
expect(response.status).toBe('partial');
expect(response.warnings).toHaveLength(1);
});
- Step 2: 运行定向测试确认失败
pnpm --filter @a-share-analysis/server exec vitest run apps/api/src/market-overview/tdx/tdx.mapper.test.ts apps/api/src/market-overview/market-overview.service.test.ts
- Step 3: 实现 DTO 和五个服务方法
服务公开以下方法:
getSummary(): Promise<MarketOverviewResponse<SummaryData>>;
getIndices(): Promise<MarketOverviewResponse<IndexData>>;
getBreadth(): Promise<MarketOverviewResponse<BreadthData>>;
getSectors(): Promise<MarketOverviewResponse<SectorData>>;
getFunds(): Promise<MarketOverviewResponse<FundData>>;
每次请求生成 snapshotId 和 asOf,调用已验证的 TDX 只读方法,映射后只返回页面需要字段。单模块错误映射为 partial 或 unavailable,不将 TDX 原始错误透传。
- Step 4: 注册控制器并完成 HTTP 测试
控制器只注入 MarketOverviewService,每个 @Get 方法仅调用对应服务方法并声明 Swagger 成功/不可用响应;模块在 ApiModule.register(config) 中装配 TdxClient 的配置工厂。
pnpm --filter @a-share-analysis/server exec vitest run apps/api/test/market-overview.e2e-spec.ts
预期:五个接口返回 200 或结构化 503,响应不包含 TDX 地址、请求参数或原始载荷。
- Step 5: 提交并推送
git add server/apps/api/src/market-overview server/apps/api/src/api.module.ts server/apps/api/test/market-overview.e2e-spec.ts
git commit -m "feat(FEAT-MO-001): 增加市场概览分模块接口"
git push
Task 4: OpenAPI 契约和前端 API 状态层
Files:
- Modify:
server/tools/export-openapi.ts - Modify:
server/openapi/openapi.json - Modify:
web/src/api/generated/schema.ts - Create:
web/src/types/market-overview.ts - Create:
web/src/api/market-overview/index.ts - Create:
web/src/api/market-overview/index.test.ts - Create:
web/src/views/market-overview/useMarketOverview.ts - Create:
web/src/views/market-overview/useMarketOverview.test.ts
Interfaces:
-
Consumes: 后端五个 OpenAPI 路径和
web/src/utils/request.ts。 -
Produces:
marketOverviewApi、useMarketOverview()、统一模块加载状态和本地分析偏好。 -
Step 1: 先写前端 API 和状态层失败测试
it('使用独立路径请求指数接口', async () => {
const request = vi.fn().mockResolvedValue({ data: { status: 'fresh' } });
await createMarketOverviewApi(request).getIndices();
expect(request).toHaveBeenCalledWith({ method: 'GET', url: '/api/v1/market-overview/indices' });
});
it('一个模块失败时其他模块仍保留结果', async () => {
const state = await useMarketOverview({ summary: okSummary, indices: failed, breadth: okBreadth, sectors: okSectors, funds: failed });
expect(state.summary.status).toBe('ready');
expect(state.indices.status).toBe('error');
});
- Step 2: 运行定向测试确认失败
pnpm --filter @a-share-analysis/web exec vitest run src/api/market-overview/index.test.ts src/views/market-overview/useMarketOverview.test.ts
- Step 3: 生成并校验 OpenAPI 类型
pnpm check:contracts
预期:生成的 JSON 和 TypeScript 契约只包含五个市场概览路径,且 verify-generated-contracts 通过。
- Step 4: 实现 API 文件和 composable
API 文件只调用请求封装:
export function createMarketOverviewApi(requestClient = request) {
return {
getSummary: () => requestClient<SummaryResponse>({ method: 'GET', url: '/api/v1/market-overview/summary' }),
getIndices: () => requestClient<IndicesResponse>({ method: 'GET', url: '/api/v1/market-overview/indices' }),
getBreadth: () => requestClient<BreadthResponse>({ method: 'GET', url: '/api/v1/market-overview/breadth' }),
getSectors: () => requestClient<SectorsResponse>({ method: 'GET', url: '/api/v1/market-overview/sectors' }),
getFunds: () => requestClient<FundsResponse>({ method: 'GET', url: '/api/v1/market-overview/funds' }),
};
}
useMarketOverview() 使用 Promise.allSettled 并行加载,暴露 refresh()、每个模块的 loading/ready/error 状态,以及浏览器 localStorage 中的分析周期和分析引擎偏好;不得存储行情原始载荷。
- Step 5: 运行定向测试和类型检查
pnpm --filter @a-share-analysis/web exec vitest run src/api/market-overview/index.test.ts src/views/market-overview/useMarketOverview.test.ts
pnpm --filter @a-share-analysis/web typecheck
- Step 6: 提交并推送
git add server/tools/export-openapi.ts server/openapi/openapi.json web/src/api/generated/schema.ts web/src/types/market-overview.ts web/src/api/market-overview web/src/views/market-overview/useMarketOverview.ts web/src/views/market-overview/useMarketOverview.test.ts
git commit -m "feat(FEAT-MO-001): 同步市场概览前端契约"
git push
Task 5: Vue 首屏和交互状态
Files:
- Create:
web/src/views/market-overview/MarketOverviewPage.vue - Create:
web/src/views/market-overview/components/MarketConclusion.vue - Create:
web/src/views/market-overview/components/MarketDrivers.vue - Create:
web/src/views/market-overview/components/IndexOverview.vue - Create:
web/src/views/market-overview/components/MarketBreadth.vue - Create:
web/src/views/market-overview/components/SectorOverview.vue - Create:
web/src/views/market-overview/components/FundTrend.vue - Modify:
web/src/app/router.ts - Modify:
web/src/app/App.vue - Modify:
web/src/styles/index.scss - Modify:
web/src/app/App.test.ts - Modify:
web/tests/smoke.spec.ts
Interfaces:
-
Consumes:
useMarketOverview()、市场概览类型和marketOverviewApi。 -
Produces:
/可访问的市场综合概览首屏,包含数据来源、时间、模块状态、依据入口和分析偏好入口。 -
Step 1: 先写页面失败测试
it('首屏显示市场结论、更新时间和 TDX 来源', async () => {
const wrapper = mountMarketOverview({ state: freshState });
expect(wrapper.getByRole('heading', { name: '市场综合概览' })).toBeTruthy();
expect(wrapper.getByText('数据来源:TDX')).toBeTruthy();
expect(wrapper.getByText('更新时间')).toBeTruthy();
});
it('TDX 不可用时显示错误状态而不是实时数据', async () => {
const wrapper = mountMarketOverview({ state: unavailableState });
expect(wrapper.getByText('TDX 数据不可用')).toBeTruthy();
expect(wrapper.queryByText('实时行情')).toBeNull();
});
- Step 2: 运行前端测试确认失败
pnpm --filter @a-share-analysis/web exec vitest run src/app/App.test.ts
- Step 3: 实现首屏和组件状态
页面保持结论优先顺序;指数、板块使用按钮/链接样式保留未来详情页入口;加载、空、部分、过期、错误状态均有明确文案和稳定尺寸。分析周期和分析引擎使用 Naive UI 的选择控件,偏好保存在本地,不触发 TDX 请求参数变化。
- Step 4: 接入路由和应用壳
createAppRouter() 的 / 路由渲染 MarketOverviewPage;应用壳保留可访问 header、main 和 NMessageProvider,不新增无业务意义的导航菜单。
- Step 5: 运行组件、构建和浏览器冒烟
pnpm --filter @a-share-analysis/web exec vitest run src/app/App.test.ts src/views/market-overview
pnpm --filter @a-share-analysis/web build
pnpm verify:e2e -- --project=chromium
预期:桌面和窄屏无横向溢出,TDX 连接不可用时页面仍可读但明确标记不可用。
- Step 6: 提交并推送
git add web/src/views/market-overview web/src/app/router.ts web/src/app/App.vue web/src/styles/index.scss web/src/app/App.test.ts web/tests/smoke.spec.ts
git commit -m "feat(FEAT-MO-001): 完成TDX市场概览首屏"
git push
Task 6: 真实 TDX 联调、文档追踪和 Review
Files:
- Modify:
docs/features/FEAT-MO-001-market-overview/requirements.md - Modify:
docs/features/FEAT-MO-001-market-overview/design.md - Modify:
docs/features/FEAT-MO-001-market-overview/implementation-plan.md - Modify:
docs/features/FEAT-MO-001-market-overview/test-plan.md - Create:
docs/features/FEAT-MO-001-market-overview/development-summary.md - Create:
docs/features/FEAT-MO-001-market-overview/review/code-review.md - Create:
docs/features/FEAT-MO-001-market-overview/review/standards-review.md - Modify:
docs/features/FEAT-MO-001-market-overview/manifest.yaml
Interfaces:
-
Consumes: 已完成的 API、前端页面、脱敏 TDX 基线和测试结果。
-
Produces: 完整功能档案、开发总结、安全/性能证据、代码 Review 和规范 Review。
-
Step 1: 外出 Tailscale 隧道执行真实只读联调
ssh -S "$HOME/.ssh/tdx-windows-tailnet-control" -O check tdx-windows-tailnet
lsof -nP -iTCP:17710 -sTCP:LISTEN
pnpm --filter @a-share-analysis/server exec vitest run apps/api/test/market-overview.e2e-spec.ts
记录接口耗时、字段完整性、模块状态和 TDX 错误分类;报告不保存地址、密钥、完整请求或完整响应。
- Step 2: 更新功能档案
开发总结必须明确:原始需求、范围变化(由分层混合改为 TDX 单路径)、实际完成、修复缺陷、延期项、关键提交、测试/构建/视觉证据和残余风险。需求、设计、测试计划和 manifest 的状态必须一致。
- Step 3: 执行代码 Review 和规范 Review
Review 至少检查:TDX 地址白名单、错误脱敏、模块级降级、请求超时、响应大小、DTO 不透传原始字段、Axios API 边界、中文注释、性能目标、无凭据提交和移动端溢出。问题及处置写入两个 Review 文档。
- Step 4: 完成全量验证和 GitNexus 变更检测
npx gitnexus analyze
npx gitnexus detect-changes --repo /Users/citrons/Documents/Codex/2026-08-12/wo-x/a-share-analysis --scope all
pnpm verify
pnpm verify:source
预期:GitNexus 只显示市场概览、配置、OpenAPI、前端路由和测试相关变更;任何未预期跨模块影响必须先处置。
- Step 5: 执行治理收尾并推送标签(仅在用户批准发布时)
pnpm governance:finish -- FEAT-MO-001 market-overview
git add docs/features/FEAT-MO-001-market-overview
git commit -m "docs(FEAT-MO-001): 完成市场概览开发收尾"
git push
未获发布批准前不创建或推送版本标签;所有提交推送失败时不得标记功能完成。
计划自审
- 设计中的五个分模块接口均在 Task 3、Task 4、Task 5 有对应实现和测试。
- TDX 单一路径、无样本回退、安全、性能、分钟级刷新、错误状态和脱敏报告均有明确任务。
- OpenAPI、前端 Axios API 文件、Nest 分层、中文注释和 GitNexus 门禁均有明确文件及命令。
- 没有
TODO、TBD或未定义的后续函数;TDX 方法名在 Task 1 以实际只读协议验证结果为准并写入类型,避免臆测字段。 - MySQL/Redis/RocketMQ/AI/用户体系未被实现任务隐式引入。