feat(v2.2): 完成高频读取热路径
This commit is contained in:
@@ -243,3 +243,12 @@ Partitioned tables must include the partition key in every primary key and busin
|
||||
Xiaobao uses two storage shapes: `xiaobao_risk_summaries` keeps one current row per version for fast reads, while `xiaobao_risk_snapshots` stores append-only history for trend analysis.
|
||||
|
||||
The AppData migration path is staged through a pure mapper plus preview service. `AppDataV22MigrationService.preview()` reads the allowed `app_data` keys, maps legacy JSON into partition-key-ready rows, and reports row counts plus skipped records before any insert path is enabled.
|
||||
|
||||
The first V2.2 read layer is query-first and AppData-compatible. `V22QueryModule` exposes scoped read APIs for version detail, requirement pool, workspace, and Xiaobao warning summaries:
|
||||
|
||||
- Version detail reads only the current version's requirements, plans, dev tasks, test cases, and bugs.
|
||||
- Requirement pool queries require `productId`, so list/search/filter operations stay on the `requirements.product_id` partition key.
|
||||
- Workspace reads only the current user's unfinished plans, dev tasks, test cases, and bugs.
|
||||
- Xiaobao warning reads `xiaobao_risk_summaries` first, then maps the precomputed summary into the existing warning UI shape.
|
||||
|
||||
During the V2.2 compatibility window, writes still go through the existing AppData stores. The frontend consumes V2.2 relation-table results for render-heavy pages and falls back to AppData only when the V2.2 read is unavailable or empty.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 开发路线图
|
||||
|
||||
## 当前阶段:V2.1 — 服务端持久化第一阶段
|
||||
## 当前阶段:V2.2 — 分区关系表与高频读取热路径
|
||||
|
||||
业务流程仍保持 V1 的前端 store 形状,但业务数据主存储已切到 NestJS + PostgreSQL `app_data` 文档表。浏览器只保留登录态,不再保存产品、项目、版本、需求、版本详情、成员、任务类型等业务数据。
|
||||
V2.2 已完成第一批高频读取热路径:分区关系表基础、AppData 迁移预演、V2.2 scoped read API,以及版本详情、需求池、与我相关、小宝预警的前端快读接入。业务写入仍保留现有 AppData store 兼容窗口,后续再逐步打开关系表写入和领域 CRUD。
|
||||
|
||||
### 已完成(按时间倒序)
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
- Xiaobao precompute storage foundation added: `xiaobao_risk_summaries` stores the current version risk, and `xiaobao_risk_snapshots` stores historical snapshots.
|
||||
- Prisma schema now includes the V2.2 relational model skeleton, and the legacy `RequirementService` now uses the `(id, product_id)` composite key.
|
||||
- AppData V2.2 migration mapper and preview service added, so legacy JSON can be rehearsed into relation-table rows with counts and skipped-record diagnostics before inserts are enabled.
|
||||
- V2.2 scoped read API added for version detail, requirement pool, workspace, and Xiaobao warning summaries.
|
||||
- Version detail, requirement pool, workspace, sidebar badges, version list Xiaobao indicators, and Xiaobao warning page now prefer V2.2 fast-read data and fall back to AppData only for compatibility.
|
||||
- Requirement pool V2.2 queries require `productId`, avoiding accidental full-table scans against annual hundreds-of-thousands-row data.
|
||||
- Xiaobao warning now consumes precomputed `xiaobao_risk_summaries` before loading heavy AppData task/test/bug/activity documents.
|
||||
- V2.2 completion boundary: read hot paths are complete; writes remain on AppData until the relation-table write APIs are enabled.
|
||||
|
||||
**2026-07-02**
|
||||
- `app_data` 读写增加乐观锁版本:`GET` 返回 `version`,前端保存携带最近版本,后端用 `key + updatedAt` 原子更新
|
||||
|
||||
134
docs/superpowers/plans/2026-07-03-v22-performance-hot-path.md
Normal file
134
docs/superpowers/plans/2026-07-03-v22-performance-hot-path.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# V2.2 Performance Hot Path 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:** Finish V2.2 by moving high-volume read paths from full AppData document scans to partition-key-scoped relation-table queries, with safe AppData fallback for existing writes.
|
||||
|
||||
**Architecture:** Backend exposes read-optimized V2.2 query endpoints for version detail, requirement pool, workspace, and Xiaobao warning summary data. Frontend adds a single mapping layer that converts Prisma-shaped rows into the existing UI types, then pages consume that layer first and fall back to the existing Zustand/AppData stores when the relation tables are unavailable or empty.
|
||||
|
||||
**Tech Stack:** Next.js 14 App Router, Zustand, NestJS, Prisma, PostgreSQL partitioned tables, node:test, Jest.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Frontend V2.2 API Mapping
|
||||
|
||||
**Files:**
|
||||
- Create: `apps/web/lib/v22-api.ts`
|
||||
- Create: `apps/web/lib/v22-api.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
Add `apps/web/lib/v22-api.test.ts` with tests that mock `fetch`, call `loadV22VersionDetailData('version-1')`, and assert:
|
||||
|
||||
```ts
|
||||
assert.equal(calls[1].url.endsWith('/v2.2/versions/version-1/detail-data'), true);
|
||||
assert.equal(result.scope.requirements[0].typeId, 'feature');
|
||||
assert.deepEqual(result.scope.requirements[0].platforms, ['web', 'ios']);
|
||||
assert.equal(result.scope.devTasks[0].taskNo, 'DEV-001');
|
||||
assert.equal(result.scope.devTasks[0].actualStartAt, '2026-01-02T09:00:00.000Z');
|
||||
assert.equal(result.scope.testCases[0].caseNo, 'TC-001');
|
||||
assert.equal(result.scope.bugs[0].bugNo, 'BUG-001');
|
||||
assert.equal(result.scope.plans[0].owner, 'member-1');
|
||||
assert.equal(result.scope.plans[0].startTime, '2026-01-01T00:00:00.000Z');
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `pnpm --filter web test`
|
||||
|
||||
Expected: FAIL because `apps/web/lib/v22-api.ts` does not exist.
|
||||
|
||||
- [ ] **Step 3: Implement minimal mapping layer**
|
||||
|
||||
Create `apps/web/lib/v22-api.ts` exporting:
|
||||
|
||||
```ts
|
||||
loadV22VersionDetailData(versionId: string)
|
||||
loadV22RequirementsPage(query)
|
||||
loadV22WorkspaceData(userId: string)
|
||||
loadV22XiaobaoWarnings(query)
|
||||
```
|
||||
|
||||
The mapper must convert `priority: number` to `P0`-style priorities, `platform` CSV to `platforms[]`, `code` to `taskNo/caseNo/bugNo`, `ownerId` to `owner`, and date-like values to ISO strings.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `pnpm --filter web test`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 2: Version Detail Hot Path
|
||||
|
||||
**Files:**
|
||||
- Modify: `apps/web/app/versions/[id]/page.tsx`
|
||||
|
||||
- [ ] **Step 1: Write or extend testable helper first**
|
||||
|
||||
Use Task 1 mapping tests as the behavior guard for the data shape consumed by the page.
|
||||
|
||||
- [ ] **Step 2: Replace full child-data fetches for read-heavy render**
|
||||
|
||||
In `apps/web/app/versions/[id]/page.tsx`, load `loadV22VersionDetailData(versionId)` in an effect. Use its returned scope for overview, requirement, plan, dev-task, test-case, and bug tab props when available. Keep the existing stores loaded for overview, members, categories, overtime, drawers, and mutations.
|
||||
|
||||
- [ ] **Step 3: Keep fallback behavior**
|
||||
|
||||
If the V2.2 request fails or returns an empty relation scope, keep using `buildVersionDataScope(...)` from AppData stores.
|
||||
|
||||
- [ ] **Step 4: Verify**
|
||||
|
||||
Run: `pnpm --filter web type-check` and `pnpm --filter web test`.
|
||||
|
||||
Expected: both exit 0.
|
||||
|
||||
### Task 3: Backend And Migration Verification
|
||||
|
||||
**Files:**
|
||||
- Already modified: `apps/server/src/modules/migration/*`
|
||||
- Already created: `apps/server/src/modules/v22-query/*`
|
||||
- Modify if needed: `apps/server/src/app.module.ts`
|
||||
|
||||
- [ ] **Step 1: Verify Prisma schema**
|
||||
|
||||
Run: `pnpm --filter server exec prisma validate --schema prisma/schema.prisma`
|
||||
|
||||
Expected: schema validates.
|
||||
|
||||
- [ ] **Step 2: Verify backend types and tests**
|
||||
|
||||
Run: `pnpm --filter server type-check`
|
||||
|
||||
Run from `apps/server`: `$env:NODE_OPTIONS='--max-old-space-size=4096'; .\node_modules\.bin\jest.CMD --runInBand`
|
||||
|
||||
Expected: both exit 0.
|
||||
|
||||
### Task 4: Documentation And Commit
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/architecture.md`
|
||||
- Modify: `docs/roadmap.md`
|
||||
|
||||
- [ ] **Step 1: Document V2.2 completion boundary**
|
||||
|
||||
Update docs to say V2.2 relation tables, import execution, read query API, and version-detail frontend hot path are complete. State that writes still go through AppData during the compatibility window.
|
||||
|
||||
- [ ] **Step 2: Final verification**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
pnpm --filter web type-check
|
||||
pnpm --filter web test
|
||||
pnpm --filter server type-check
|
||||
pnpm --filter server exec prisma validate --schema prisma/schema.prisma
|
||||
```
|
||||
|
||||
Run full backend Jest from `apps/server`.
|
||||
|
||||
- [ ] **Step 3: Commit locally**
|
||||
|
||||
```powershell
|
||||
git add apps/server apps/web docs
|
||||
git commit -m "feat(v2.2): 完成高频读取热路径"
|
||||
```
|
||||
|
||||
Do not push unless the user explicitly asks.
|
||||
Reference in New Issue
Block a user