docs(FEAT-MO-005): 编写市场结构实施计划
This commit is contained in:
@@ -0,0 +1,398 @@
|
||||
# 市场结构与成交额趋势实施计划
|
||||
|
||||
> **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:** 为综合概览增加行业/题材排行、资金流向排行和全市场成交额趋势,并保持现有指数、市场宽度和短线情绪模块的独立失败隔离。
|
||||
|
||||
**Architecture:** 在现有 `market-overview` 模块内增加一个连续可读的 `structure` 业务边界。TDX 负责已验证的指数与成交额能力,AKTools 只通过固定白名单适配行业、题材和资金接口;Nest 输出三个独立 HTTP API,Vue 通过 Axios 和 composable 并行消费,任何未验证的数据源都返回明确状态而不生成占位数据。
|
||||
|
||||
**Tech Stack:** NestJS、TypeScript、Vue 3、Axios、TDX HTTP 桥接、AKTools HTTP、OpenAPI/`openapi-typescript`、Vitest/Node test、Playwright。
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-08-25-market-structure-and-turnover-design.md`
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Node 使用 `22.x` 系列;MySQL 使用 `5.7.x`,本切片不启用 MySQL、Redis、RocketMQ。
|
||||
- 数据库若被治理命令读取,只允许 `APP_ENV=development` 的 `a_share_analysis_dev`,字符集 `utf8mb4`、排序规则 `utf8mb4_general_ci`。
|
||||
- 浏览器不得直连 TDX 或 AKTools;所有请求经过 `web/src/utils/request.ts` 和 Nest 服务端固定适配器。
|
||||
- TDX/AKTools 地址、账号、密钥、家庭网络信息、原始行情载荷不得进入仓库、日志或 HTTP 响应。
|
||||
- API 参数必须白名单校验;排序、分类、数量和时间粒度拒绝未知值及超出范围值。
|
||||
- 成交额统一以亿元输出;资金净流入只能使用上游明确字段,不得从涨跌或成交额推导。
|
||||
- 模块状态只能使用 `fresh`、`delayed`、`partial`、`unavailable`;不可用时禁止离线样本和伪造值。
|
||||
- 修改任何函数、类、方法前先运行 GitNexus 影响分析;提交前运行 `gitnexus_detect_changes`。
|
||||
- 每次提交使用带功能编号的中文 Conventional Commit,并立即推送当前分支到项目 Gitea。
|
||||
|
||||
### Task 1: 治理基线与数据源能力探针
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/manifest.yaml`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/prd.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/requirements.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/design.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/test-plan.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/rollback.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/data-source-probe.md`
|
||||
- Create: `tools/probes/market-structure-capability.mjs`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: local TDX bridge configuration and `http://127.0.0.1:8080/api/public/{interface}`.
|
||||
- Produces: a redacted capability table consumed by Tasks 2–4; each endpoint is classified as `usable`, `partial`, or `unavailable`.
|
||||
|
||||
- [ ] **Step 1: Capture the development schema baseline before starting the version.**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
npm run schema:baseline
|
||||
npm run schema:verify
|
||||
```
|
||||
|
||||
Expected: the commands either capture a valid development-only baseline or produce the repository-approved `not_applicable`/`captured_empty` evidence; no production host is contacted.
|
||||
|
||||
- [ ] **Step 2: Start the governance record and refresh GitNexus.**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
npm run governance:start -- FEAT-MO-005 market-structure-turnover
|
||||
```
|
||||
|
||||
Expected: `docs/features/FEAT-MO-005-market-structure-turnover/gitnexus/before.md` and `impact-plan.md` exist and record the baseline commit, schema evidence and current index.
|
||||
|
||||
- [ ] **Step 3: Implement the probe as a read-only script.**
|
||||
|
||||
The script must call these fixed candidates and output only status, elapsed time, row count, keys, first/last timestamp and a short error class:
|
||||
|
||||
```js
|
||||
const candidates = [
|
||||
'stock_board_industry_spot_em',
|
||||
'stock_board_concept_spot_em',
|
||||
'stock_sector_fund_flow_rank',
|
||||
'stock_market_fund_flow',
|
||||
'stock_zh_a_spot_em',
|
||||
];
|
||||
```
|
||||
|
||||
For TDX, call `get_market_data` for `000001.SH`, `399001.SZ`, and `899050.BJ` with `period` values `1m`, `5m`, `15m`, and `1d`; report whether `Date` and `Amount` are aligned and whether timestamps are intraday.
|
||||
|
||||
- [ ] **Step 4: Run the probe twice after market close and once during a trading session.**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
node tools/probes/market-structure-capability.mjs --base-url http://127.0.0.1:8080
|
||||
```
|
||||
|
||||
Expected: the report distinguishes “收盘后最后一条记录” from actual盘中 freshness, records HTTP 500/timeout separately, and does not store raw rows or URLs beyond the configured local base URL.
|
||||
|
||||
- [ ] **Step 5: Decide source mapping in the feature record.**
|
||||
|
||||
Write one of these explicit outcomes for each metric: TDX primary, AKTools supplement, derived from validated snapshots, or deferred as unavailable. Do not begin Tasks 2–4 until the mapping and field definitions are recorded.
|
||||
|
||||
- [ ] **Step 6: Commit the probe and governance documents.**
|
||||
|
||||
```bash
|
||||
git add docs/features/FEAT-MO-005-market-structure-turnover tools/probes/market-structure-capability.mjs
|
||||
git commit -m "docs(FEAT-MO-005): 建立市场结构数据源探针"
|
||||
git push origin HEAD
|
||||
```
|
||||
|
||||
### Task 2: 建立结构领域类型、映射和来源客户端
|
||||
|
||||
**Files:**
|
||||
- Create: `server/apps/api/src/market-overview/structure/market-structure.types.ts`
|
||||
- Create: `server/apps/api/src/market-overview/structure/market-structure.mapper.ts`
|
||||
- Create: `server/apps/api/src/market-overview/structure/market-structure.mapper.test.ts`
|
||||
- Create: `server/apps/api/src/market-overview/structure/aktools-structure.client.ts`
|
||||
- Create: `server/apps/api/src/market-overview/structure/aktools-structure.client.test.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/market-overview.dto.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/tdx/tdx.types.ts` only if the probe confirms an intraday TDX response shape.
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Task 1 source mapping and raw TDX/AKTools rows.
|
||||
- Produces: `SectorRankingRecord`, `CapitalFlowRecord`, `TurnoverPoint`, `MarketStructureSourceClient`, and pure mappers that reject invalid dates, negative amounts, duplicate timestamps and unknown categories.
|
||||
|
||||
- [ ] **Step 1: Run symbol-level GitNexus impact before editing shared DTOs.**
|
||||
|
||||
Run impact analysis for `MarketOverviewMetaDto`, `MarketOverviewService`, and `createAktoolsClient` with upstream direction. Record direct callers and affected flows in `gitnexus/impact-plan.md`; if risk is HIGH or CRITICAL, stop and obtain explicit scope confirmation.
|
||||
|
||||
- [ ] **Step 2: Write failing mapper tests.**
|
||||
|
||||
Cover these exact cases:
|
||||
|
||||
```ts
|
||||
expect(mapSectorRanking({ category: 'industry', name: '半导体', changePercent: '2.5' })).toMatchObject({ changePercent: 2.5 });
|
||||
expect(mapSectorRanking({ category: 'unknown', name: 'X' })).toBeNull();
|
||||
expect(mapTurnoverPoints([{ time: '2026-08-25 09:35', amount: '10' }, { time: '2026-08-25 09:30', amount: '8' }])).toEqual({ points: [], invalidCount: 2 });
|
||||
expect(mapCapitalFlow({ netInflow: 'N/A' }).netInflow).toBeNull();
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Implement source clients with fixed endpoint allowlists.**
|
||||
|
||||
`AktoolsStructureClient` may call only endpoints classified usable by Task 1. It must apply the existing timeout, response-size limit, JSON validation and error redaction pattern. It must not accept an arbitrary interface name from a request query.
|
||||
|
||||
- [ ] **Step 4: Implement pure mappers and source-specific unit tests.**
|
||||
|
||||
Convert provider field names to domain fields, normalize amounts to亿元, preserve `source`, `tradeDate` and `asOf`, and return `null` for unknown money definitions instead of zero.
|
||||
|
||||
- [ ] **Step 5: Run focused tests and commit.**
|
||||
|
||||
```bash
|
||||
pnpm --filter @a-share-analysis/server test -- market-structure.mapper aktools-structure.client
|
||||
git add server/apps/api/src/market-overview/structure server/apps/api/src/market-overview/market-overview.dto.ts
|
||||
git commit -m "feat(FEAT-MO-005): 建立市场结构数据映射边界"
|
||||
git push origin HEAD
|
||||
```
|
||||
|
||||
### Task 3: 实现行业、题材和板块排行 API
|
||||
|
||||
**Files:**
|
||||
- Create: `server/apps/api/src/market-overview/structure/market-structure.dto.ts`
|
||||
- Create: `server/apps/api/src/market-overview/structure/market-structure.service.ts`
|
||||
- Create: `server/apps/api/src/market-overview/structure/market-structure.controller.ts`
|
||||
- Create: `server/apps/api/src/market-overview/structure/market-structure.service.test.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/market-overview.module.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `MarketStructureSourceClient` and Task 2 mappers.
|
||||
- Produces: `GET /api/v1/market-overview/sector-rankings?category=industry|concept|board&sort=rise|fall|turnover&limit=1..100`.
|
||||
|
||||
- [ ] **Step 1: Add controller validation tests for category, sort and limit.**
|
||||
|
||||
Reject `category=stock`, `sort=unknown`, `limit=0`, `limit=101` and non-integer limits with a 400 response; accept `industry`, `concept`, `board`, `rise`, `fall`, `turnover` and limits 1–100.
|
||||
|
||||
- [ ] **Step 2: Add service tests for sorting and status.**
|
||||
|
||||
Verify descending rise/fall/turnover order, top-N truncation, `partial` when one category source fails, `unavailable` when all rows fail, and `delayed` when the latest trade date is not the current Shanghai trading date.
|
||||
|
||||
- [ ] **Step 3: Implement DTOs and service.**
|
||||
|
||||
Return `category`, `code`, `name`, `changePercent`, `turnoverAmount`, `advancingCount`, `decliningCount`, `leader`, and `tradeDate`; omit fields that the source cannot substantiate rather than filling zeros.
|
||||
|
||||
- [ ] **Step 4: Register the structure controller/provider and run the server suite.**
|
||||
|
||||
```bash
|
||||
pnpm --filter @a-share-analysis/server test
|
||||
pnpm --filter @a-share-analysis/server typecheck
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Commit the endpoint.**
|
||||
|
||||
```bash
|
||||
git add server/apps/api/src/market-overview
|
||||
git commit -m "feat(FEAT-MO-005): 增加行业题材板块排行接口"
|
||||
git push origin HEAD
|
||||
```
|
||||
|
||||
### Task 4: 实现资金流向 API
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/apps/api/src/market-overview/structure/market-structure.dto.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/structure/market-structure.service.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/structure/market-structure.controller.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/structure/market-structure.service.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Task 1 confirmed fund-flow endpoint and Task 2 `CapitalFlowRecord`.
|
||||
- Produces: `GET /api/v1/market-overview/capital-flow?category=industry|concept|board&sort=inflow|outflow&limit=1..100`.
|
||||
|
||||
- [ ] **Step 1: Add failing tests for explicit money definitions.**
|
||||
|
||||
Assert that a row without a documented net-flow field returns `netInflow=null`, `flowDefinition='unavailable'`; assert that the API never derives net flow from `changePercent` or `turnoverAmount`.
|
||||
|
||||
- [ ] **Step 2: Implement field mapping and sorting.**
|
||||
|
||||
Sort only validated numeric fields, preserve `null` at the end, and include the provider definition text in `flowDefinition`.
|
||||
|
||||
- [ ] **Step 3: Add partial and unavailable behavior tests.**
|
||||
|
||||
One failed category request must preserve other category data with `partial`; all failed requests return `data=null` and `unavailable`.
|
||||
|
||||
- [ ] **Step 4: Run focused server tests and commit.**
|
||||
|
||||
```bash
|
||||
pnpm --filter @a-share-analysis/server test -- market-structure.service
|
||||
git add server/apps/api/src/market-overview/structure
|
||||
git commit -m "feat(FEAT-MO-005): 增加行业题材资金流向接口"
|
||||
git push origin HEAD
|
||||
```
|
||||
|
||||
### Task 5: 实现全市场成交额趋势 API
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/apps/api/src/market-overview/structure/market-structure.dto.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/structure/market-structure.service.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/structure/market-structure.controller.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/structure/market-structure.service.test.ts`
|
||||
- Modify: `server/apps/api/src/market-overview/tdx/tdx.types.ts` and `server/apps/api/src/market-overview/tdx/tdx.mapper.ts` only when Task 1 confirms TDX intraday Amount.
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: validated TDX intraday Amount or the explicitly approved AKTools fallback.
|
||||
- Produces: `GET /api/v1/market-overview/turnover-trend?interval=5|15&tradeDate=YYYYMMDD` with `TurnoverPoint[]`.
|
||||
|
||||
- [ ] **Step 1: Add failing tests for point integrity.**
|
||||
|
||||
Cover aligned timestamps, 5/15-minute interval validation, cumulative amount calculation, negative values, duplicate timestamps, date mismatch, and close-after-market handling.
|
||||
|
||||
- [ ] **Step 2: Implement trend mapping.**
|
||||
|
||||
Sort points by time, reject invalid points, calculate `cumulativeAmount` from accepted interval amounts, and report `invalidPointCount` through a warning rather than silently repairing data.
|
||||
|
||||
- [ ] **Step 3: Implement API status rules.**
|
||||
|
||||
Return `fresh` only when the latest point is within the validated trading-session freshness window; after close, use the latest trading date and expose the final timestamp without calling it delayed solely because the market is closed.
|
||||
|
||||
- [ ] **Step 4: Run server tests and commit.**
|
||||
|
||||
```bash
|
||||
pnpm --filter @a-share-analysis/server test -- market-structure
|
||||
git add server/apps/api/src/market-overview
|
||||
git commit -m "feat(FEAT-MO-005): 增加全市场成交额趋势接口"
|
||||
git push origin HEAD
|
||||
```
|
||||
|
||||
### Task 6: 生成契约并接入前端数据层
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/openapi/openapi.json`
|
||||
- Modify: `web/src/api/generated/schema.ts`
|
||||
- Create: `web/src/api/market-overview/structure.ts`
|
||||
- Modify: `web/src/api/market-overview/index.ts`
|
||||
- Modify: `web/src/types/market-overview.ts`
|
||||
- Modify: `web/src/views/market-overview/useMarketOverview.ts`
|
||||
- Test: `web/src/api/market-overview/structure.test.ts`
|
||||
- Test: `web/src/views/market-overview/useMarketOverview.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Tasks 3–5 OpenAPI routes and DTOs.
|
||||
- Produces: typed `getSectorRankings`, `getCapitalFlow`, `getTurnoverTrend` methods and composable states with independent loading/error handling.
|
||||
|
||||
- [ ] **Step 1: Regenerate contracts instead of hand-editing generated files.**
|
||||
|
||||
```bash
|
||||
pnpm check:contracts
|
||||
```
|
||||
|
||||
Expected: OpenAPI and generated TypeScript schema match; boundary verification passes.
|
||||
|
||||
- [ ] **Step 2: Add Axios API wrappers.**
|
||||
|
||||
Each wrapper must call `/api/v1/market-overview/...` through `request.ts`, pass only typed query parameters, and never expose the AKTools base URL.
|
||||
|
||||
- [ ] **Step 3: Extend `useMarketOverview`.**
|
||||
|
||||
Add independent `sectorRankings`, `capitalFlow`, and `turnoverTrend` states; include them in `isLoading`, `setLoading`, and `refresh` without coupling their errors to existing `sectors` or `funds` states.
|
||||
|
||||
- [ ] **Step 4: Add API and composable tests.**
|
||||
|
||||
Assert query serialization, typed response assignment, parallel loading, and one-module failure isolation.
|
||||
|
||||
- [ ] **Step 5: Commit the contract/data-layer change.**
|
||||
|
||||
```bash
|
||||
git add server/openapi web/src/api web/src/types web/src/views/market-overview/useMarketOverview.ts
|
||||
git commit -m "feat(FEAT-MO-005): 接入市场结构前端数据层"
|
||||
git push origin HEAD
|
||||
```
|
||||
|
||||
### Task 7: 实现首屏排行与成交额趋势组件
|
||||
|
||||
**Files:**
|
||||
- Create: `web/src/views/market-overview/components/SectorRankingPanel.vue`
|
||||
- Create: `web/src/views/market-overview/components/CapitalFlowPanel.vue`
|
||||
- Create: `web/src/views/market-overview/components/TurnoverTrendPanel.vue`
|
||||
- Modify: `web/src/views/market-overview/MarketOverviewPage.vue`
|
||||
- Modify: `web/src/styles/index.scss`
|
||||
- Test: `web/src/views/market-overview/components/MarketStructurePanels.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Task 6 composable states and generated response types.
|
||||
- Produces: scan-friendly category tabs, sortable rankings, click-through detail events, and a responsive amount trend chart.
|
||||
|
||||
- [ ] **Step 1: Write component tests before implementation.**
|
||||
|
||||
Cover loading, empty, unavailable, partial and delayed states; category switching; rise/fall/inflow/outflow sorting controls; `亿元` labels; and no rendering of unsupported null money values as zero.
|
||||
|
||||
- [ ] **Step 2: Implement ranking panels.**
|
||||
|
||||
Show a bounded top/bottom list on the overview, provide an accessible “查看全部” command, and emit a detail event only for validated `code` and `category` values.
|
||||
|
||||
- [ ] **Step 3: Implement the turnover trend chart.**
|
||||
|
||||
Use the existing lightweight chart conventions in the repository; draw interval amount and cumulative amount with stable dimensions, visible units and no SVG/network dependency that introduces a new package.
|
||||
|
||||
- [ ] **Step 4: Integrate panels without nesting cards.**
|
||||
|
||||
Keep the page sections full-width within the existing overview grid, preserve the current index/breadth/short-term panels, and avoid a single card containing multiple framed cards.
|
||||
|
||||
- [ ] **Step 5: Run front-end tests and typecheck.**
|
||||
|
||||
```bash
|
||||
pnpm --filter @a-share-analysis/web test
|
||||
pnpm --filter @a-share-analysis/web typecheck
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Commit the UI change.**
|
||||
|
||||
```bash
|
||||
git add web/src/views/market-overview
|
||||
git commit -m "feat(FEAT-MO-005): 展示市场结构与成交额趋势"
|
||||
git push origin HEAD
|
||||
```
|
||||
|
||||
### Task 8: 端到端验证、Review 与治理收尾
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/features/FEAT-MO-005-market-structure-turnover/test-plan.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/review/code-review.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/review/standards-review.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/development-summary.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/release-notes.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/qa-report.md`
|
||||
- Create: `docs/features/FEAT-MO-005-market-structure-turnover/gitnexus/after.md`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: all implementation tasks, probe report and generated contracts.
|
||||
- Produces: repeatable verification evidence, two passed Reviews, final GitNexus comparison and a releasable feature record.
|
||||
|
||||
- [ ] **Step 1: Run focused and full verification.**
|
||||
|
||||
```bash
|
||||
pnpm lint
|
||||
pnpm typecheck
|
||||
pnpm test
|
||||
pnpm build
|
||||
pnpm verify:e2e
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify the HTTP contract and real service states.**
|
||||
|
||||
During one trading session and once after close, call the three new routes and record status, row count, trade date, last timestamp, warning count and response duration without saving raw payloads.
|
||||
|
||||
- [ ] **Step 3: Run visual verification.**
|
||||
|
||||
Use Playwright at desktop and 390px mobile widths. Assert the page is nonblank, no page-level horizontal overflow exists, ranking text fits, and the trend chart has nonzero SVG/canvas pixels.
|
||||
|
||||
- [ ] **Step 4: Run GitNexus final detection and refresh.**
|
||||
|
||||
```bash
|
||||
npx gitnexus analyze
|
||||
npx gitnexus status
|
||||
```
|
||||
|
||||
Run `gitnexus_detect_changes({ scope: "staged" })`, compare affected flows with `gitnexus/before.md`, and record any unexpected module impact before Review.
|
||||
|
||||
- [ ] **Step 5: Complete both Reviews.**
|
||||
|
||||
Code Review must inspect source allowlists, status rules, field口径, error isolation, performance and tests. Standards Review must inspect Chinese comments, API folder boundaries, security evidence, performance evidence, documentation traceability and commit/push history. Both documents must end with `passed` only after issues are resolved.
|
||||
|
||||
- [ ] **Step 6: Finish governance and push the final record.**
|
||||
|
||||
```bash
|
||||
npm run governance:finish -- FEAT-MO-005 market-structure-turnover
|
||||
git add docs/features/FEAT-MO-005-market-structure-turnover
|
||||
git commit -m "docs(FEAT-MO-005): 完成市场结构功能治理收尾"
|
||||
git push origin HEAD
|
||||
```
|
||||
|
||||
Expected: feature record is complete, final GitNexus report is saved, and no required task remains undocumented.
|
||||
Reference in New Issue
Block a user