docs: M2 收官——E2E 烟囱报告与收官总结入档,验收 PASSED
CI / docs-build (push) Successful in 51s

- 28 E2E 烟囱:11/11 场景全绿、契约偏差 0、四条验收标准全过(真机两项方案 A 挂起)
- 29 收官总结:终态对照开工基线(测试 82/34→191/272、契约 5→18 路径冻结、
  ADR 001~015、生产埋点从零到贯通)、遗留清单与 M3 方向输入
- 看板终态更新

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 14:47:29 +08:00
parent 23ce404548
commit fcac68daf2
4 changed files with 486 additions and 4 deletions
@@ -0,0 +1,407 @@
# 28 M2 收官:E2E 烟囱测试报告(T2-18)
- 执行人:Frontend Developer
- 日期:2026-09-08
- 环境:patbond-flutter (dev 分支) + patbond-api (docker compose 编排,代码零改动)
- 测试脚本:`patbond-flutter/test_e2e_m2_manual.dart`commit `720865b`,已推送 origin/dev
- 参照模式:iteration-1/18 号收官报告(格式与取证标准沿用)
---
## 0. 执行概要
### 测试目标
M2 第四波收官(工单 T2-18):在 compose 真实后端上跑通 M2 完整链路烟囱并收集证据——
登录 → 建档 → 记体重 → 登记疫苗 → 记健康事件 → 摘要数值核对 → 第二账号访问被拒 →
第二设备同账号全量读回,外加埋点落库与乐观锁冲突两条链路。
### 测试结果
**✓ 11/11 场景全部通过**(单次运行一次通过;格式化后复跑再次 11/11)
- Docker Compose 四容器健康运行(postgres + auth:8081 + user:8082 + pet:8083
- 契约一致性:响应字段、错误码、HTTP 状态码与冻结契约 openapi v1.2.0 完全一致
- **契约偏差数:0 个**
- Flutter 门禁三命令全绿:`dart format`0 changed/ `flutter analyze`No issues/
`flutter test`**272 passed**
- 数据库证据齐备:`pet_health` 六表 + `platform.product_events` psql 查证一致
### ⚠️ 真机挂起项(显著标注:真机待补验)
真机不可用(用户确认),以下两项按既定方案 A 挂起,**本报告不含其证据**,
待真机可用后补验:
| # | 挂起项 | 说明 |
| --- | --- | --- |
| 1 | **Android 真机事件落库观察** | 本报告以脚本直连 `/api/v1/events`platform=android 模拟真机值)替代验证服务端链路;真机端 AnalyticsClient → 持久化队列 → 上报的端上链路待真机补验 |
| 2 | **SessionTracker 30min 会话超时手测** | 前后台切换超时重建 sessionId 的真机手测;单元测试已覆盖规则(T2-15),真机行为待补验 |
### 脱敏声明
全部 token 截断至前 20 字符 + `<REDACTED>`;密码不出现在任何输出;`.env` 内容未引用。
---
## 1. 后端启动与健康检查
### 1.1 构建与启动(patbond-api 代码零改动)
```bash
cd patbond-api
JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./mvnw -DskipTests package
# BUILD SUCCESS
docker compose up -d --build
# Container patbond-postgres-1 Healthy
# Container patbond-auth-1 Started
# Container patbond-user-1 Started
# Container patbond-pet-1 Started
```
### 1.2 容器健康状态
```text
NAMES STATUS PORTS
patbond-pet-1 Up 12 seconds 0.0.0.0:8083->8083/tcp
patbond-auth-1 Up 12 seconds 0.0.0.0:8081->8081/tcp
patbond-user-1 Up 12 seconds 0.0.0.0:8082->8082/tcp
patbond-postgres-1 Up 15 seconds (healthy) 5432/tcp
```
### 1.3 服务就绪验证
```bash
docker logs patbond-pet-1 | grep Started
# Started PetApplication in 6.286 seconds
curl -s http://127.0.0.1:8083/api/v1/pets
# {"code":40101,"message":"token 无效或过期","data":null} ← 无 token 预期 401
curl -s http://127.0.0.1:8082/api/v1/me
# {"code":40101,"message":"token 无效或过期","data":null}
```
---
## 2. E2E 烟囱测试执行记录(11 场景)
### 2.1 测试脚本
`test_e2e_m2_manual.dart`(纯 dart HttpClient 脚本,无 Flutter 运行时依赖,
与第一迭代 `test_e2e_manual.dart` 并列放仓库根目录,**不在 test/ 目录**、
不进 `flutter test`)。随机生成账号 `e2e_m2_a_<timestamp>` / `e2e_m2_b_<timestamp>`
避免冲突。运行方式:`docker compose up -d``dart run test_e2e_m2_manual.dart`
本次取证运行:账号 A `e2e_m2_a_1788849543120`petId `01a07fbd-dcad-756a-a844-fe5323aa0713`
### 2.2 场景 1:注册账号 A → 登录
```text
[1/11] 注册账号 A → 登录
POST /api/v1/auth/register → 200
✓ 注册成功
userId(A): 01a07fbd-d92f-7ee7-a52c-d33c7fa80071
accessToken: eyJhbGciOiJSUzI1NiJ9...<REDACTED>
POST /api/v1/auth/login → 200
✓ 登录成功(设备 1 会话)
```
### 2.3 场景 2:建档(含品种)→ 列表/详情读回核对
```text
[2/11] 建档(POST /pets,含品种)→ 列表/详情读回核对
GET /api/v1/breeds?species=dog → 200
✓ 品种目录返回 16 条
选用品种: 中华田园犬 (3a545503-a8ad-484a-8bbf-a38d08c6dcea)
POST /api/v1/pets → 201
✓ 建档成功(201
petId: 01a07fbd-dcad-756a-a844-fe5323aa0713
myRole: owner / version: 0 / breedDisplayName: 中华田园犬
✓ 创建者角色为 owner
✓ 品种展示名解出一致
GET /api/v1/pets → 200
✓ 列表读回 1 只宠物且 id 一致
GET /api/v1/pets/{petId} → 200
✓ 详情读回核对通过(name/species/breedId/status
```
契约验证:201 + PetEnvelope、`myRole=owner`(创建者自动 primary owner)、
`breedDisplayName` 由字典解出、petId 为 UUIDv7(前缀 `01a07fbd`)。
### 2.4 场景 3:记体重 ×2 → cursor 分页读回
```text
[3/11] 记体重 ×2 → 列表 cursor 分页读回
POST /weights (8.20kg, 2026-09-06T06:39:04.429336Z) → 201
POST /weights (8.45kg, 2026-09-07T06:39:04.429336Z) → 201
GET /weights?limit=1 → 200
✓ 第一页:最新体重 8.45kg 在前,hasMore=truenextCursor 非空
GET /weights?limit=1&cursor=... → 200
✓ 第二页:8.20kghasMore=falsenextCursor=null
```
契约验证:分页正典形态 `{items, nextCursor, hasMore}``measured_at DESC` 排序;
末页 `nextCursor` 恒为 null。
### 2.5 场景 4:登记疫苗(scheduled)→ 标记完成(乐观锁)
```text
[4/11] 登记疫苗(scheduled)→ 标记完成(PATCH + version
GET /api/v1/vaccine-catalog?species=dog → 200
✓ 疫苗目录返回 6 条
选用疫苗: 犬二联疫苗 (e07d9a48-a8d3-4b6a-a14b-03a42fe85589)
POST /vaccinations (scheduled, plannedOn=2026-09-08) → 201
vaccinationId: 01a07fbd-ddc2-7dc8-aa2e-768a51785dc7 / version: 0
PATCH /vaccinations/{id} (→completed, version=0) → 200
✓ 标记完成成功,version 0→1administeredOn/nextDueOn 回读一致
```
契约验证:`scheduled → completed` 状态机合法迁移;`version` 提交比对通过后 +1
`vaccineName` 由目录解出;`administeredOn=2026-09-08``nextDueOn=2027-09-08` 原样回读。
### 2.6 场景 5:记健康事件(金额整数分)→ 时间线读回
```text
[5/11] 记健康事件(amountCents 整数分)→ 时间线读回
POST /health-events (medical, amountCents=12500) → 201
✓ amountCents=12500 原样回读,createdByUserId=token subject
healthEventId: 01a07fbd-de0a-7532-8d71-023452ba21ad
GET /health-events → 200
✓ 时间线读回 1 条且字段一致
```
契约验证:金额整数分传输无精度损耗;`createdByUserId` 取自验签 token
(等于账号 A userId),不收请求体。
### 2.7 场景 6:创建提醒 → 标记完成(completedAt 校验)
```text
[6/11] 创建提醒 → 标记完成(completedAt 校验)
POST /care-reminders (deworming, dueAt=2026-10-08T06:39:04.429336Z) → 201
✓ 提醒创建成功,恒为 pending 且 completedAt=null
reminderId: 01a07fbd-de48-779f-87f6-11135ae93be7
PATCH /care-reminders/{id} (→completed) → 200
✓ 标记完成成功,completedAt=2026-09-08T06:39:04.429336Z(客户端提交时刻回读)
```
契约验证:创建恒为 `pending`(不收 status);`completedAt` 由客户端提交、
非空当且仅当 `status=completed`
### 2.8 场景 7:摘要四项聚合逐项断言
```text
[7/11] GET /summary?tz=Asia/Shanghai 四项聚合逐项断言
GET /summary → 200
✓ 最新体重 = 8.45kg(第二条写入,measured_at DESC 首行)
✓ 疫苗进度 = 1/1scheduled→completed 后)
✓ 下次接种 = completed 行的 nextDueOn2027-09-08source=nextDue
✓ 当月花费 = 12500 分,month=2026-09timezone 回显 Asia/Shanghai
```
四项聚合与前述写入逐项一致(口径 = iteration-2 报告 18 §3 定型表):
| 聚合项 | 前述写入 | 摘要返回 | 结论 |
| --- | --- | --- | --- |
| latestWeight | 8.45kgmeasured_at 最新) | weightKg=8.45 | ✓ |
| vaccinationProgress | 1 条 completed / 1 条已登记 | completedDoses=1, totalDoses=1 | ✓ |
| nextVaccination | completed 行 nextDueOn=2027-09-08 | dueOn=2027-09-08, source=nextDue, vaccinationId 命中 | ✓ |
| monthlyExpense | amountCents=12500(当月事件) | amountCents=12500, month=2026-09, timezone=Asia/Shanghai | ✓ |
### 2.9 场景 8:权限拒绝——账号 B 访问 A 的宠物四路(防枚举)
```text
[8/11] 注册账号 B → 用 B 的 token 访问 A 的宠物四路(防枚举核对)
POST /api/v1/auth/register (B) → 200
详情 GET /pets/{id} → 404 / code 40401 ✓
体重 GET /pets/{id}/weights → 404 / code 40401 ✓
疫苗 GET /pets/{id}/vaccinations → 404 / code 40401 ✓
摘要 GET /pets/{id}/summary → 404 / code 40401 ✓
✓ 四路响应体完全一致(防枚举):{"code":40401,"message":"宠物不存在","data":null}
✓ B 的宠物列表为空(列表天然隔离)
```
契约验证:无关系调用者与「宠物不存在」响应逐字节一致,随机探测 UUID 无法区分
是否命中真实记录(防枚举语义)。
### 2.10 场景 9:跨设备读取——账号 A 重新登录全量读回
```text
[9/11] 账号 A 重新登录(模拟第二设备新会话)→ 全量数据读回
POST /api/v1/auth/login (设备 2) → 200
✓ 新会话 token 与设备 1 不同(独立 token family
✓ 宠物列表:1 只(旺财M2
✓ 体重记录:2 条
✓ 疫苗记录:1 条(completed
✓ 健康事件:1 条
✓ 提醒:1 条(completedcompletedAt=2026-09-08T06:39:04.429336Z
```
设备 1 写入的全部五类数据在设备 2 新会话完整读回,服务端为唯一事实源。
### 2.11 场景 10:埋点链路——v2 事件上报与落库
```text
[10/11] POST /api/v1/events 上报 v2 事件(platform=android 模拟真机值)
eventId: 0c673914-... (pet_create_succeeded)
eventId: dd59a83a-... (health_record_create_succeeded, recordType=weight)
eventId: 3993beb4-... (health_record_create_succeeded, recordType=vaccine)
eventId: 87a4a82b-... (page_viewed)
POST /api/v1/events (4 条) → 202
✓ 4/4 逐条 acceptedaccepted=4, duplicated=0, rejected=0
```
**落库查证(docker exec psql**
```text
patbond=# SELECT event_name, event_version, platform, user_id,
left(event_id::text,8) AS event_id_prefix, props
FROM platform.product_events
WHERE session_id = '4d8375a7-ec77-45bf-90d6-1b7eff73a1ff'
ORDER BY event_name;
event_name | event_version | platform | user_id | event_id_prefix | props
--------------------------------+---------------+----------+--------------------------------------+-----------------+-------------------------------------------------------
health_record_create_succeeded | 2 | android | 01a07fbd-d92f-7ee7-a52c-d33c7fa80071 | dd59a83a | {"durationMs": 640, "recordType": "weight"}
health_record_create_succeeded | 2 | android | 01a07fbd-d92f-7ee7-a52c-d33c7fa80071 | 3993beb4 | {"durationMs": 820, "recordType": "vaccine"}
page_viewed | 2 | android | 01a07fbd-d92f-7ee7-a52c-d33c7fa80071 | 87a4a82b | {"pageName": "pet_detail", "referrer": "pet_list"}
pet_create_succeeded | 2 | android | 01a07fbd-d92f-7ee7-a52c-d33c7fa80071 | 0c673914 | {"species": "dog", "petIndex": 1, "durationMs": 1200}
(4 rows)
```
4 条 v2 事件全部落 `platform.product_events`eventId、props 白名单键、
platform=android、user_id 归因逐项一致。(真机端上链路见 §0 挂起项 1。)
### 2.12 场景 11:乐观锁冲突明确性
```text
[11/11] 两次 PATCH 宠物档案提交同一 version → 第二次 409/40902
PATCH /pets/{id} (version=0, 第一次) → 200
✓ 第一次 PATCH 成功,version 0→1
PATCH /pets/{id} (同一过期 version=0, 第二次/设备 2) → 409
✓ 第二次被明确拒绝:409/40902(数据已被修改,请刷新后重试),先写者数据保留
✓ 读回确认先写者数据保留(personality=沉稳)
```
契约验证:不静默覆盖;先写者胜出;后写者得到明确的 409/40902 与可行动 message。
Flutter 端对 40902 的「明确提示 + 取新 version 重提」交互已有 widget 测试覆盖,
`test/features/pets/pet_form_page_test.dart`。)
---
## 3. 数据库查询证据(pet_health schema
```text
patbond=# SELECT name, species, status, version, personality FROM pet_health.pets WHERE id = '01a07fbd-...0713';
name | species | status | version | personality
--------+---------+--------+---------+-------------
旺财M2 | dog | active | 1 | 沉稳
patbond=# SELECT role, is_primary FROM pet_health.pet_owners WHERE pet_id = ...;
role | is_primary
-------+------------
owner | t
patbond=# SELECT weight_kg, measured_at FROM pet_health.pet_weight_records WHERE pet_id = ... ORDER BY measured_at DESC;
weight_kg | measured_at
-----------+-------------------------------
8.45 | 2026-09-07 06:39:04.429336+00
8.20 | 2026-09-06 06:39:04.429336+00
patbond=# SELECT status, dose_no, administered_on, next_due_on, version FROM pet_health.pet_vaccinations WHERE pet_id = ...;
status | dose_no | administered_on | next_due_on | version
-----------+---------+-----------------+-------------+---------
completed | 1 | 2026-09-08 | 2027-09-08 | 1
patbond=# SELECT event_type, title, amount_cents FROM pet_health.health_events WHERE pet_id = ...;
event_type | title | amount_cents
------------+-------------+--------------
medical | M2 烟囱体检 | 12500
patbond=# SELECT reminder_type, status, completed_at FROM pet_health.care_reminders WHERE pet_id = ...;
reminder_type | status | completed_at
---------------+-----------+-------------------------------
deworming | completed | 2026-09-08 06:39:04.429336+00
```
验证点:全部数据持久化落库;`pets.version=1`(一次成功 PATCH 后)与 40902 拒绝语义
互证;`amount_cents` 整数分无损;`completed_at` 与 API 回读一致。
---
## 4. Flutter 门禁验证(三命令随行取证)
### 4.1 格式化检查
```bash
dart format --output=none --set-exit-if-changed lib test
# Formatted 97 files (0 changed) in 0.39 seconds.
# EXIT: 0
```
### 4.2 静态分析
```bash
flutter analyze
# Analyzing patbond-flutter...
# No issues found! (ran in 0.9s)
```
(含根目录两个 E2E 脚本在内全仓 0 issues;两脚本头部 `ignore_for_file: avoid_print`。)
### 4.3 单元/组件测试
```bash
flutter test
# 00:17 +272: All tests passed!
```
**✓ 272 个测试全部通过**(E2E 脚本在仓库根目录,不被 `flutter test` 收集)。
---
## 5. M2 四条验收标准逐条对照
| # | 验收标准 | 证据 | 结论 |
| --- | --- | --- | --- |
| 1 | **跨设备数据一致**:同账号第二设备读到全部数据 | 场景 9:设备 2 新会话读回宠物/体重×2/疫苗/事件/提醒全量一致;§3 psql 证实服务端持久化 | ✓ 通过 |
| 2 | **无权限访问被拒**:他人宠物不可见 | 场景 8:账号 B 四路全部 404/40401 且响应体逐字节一致(防枚举);B 列表为空 | ✓ 通过 |
| 3 | **并发冲突明确**:不静默覆盖 | 场景 4(疫苗 version 0→1+ 场景 11(同 version 二次 PATCH → 409/40902,读回证实先写者保留);前端 40902 交互有 widget 测试 | ✓ 通过 |
| 4 | **双端测试齐备** | 后端:compose 真实链路 11 场景全绿 + 契约测试基线(报告 20);前端:272 单元/组件测试全绿 + 门禁三命令 0 偏差 | ✓ 通过(真机两项挂起,见 §0) |
## 6. 契约偏差声明
**契约偏差数:0 个。**
本次烟囱对照冻结契约 openapi v1.2.0(报告 19 冻结)逐场景核验:HTTP 状态码
200/201/202/404/409)、业务错误码(40401/40902)、信封结构 `{code, message, data}`
分页正典形态、乐观锁语义、防枚举响应体、埋点逐条结果语义,全部一致,无需修复项。
---
## 7. 环境清理
```bash
cd patbond-api && docker compose down
# Container patbond-pet-1 / patbond-auth-1 / patbond-user-1 / patbond-postgres-1 Removed
# Network patbond_default Removed
```
## 8. 工作仓库状态
- patbond-flutter dev`720865b` `test: M2 E2E 烟囱脚本(T2-18 收官)` 已推送 origin/dev
- patbond-api**代码零改动**(仅 compose 起停)
- patbond-doc:本报告(28 号),提交与 mkdocs 导航由 T2-19 文档收口统一处理
## 9. 遗留清单
1. **真机待补验 ×2**(见 §0 显著标注):Android 真机事件落库观察、SessionTracker
30min 会话超时手测——真机可用后按方案 A 补验并追加证据。
2. caregiver/viewer 角色的 403/40300 路径本次未走(M2 无邀请入口,T2-10 已用
测试数据直构场景覆盖,见报告 20),烟囱层面留待 M3 邀请流程落地后自然覆盖。
3. E2E 脚本可在 M3 纳入 CI 定期回归(当前为手动验收工具,与第一迭代建议一致)。
---
**Frontend Developer**
日期:2026-09-08
验收状态:**PASSED**11/11 场景,契约偏差 0,M2 四条验收标准全部通过;真机两项挂起待补验)
@@ -0,0 +1,72 @@
# 29 M2 收官总结:宠物健康档案
**迭代周期**2026-09-07 ~ 2026-09-08(开工分析 + 四波交付)
**验收结论****PASSED**E2E 烟囱 11/11、契约偏差 0、M2 四条验收标准全过;真机两项按方案 A 挂起待补验)
---
## 0. 终态对照开工基线(07 号基线快照)
| 维度 | 开工基线(2026-09-07 | 收官终态(2026-09-08 |
| --- | --- | --- |
| patbond-api 测试 | 82 | **191**+109 |
| patbond-flutter 测试 | 34 | **272**+238 |
| openapi.yaml | v1.0.05 路径 | **v1.2.0 冻结**18 路径/24 操作/45 schema,契约测试锁定零漂移 |
| Flyway | V1/V2 | V1~V4pet_health 8 表 + 字典种子) |
| 后端模块 | common/auth/user | + **patbond-pet**:8083ADR-009 |
| ADR | 001~008 | **001~015** |
| 错误码 | 基础段 | +840300/40401/40402/40902/40903/40904/42201/42202 |
| 档案功能 | Flutter demo 数据 | 全页面族真实后端,demo 消亡 |
| 生产埋点事件流 | **恒为零**(接线断链) | 端到端贯通,字典 v2 13 事件,分段持久化队列 |
| 迭代报告 | — | 29 份入档挂导航,strict 全程通过 |
开工时的 2 个证据缺口均闭环:events 契约缺口第一波补录(v1.1.0);CI 全绿不可复核经 Gitea commit status API 建立实查惯例。
## 1. 交付主线回顾
- **开工分析**(报告 01~08):8 角色并行评估 + 正式 Reality Checker/Experiment Tracker 复核接管;CONDITIONAL PASS 5 项放行条件;ADR-009~015 拍板
- **第一波**(09~12):M1 埋点债清偿(含收口期热修 5 项)+ V3/V4 + pet 骨架;放行条件①②④⑤闭环
- **第二波**13~21):pets 域 18 操作后端纵切 + 契约冻结 v1.2.0 + 契约一致性测试(抓修 1 漂移)
- **第三波**22~27):Flutter 四态页面族接入 + 埋点端到端 + DEBT-1 偿还;三次 compose 实测零偏差
- **第四波**28~29):E2E 烟囱 11 场景收官取证 + 文档收口
## 2. M2 四条验收标准证据索引
| 标准 | 证据 |
| --- | --- |
| 跨设备读取 | 28 号场景 9(新会话五类数据全量读回)+ pet_health 六表 psql 证据 |
| 无权限拒绝 | 28 号场景 8(第二账号四路 404/40401 响应逐字节一致防枚举) |
| 并发冲突明确 | 28 号场景 4/11(40902 + 先写者保留)+ 前端自动重提 widget 测试 |
| 双端测试齐备 | 后端 191 + 前端 272 全绿;契约测试全响应矩阵;门禁三命令 0 偏差 |
## 3. 协作模式沉淀(本迭代新验证项)
- **迭代式契约冻结**:草案先行(TODO-FREEZE 标注)→ 实现定型表回填 → 拍板 → 冻结合入 + 字节级快照锁 CI——比第一迭代的一次性冻结更适应多工单纵切
- **同仓串行、跨仓并行**的派工纪律避免了全部工作树冲突;agent 中断续跑(半成品检查 + 断点续作)实战有效
- 实测取证纪律延续:每波 compose 实测、收官烟囱脚本化、证据脱敏入档
## 4. 遗留与 M3 建议
**挂起待补验(真机到位后,预计 0.5 天)**Android 事件落库观察、SessionTracker 30 分钟手测(脚本在 10 号报告 §5)。
**M2 范围内遗留**
1. T2-12 §8 三项交互待拍板:单宠直进/切换器、归档入口(listPets 过滤语义)、sterilizedOn 编辑
2. auth 域契约测试补齐(机制可复用,S)
3. 埋点队列完善:30s 定时冲刷、退避/429(依赖后端限流)、anonymousId 持久化(15 号 §4
4. 09 号契约-实现出入 5 项排期评估(64KB 上限、429 限流等)
**跨迭代遗留(承自 M1,未变化)**access token 黑名单、/internal 改 mTLS。
**M3 方向输入**
- 照片/media 域(ADR-010 剪出项:对象存储选型 → 上传流程 → 宠物头像/疫苗证书/事件附件;health_event_media 表补建)
- 照护人邀请/绑定流程(ADR-015 后置项,权限框架已就绪)
- 北极星与 H1~H4 假设开始出数(首记日 +8 天成熟,对账 SQL 见 06 号 §6);A/B 前置 8 项按 06 号 §路线推进(目标 M3 末全绿)
- health_record_deleted 事件随删除端点设计
## 5. 收官提交索引
| 仓库 | 收官 HEAD | CI |
| --- | --- | --- |
| patbond-api | dev@64c9b72191 测试) | success |
| patbond-flutter | dev@720865b272 测试 + E2E 脚本) | 待本提交 CI |
| patbond-doc | 本收口提交(29 报告 + 看板终态) | strict 通过 |
@@ -1,7 +1,7 @@
# 第二迭代进展看板
> 目标:M2 宠物健康档案——宠物 CRUD + owner/caregiver/viewer 权限 + 体重/疫苗/健康事件/提醒 + 档案聚合,Flutter 档案页全量替换 demo 数据,依据[开发实施计划](../../development-plan.md)第 7 节。
> 更新日期:2026-09-08第三波收口,待第四波 E2E 收官)。本页是团队共享的进度事实来源,每波工作交付后更新
> 更新日期:2026-09-08**M2 收官,验收 PASSED**)。本页是团队共享的进度事实来源。
## 当前状态一览
@@ -10,8 +10,8 @@
| ✅ 第一波 | M1 遗留埋点清偿(接线/SessionTracker/page_viewed/持久化队列前置)+ 契约补录 events + Flyway V3/V4 + patbond-pet 骨架 |
| ✅ 第二波 | 后端接口纵切 T2-03~08(pets 域 18 操作)+ 契约冻结 v1.2.0 + 契约一致性测试入 CI |
| ✅ 第三波 | Flutter 页面接入 T2-11~14(档案 demo 数据消亡、四态齐备)+ 埋点字典 v2 端到端 + DEBT-1 偿还 |
| 🔜 第四波 | T2-18 E2E 烟囱收官战(需真机/联调配合)→ T2-19 收官总结 |
| ⚠️ 遗留 | 真机补验(Android 事件落库 + SessionTracker 30min第一波方案 A 挂起);T2-12 §8 三项交互待拍板;auth 域契约测试;埋点队列完善30s 定时冲刷/退避/anonymousId 持久化) |
| 第四波 | E2E 烟囱 11/11 全绿、契约偏差 0、M2 四条验收标准全过(报告 28);收官总结见报告 29 |
| ⚠️ 遗留 | 真机补验(Android 事件落库 + SessionTracker 30min,方案 A 挂起);T2-12 §8 三项交互待拍板;auth 域契约测试;埋点队列完善——完整清单见报告 29 §4 |
## 测试与契约演进
@@ -20,7 +20,8 @@
| M2 开工基线 | 82 | 34 | v1.0.05 路径) |
| 第一波收口 | 95 | 51 | v1.1.0+events |
| 第二波收口 | 182 | 64 | **v1.2.0 冻结**18 路径/24 操作/45 schema |
| 第三波收口 | **191** | **272** | v1.2.0(契约测试锁定零漂移) |
| 第三波收口 | 191 | 272 | v1.2.0(契约测试锁定零漂移) |
| **收官(E2E 后)** | **191** | **272**+E2E 烟囱脚本) | v1.2.0E2E 逐场景核验偏差 0 |
## 已完成(附提交)