You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
chajia/docs/查价系统-工程任务拆解-v1.2.md

1719 lines
68 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 查价系统 工程任务拆解清单 v1.2
| 版本 | 日期 | 说明 |
|------|------|------|
| v1.0 | 2026-06-16 | 首版原子任务拆解 |
| v1.1 | 2026-06-16 | 对照 Traceability Matrix 补齐;口径对齐 PRD v0.4 |
| v1.1.1 | 2026-06-16 | **按推荐开发依赖顺序重排任务章节**(非 Task ID 数字序) |
| v1.2 | 2026-06-16 | 对齐 PRD v0.6 + 技术设计 v1.2;基线 001118 已完成;增量 119135 |
> **当前版本请使用本文件v1.2)。** v1.1 文件保留作历史对照。
> 配套文档:[查价系统-PRD.md](./查价系统-PRD.md)v0.6)· [查价系统-技术设计.md](./查价系统-技术设计.md)v1.2)· [查价系统-UI设计.md](./查价系统-UI设计.md) · [查价系统-Traceability-Matrix-v1.0.md](./查价系统-Traceability-Matrix-v1.0.md)
> **v1.1 基线task-001~118除废止= 已完成v1.2 增量task-119~135= PRD v0.6 + 技术设计 v1.2 待交付。**
---
## 开发顺序总览(自上而下执行)
| Phase | 名称 | Task 序列 | 状态 |
|-------|------|-----------|------|
| 0 | 环境与底座 | 072→073→**119→120**→070→071→097→030 | 072030 已完成119120 待执行 |
| 1 | 基础设施与缓存 | 096→031~036→035-ip | 已完成 |
| 2 | 鉴权 | 001~005→098 | 已完成 |
| 3 | 领域逻辑 | 040~044→010~014,092,095,109,111,019 | 已完成 |
| 4 | API 层 | 015~017→042~043→018 | 已完成 |
| 5.0 | RPA 录制前置 | **121→122** | 已完成 |
| 5 | RPA v1.2 重构 | **123→131**(基线 020029,110,093,099,100 已完成) | 123131 待执行 |
| 6 | 预警/审计 | 050~057→094→105 | 已完成 |
| 7 | 观测指标 | 101→102 | 已完成 |
| 8 | 前端 | 060~069→106→063,064,079,103,104→**132**→080 | 132 已完成 |
| 9 | 测试/CI | 081~118→**133→135**→091 | 133135 待执行 |
| — | 已废止 | 075~078 | — |
**里程碑 M1Phase 0~4**:已完成 — `POST /quotes` L2 命中、幂等、校验 400。
**里程碑 M2v1.2**`RPA_MOCK_MODE=false` 下 `scripts/probe-rpa.ts` **连续 3 次 exit 0**,四档 `source_type=rpa`TC-601 + §12.7 Go/No-Go
---
## 模块索引(按职能归类,非执行顺序)
| 模块 | Task ID | 数量 |
|------|---------|------|
| 数据库DB | 070073 | 4 |
| 基础设施Lib | 096098, **119120** | 5 |
| 缓存系统 | 030036, 035-ip | 8 |
| 用户系统Auth | 001005 | 5 |
| 加价系统Markup | 040044 | 5 |
| 查价核心Quote Engine | 010019, 092, 095, 109, 111, **129** | 15 |
| API 路由 | 015018, 042043 | 6 |
| RPA 系统 | 020029, 093, 099100, 110, **121131** | 23 |
| 预警系统Alert | 050057, 094, 105 | 10 |
| 观测与指标 | 101102 | 2 |
| 前端 UI | 060080, 103104, 106, **132** | 19 |
| 测试系统 | 081091, 112118, **133135** | 21 |
| **合计(可执行)** | | **~119** |
| **已废止** | 075078 | 4 |
## 技术栈约定
- Next.js 15 App Router + TypeScript
- MySQL 8.0 + Prisma ORM
- Redis 7 + BullMQ
- PlaywrightRPA Worker
- Tailwind CSS + shadcn/ui + phosphor-icons
## v1.1 口径冻结(对齐 PRD v0.4,基线已完成)
| 决策 | 规则 | 任务影响 |
|------|------|----------|
| GD-11 嵌入形态 | 查价 UI 为**宿主内嵌组件**,中台仅 admin 管理端 | task-106 替代 075077task-064 仅 admin |
| §2.3 加价配置 | 中台**不提供**运营加价 UI由宿主调 API | task-078 **废止**task-042/043 保留 |
| 四档报价 | GD-1/TC-102 为准quotes=4 | task-088/111 按 4 档验收 |
| Fallback | 独立 FallbackOrchestrator 模块 | task-092 |
| 管理端 RPA | §3.1 预警 + RPA/开发进度 | task-093, 103, 104 |
| audit / metrics | §10.6 audit log + GD-4 三率 | task-094, 101, 102, 117 |
## v1.2 口径冻结(对齐 PRD v0.6 / 技术设计 v1.2
| 决策 | 规则 | 任务影响 |
|------|------|----------|
| GD-15 入口 URL | `MOTHERSHIP_QUOTE_URLS` headed 录制;禁止 dashboard / `/quote` | task-119, 121, 122, 123 |
| 入口 vs 抓取错误 | 入口错误与抓取错误分开分类;地址未锁定单独处理 | task-125, 128, 129 |
| 新错误码 | `QUOTE_ENTRY_UNAVAILABLE`、`ADDRESS_SUGGESTION_NOT_FOUND` | task-128, 110基线 |
| QuotePageAdapter | 多 URL 探测 + storageState + login 无凭据→STRUCT_CHANGE | task-123, 124 |
| Selector env 化 | 全部 `RPA_SELECTOR_*`,禁止手猜 selector | task-125127 |
| probe 门禁 | 连续 3 次 exit 0 + 四档 | task-130, 133135 |
| Bull Board | `/admin/queues` 队列监控P1 | task-132 |
## v1.0 → v1.1 变更摘要
| 类型 | Task | 说明 |
|------|------|------|
| 新增 | 092118除重复编号 | 见各 Phase 章节 |
| 修订 | 005, 014, 016, 018, 029, 050, 064, 065, 066, 079, 085, 091 | 补 RBAC/置信度/Fallback 引用等 |
| 废止 | 075, 076, 077, 078 | PRD v0.4 口径下不交付 |
| 替代 | 106 | 宿主内嵌查价组件(替代 075 |
| 排序 | v1.1.1 | 正文按 Phase 0→9 开发顺序排列 |
## v1.1 → v1.2 变更摘要
| CHG ID | 类型 | Task | 说明 |
|--------|------|------|------|
| CHG-P02/T03 | 新增 | 119, 121, 122 | GD-15 env + 录制前置 |
| CHG-T04 | 新增 | 120 | docker rpa_state volume |
| CHG-P05/T05/T06 | 新增 | 123 | QuotePageAdapter |
| CHG-T09 | 新增 | 124 | storageState 生命周期 |
| CHG-T07 | 新增 | 125127 | selector env 化 |
| CHG-P03/P04/T08 | 新增 | 128, 129 | 错误分类 v0.6 |
| CHG-P08/T02 | 新增 | 130 | probe 3/3 |
| CHG-T03 P1 | 新增 | 131 | Patchright 可选 |
| CHG-T10 | 新增 | 132 | /admin/queues Bull Board |
| CHG-P08/P09 | 新增 | 133135 | TC-601 + Go-No-Go + CI |
| — | 状态 | 001118 | 全部标「已完成」(废止除外) |
| — | 说明 | 022, 023, 028, 073, 110, 117, 088 | 基线已实现;行为变更由 task-12x 承接 |
---
# Phase 0 — 环境与底座
> 执行顺序task-072 → task-073 → **task-119 → task-120** → task-070 → task-071 → task-097 → task-030
## task-072
- **ID**task-072
- **状态**:已完成
- **模块**:数据库
- **目标**:创建 Docker Compose 配置4容器
- **输入**:技术设计 §6.1
- **输出**`docker-compose.yml`,含 mysql/redis/next-app/rpa-worker含 healthcheck 和 shm_size
- **实现范围**:仅基础设施配置,不含应用代码
- **验证**`docker compose up -d` 四容器全部 healthy`docker compose ps` 状态 running
---
## task-073
- **ID**task-073
- **状态**:已完成
- **模块**:数据库
- **目标**:创建 `.env.example` + Dockerfile + Dockerfile.worker
- **输入**:技术设计 §6.2
- **输出**`.env.example` / `Dockerfile` / `Dockerfile.worker`
- **实现范围**:环境变量模板 + 容器构建文件
- **验证**`docker compose build` 无报错;`.env.example` 含全部必填变量
- **v1.2 说明**:基线已实现;行为变更由 task-12x 承接
---
# 基础设施Lib
---
## task-119
- **ID**task-119
- **状态**:待执行
- **模块**Lib/Infra
- **目标**v0.6 RPA 环境变量模板GD-15
- **输入**PRD §8.2.1;技术设计 §6.2 CHG-T03
- **输出**`.env.example` 增 `MOTHERSHIP_QUOTE_URLS`、`RPA_STORAGE_STATE_PATH`、`RPA_SELECTOR_*`8 项)、`RPA_USE_PATCHRIGHT`
- **实现范围**:禁止内置 dashboard / `/quote` 默认 URL`MOTHERSHIP_QUOTE_URLS` 时 rpa-worker fail-fast
- **验证**`.env.example` 含全部 RPA 必填项;未配置 URL 列表时 worker 启动报错退出
---
## task-120
- **ID**task-120
- **状态**:待执行
- **模块**Lib/Infra
- **目标**Docker RPA 持久化storageState volume
- **输入**:技术设计 §6.1 §7.5 CHG-T04
- **输出**`docker-compose.yml` rpa-worker 注入 RPA env + `rpa_state` volume → `/app/.rpa`
- **实现范围**volume 挂载 + env 透传;不含业务逻辑
- **验证**`docker compose up -d` 后 `.rpa/mothership-storage.json` 跨容器重启保留
---
## task-070
- **ID**task-070
- **状态**:已完成
- **模块**:数据库
- **目标**:创建完整 Prisma schema6张表
- **输入**PRD §9 + 技术设计 §3.5
- **输出**`prisma/schema.prisma`,含 SysUser / QuoteRecord / IdempotencyRecord / QuoteCacheMeta / MarkupConfig / AlertLog / **AuditLog**
- **实现范围**:仅 schema 文件,不含 migrate 执行
- **验证**`npx prisma validate` 零错误;所有字段类型、约束与 PRD DDL 一致
---
## task-071
- **ID**task-071
- **状态**:已完成
- **模块**:数据库
- **目标**:执行 Prisma migrate + seed初始化 admin_demo 账号)
- **输入**task-070 的 schema
- **输出**`prisma/migrations/` + `prisma/seed.ts`,创建 admin_demo/Demo@123
- **实现范围**:仅 migrate dev + seed不含业务逻辑
- **验证**`npx prisma migrate dev` 无报错;`SELECT * FROM sys_user` 返回 1 行 admin
---
## task-097
- **ID**task-097
- **状态**:已完成
- **模块**Lib
- **目标**:实现 lib/prisma.ts Prisma 客户端单例
- **输入**:技术设计 §5
- **输出**`lib/prisma.ts`;导出 `prisma` 单例dev 热重载防多实例
- **实现范围**:仅 ORM 连接;不含业务查询
- **验证**`prisma.$connect()` 成功;多模块 import 同一实例
---
## task-030
- **ID**task-030
- **状态**:已完成
- **模块**Cache
- **目标**:实现 Redis 客户端单例lib/redis.ts
- **输入**ioredis ^5.x技术设计 §3.6
- **输出**`lib/redis.ts`;导出 `getRedis()` 单例;连接失败时抛错并 log
- **实现范围**:连接配置 + 错误处理;不含业务操作
- **验证**`getRedis().ping()` 返回 PONGRedis 不可达 → 抛异常并记录 error log
---
# Phase 1 — 基础设施与缓存W1
> 执行顺序task-096 → task-031 → task-032 → task-033 → task-034 → task-035 → task-035-ip → task-036
## task-096
- **ID**task-096
- **状态**:已完成
- **模块**Lib
- **目标**:实现 lib/response.ts 统一 API 响应包络
- **输入**:技术设计 §4.1PRD §8.5
- **输出**`lib/response.ts``ok(data)` / `fail(code, message, httpStatus)`;所有路由复用
- **实现范围**:仅响应格式化;自动附加 `Cache-Control: no-store` 辅助函数
- **验证**Vitestok → `{ code:0, message:'ok', data }`fail → `{ code, message, data:null }` + 正确 HTTP 状态码
---
## task-031
- **ID**task-031
- **状态**:已完成
- **模块**Cache
- **目标**:实现 L1 缓存idem:{request_id}24h
- **输入**task-030PRD §7.2GD-2
- **输出**`modules/cache/redis-cache.ts` 中 `getL1(request_id)` / `setL1(request_id, data)`
- **实现范围**SETNX + GETTTL=24hvalue=完整响应快照 JSON
- **验证**set → get 返回相同值TTL 校验 ≈ 86400s重复 SETNX → 不覆盖
---
## task-032
- **ID**task-032
- **状态**:已完成
- **模块**Cache
- **目标**:实现 L2 缓存quote:{cargo_hash}3min+jitter
- **输入**task-030PRD §7.2GD-2
- **输出**`modules/cache/redis-cache.ts` 中 `getL2(cargo_hash)` / `setL2(cargo_hash, data)`
- **实现范围**SET + GETTTL=180+random(0~30)svalue=四档原始报价 JSON不含加价
- **验证**set → get 返回相同值TTL 在 180~210s 之间(随机 jitter 验证分布)
---
## task-033
- **ID**task-033
- **状态**:已完成
- **模块**Cache
- **目标**:实现 L3 缓存stale:{cargo_hash}30min只读降级
- **输入**task-030PRD §7.2GD-2
- **输出**`modules/cache/redis-cache.ts` 中 `getL3(cargo_hash)` / `setL3(cargo_hash, data)`(仅 RPA 成功时写入)
- **实现范围**SET + GETTTL=1800s**正常路径禁止读取 L3**(只在 RPA 失败 fallback 时读)
- **验证**RPA 成功后 L3 有值L2 命中路径不访问 L3
---
## task-034
- **ID**task-034
- **状态**:已完成
- **模块**Cache
- **目标**实现缓存击穿锁lock:quote:{cargo_hash}
- **输入**task-030PRD §11.6
- **输出**`modules/cache/redis-cache.ts` 中 `acquireLock(cargo_hash)` / `releaseLock(cargo_hash)`
- **实现范围**SETNX lock keyTTL=5s获取失败 → 等待2s后读L2用完后 DEL
- **验证**100并发同一 cargo_hash miss → 只触发1次 RPA其余等待后命中 L2TC-11.6
---
## task-035
- **ID**task-035
- **状态**:已完成
- **模块**Cache
- **目标**:实现限流 Redis Key令牌桶60次/分钟/customer
- **输入**task-030PRD §10.3 §11.7GD-4
- **输出**`modules/cache/rate-limiter.ts``checkRateLimit(customer_id)` → 超限返回 RATE_LIMITED
- **实现范围**ratelimit:customer:{id} INCR + EXPIRE 60s超60 → 429
- **验证**60次 → 全部通过第61次 → 429 RATE_LIMITEDTC-303 TC-503
---
## task-035-ip
- **ID**task-035-ip
- **状态**:已完成
- **模块**Cache
- **目标**:实现 IP 级限流1000次/分钟,超限封禁 10 分钟)
- **输入**PRD §11.9
- **输出**`modules/cache/ip-rate-limiter.ts``ratelimit:ip:{ip}` + `ban:ip:{ip}` TTL=600s
- **实现范围**middleware 调用;>1000/min → 429 + 写 SECURITY 预警task-105
- **验证**:单 IP 1200 次/分钟 → 429封禁 10 分钟内全部拒绝TC-503 IP 维度)
---
# 加价系统Markup
---
## task-036
- **ID**task-036
- **状态**:已完成
- **模块**Cache
- **目标**实现熔断状态管理circuit:rpa Redis key
- **输入**task-030PRD §10.3 §11.5GD-4
- **输出**`modules/cache/circuit-breaker.ts``isCircuitOpen()` / `openCircuit()` / `closeCircuit()`
- **实现范围**Redis key circuit:rpaTTL=600s10min连续失败≥3次 → open期间 Worker 不消费
- **验证**连续3次失败 → circuit open10分钟后自动关闭open期间 job 走 L3/failedTC-209
---
# Phase 2 — 鉴权
> 执行顺序task-001 → task-002 → task-003 → task-004 → task-005 → task-098
## task-001
- **ID**task-001
- **状态**:已完成
- **模块**Auth
- **目标**:实现 JWT 工具函数jose 库:签发/校验/解码)
- **输入**:技术设计 §4.2jose ^5.x
- **输出**`modules/auth/jwt.ts`,导出 `signToken(payload)` / `verifyToken(token)` / `decodeToken(token)`
- **实现范围**JWT 操作只;不含数据库查询
- **验证**Vitest 单元测试:签发 → 校验通过;篡改 → 抛异常;过期 → 抛异常
---
## task-002
- **ID**task-002
- **状态**:已完成
- **模块**Auth
- **目标**:实现 POST /api/auth/login仅 admin 角色)
- **输入**task-001Prisma SysUser
- **输出**`app/api/auth/login/route.ts`;成功返回 `{ token, user: { user_id, role } }`
- **实现范围**用户名密码校验bcrypt compare+ JWT 签发;非 admin 拒绝;不含 RBAC
- **验证**curl POST 正确凭据 → 200 + token错误密码 → 401customer 账号 → 403
---
## task-003
- **ID**task-003
- **状态**:已完成
- **模块**Auth
- **目标**:实现 middleware.tsJWT 鉴权 + 路由保护)
- **输入**task-001Next.js middleware
- **输出**`middleware.ts`;未鉴权路由返回 401admin 路由校验 role=admin
- **实现范围**:路由匹配 + JWT 校验不含限流task-035 实现)
- **验证**:无 token 访问 `/api/quotes` → 401有效 admin JWT 访问 `/api/alerts` → 通过
---
## task-004
- **ID**task-004
- **状态**:已完成
- **模块**Auth
- **目标**:实现宿主 Service Token 验证customer_id 租户绑定校验)
- **输入**PRD §2.1task-003
- **输出**`modules/auth/service-token.ts`;校验 token + customer_id 绑定;越权 403
- **实现范围**Service Token 解析 + customer_id 匹配;不含 JWT 签发(宿主自签)
- **验证**:正确 token + 匹配 customer_id → 通过customer_id 不匹配 → 403
---
## task-005
- **ID**task-005
- **状态**:已完成
- **模块**Auth
- **目标**:实现 RBAC 权限检查函数(含 rpa:operate
- **输入**PRD §10.6 §2.1task-001
- **输出**`modules/auth/rbac.ts`,导出 `requirePermission(token, permission)` 中间件
- **实现范围**:权限枚举:`pricing:markup:write` / `alert:read` / **`rpa:operate`**;无权限抛 FORBIDDEN
- **验证**Vitestadmin token + alert:read → 通过admin + rpa:operate → 通过;宿主 token + alert:read → 403
---
# 查价核心系统Quote Engine
---
## task-098
- **ID**task-098
- **状态**:已完成
- **模块**Lib
- **目标**:实现 gateway 503 单次重试中间件
- **输入**PRD §11.4
- **输出**`middleware.ts` 或 `lib/gateway-retry.ts`5xx 时 retry 1 次后仍失败 → 503 INTERNAL_ERROR
- **实现范围**:仅网关层重试;不含业务降级
- **验证**mock 首次 503 第二次 200 → 客户端得 200连续 503 → 503 + INTERNAL_ERROR
---
# 用户系统Auth
---
# Phase 3 — 加价基础
> 执行顺序task-040 → task-041 → task-044
## task-040
- **ID**task-040
- **状态**:已完成
- **模块**Pricing
- **目标**:实现 roundHalfUp 工具函数
- **输入**PRD GD-10技术设计 §4.5
- **输出**`lib/math.ts``roundHalfUp(value, decimals)` 使用 Number.EPSILON 修正
- **实现范围**:仅数学函数
- **验证**Vitest0.105×2 → 0.21不是0.2032.005 → 32.01;边界值含负数
---
## task-041
- **ID**task-041
- **状态**:已完成
- **模块**Pricing
- **目标**:实现 PricingEngine.applyMarkup()
- **输入**task-040PRD §6.3
- **输出**`modules/pricing/engine.ts``applyMarkup(rawFreight, rawTotal, markupPercent)` → `{ markupAmount, finalTotal }`
- **实现范围**markup_amount = ROUND_HALF_UP(raw_freight × markup_percent / 100, 2)final_total = ROUND_HALF_UP(raw_total + markup_amount, 2)
- **验证**Vitestraw_freight=320surcharges=15markup=10% → markup_amount=32.00final_total=367.00TC-103raw_freight=380markup=10% → 38.00/418.00
---
## task-044
- **ID**task-044
- **状态**:已完成
- **模块**Pricing
- **目标**:实现未配置客户默认 0% 逻辑MarkupConfig 查询)
- **输入**Prisma MarkupConfigPRD BR-6.3
- **输出**`modules/pricing/engine.ts` 中 `getMarkupPercent(customer_id)` 函数;未配置返回 0.0
- **实现范围**DB 查询 + 默认值兜底;不含写操作
- **验证**Vitest未配置 customer_id → 返回 0.0;已配置 10.0% → 返回 10.0
---
# 预警系统Alert
---
# Phase 3 — 查价领域逻辑
> 执行顺序task-010 → task-011 → task-012 → task-095 → task-111 → task-013 → task-019 → task-092 → task-109 → task-014
## task-010
- **ID**task-010
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 ValidationModule输入校验 + Mothership 官方硬限)
- **输入**PRD §4.2.8zod技术设计 §7.2.2
- **输出**`modules/quote/validation.ts`;导出 `MOTHERSHIP_LIMITS` 常量 + `validateQuoteInput(body)` 函数
- **实现范围**selected_from_suggestions=true 校验pallet_count 125dims L≤999/W≤99/H≤99 in单托重≤9999 lb总重 ≤249975 lbcargo_type 9项枚举request_id UUID v4zip 正则SQL注入检测
- **验证**VitestTC-201~TC-204 + TC-E4.1~E4.7 全部场景;边界值测试
---
## task-011
- **ID**task-011
- **状态**:已完成
- **模块**Quote Engine
- **目标**实现单位换算函数kg→lbcm→in
- **输入**PRD §4.2.2 §4.2.3GD-13
- **输出**`modules/quote/unit-converter.ts``kgToLb(kg)` / `cmToIn(cm)`ROUND_HALF_UP 2位
- **实现范围**:仅数学换算;不含校验逻辑
- **验证**Vitest227kg → 500.05lb±0.01122cm → 48.03in;精度 ROUND_HALF_UP
---
## task-012
- **ID**task-012
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 cargo_hash 算法MD5
- **输入**PRD BR-4.4;技术设计 §3.7
- **输出**`modules/quote/cargo-hash.ts``buildCargoHash(input)` 返回 32位 hex
- **实现范围**:含 pickup(place_id) + delivery + weight_lb + dims_in + pallet_count + cargo_type不含 service_level / customer_id
- **验证**Vitest相同入参 → 相同 hashservice_level 不同 → 相同 hashplace_id 不同 → 不同 hash
---
## task-095
- **ID**task-095
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 confidence_score 赋值逻辑F5.6
- **输入**PRD §5.3 F5.6
- **输出**`modules/quote/confidence.ts``getConfidenceScore(sourceType)` → rpa/cache=0.95stale=0.70
- **实现范围**:仅映射函数;在 GET /quotes 与落库时调用
- **验证**Vitestsource=rpa → 0.95source=stale → 0.70source=cache → 0.95
---
## task-111
- **ID**task-111
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 BR-5.5 四档齐全校验done 前 gates
- **输入**PRD BR-5.5GD-1
- **输出**`modules/quote/quote-completeness.ts``assertFourTiers(quotes[])` → 不足 4 档抛 RPA_DATA_INVALID
- **实现范围**:校验 standard/guaranteed × lowest/fastest 组合齐全orchestrator 与 RPA worker 共用
- **验证**3 档 → 抛错走 Fallback4 档 → 通过TC-102
---
# RPA 系统
---
## task-013
- **ID**task-013
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 IdempotencyModuleRedis L1 + DB 双保险)
- **输入**task-031L1 RedisPrisma IdempotencyRecordPRD §7.3 §10.4
- **输出**`modules/quote/idempotency.ts``checkIdempotency(request_id)` + `saveIdempotency(request_id, quote_id)`
- **实现范围**Redis SETNX L1 → 命中返回 quote_idDB 唯一键冲突处理24h TTL
- **验证**Vitest重复 request_id → 返回同一 quote_id并发 10次 → 仅写入 1条 DB 记录TC-207
---
## task-019
- **ID**task-019
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 quote_id 生成函数
- **输入**PRD §5.2 示例格式QTE_20260616_0001
- **输出**`modules/quote/quote-id.ts``generateQuoteId()` 含日期+序号;保证唯一性
- **实现范围**:仅 ID 生成;使用 DB 自增或 UUID+日期前缀
- **验证**:并发 100次调用 → 无重复TC-402DB 唯一键冲突 → INTERNAL_ERROR + 写 audittask-109
---
## task-092
- **ID**task-092
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 FallbackOrchestratorRPA 失败 → L3 降级完整编排)
- **输入**task-033L3task-041加价task-050~053预警PRD §7.6 §8.4 §2.5
- **输出**`modules/quote/fallback-orchestrator.ts``handleRpaFailure(quoteId, cargoHash, customerId, error)`
- **实现范围**:读 L3 → 有:按客户加价重算 → UPDATE done(source=stale,is_realtime=false) → STALE_FALLBACK 预警failed + QUOTE_UNAVAILABLE → RPA_FAILED 预警;**不抛异常阻断主流程**
- **验证**TC-205stale doneTC-206failedTC-602集成测试可单点 mock RPA 失败
---
## task-109
- **ID**task-109
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 quote_id DB 唯一冲突 → INTERNAL_ERROR 处理
- **输入**PRD §11.10
- **输出**orchestrator 落库 catch P2002 → 写 audit + 返回 500 INTERNAL_ERROR
- **实现范围**:仅 quote_id 冲突;不含其他 DB 错误
- **验证**mock 唯一键冲突 → 500 + audit_log 有记录;不写入脏数据
---
# 缓存系统
---
## task-014
- **ID**task-014
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 QuoteOrchestrator 主流程L1→L2→入队
- **输入**task-010~013task-032L2BullMQPrisma QuoteRecord技术设计 §2.3
- **输出**`modules/quote/orchestrator.ts``submitQuote(body)` 完整主流程
- **实现范围**:换算 → 校验 → L1 → L2命中则加价+落库+写L1+返回done→ 未命中则 INSERT processing + 入队 → 返回 processing**RPA 失败时委托 task-092 FallbackOrchestrator**
- **验证**集成测试L1 命中 → 不触发 RPAL2 命中 → source=cache + done首次 → status=processingTC-104 TC-105失败路径调用 092
---
# Phase 4 — API 层里程碑L1/L2 可通)
> 执行顺序task-015 → task-016 → task-017 → task-042 → task-043 → task-018
## task-015
- **ID**task-015
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 POST /api/quotes 路由(薄层)
- **输入**task-003鉴权task-014orchestrator技术设计 §4.3
- **输出**`app/api/quotes/route.ts`;调用 task-096 统一响应Cache-Control: no-store
- **实现范围**:路由层:鉴权 → 调 orchestrator → 格式化响应;不含业务逻辑
- **验证**curl POST 正常参数 → 200 + quote_id缺字段 → 400无 token → 401
---
## task-016
- **ID**task-016
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 GET /api/quotes/{quoteId} 路由(轮询 + expired 检测)
- **输入**task-003Prisma QuoteRecordPRD §5.2 §5.3
- **输出**`app/api/quotes/[quoteId]/route.ts`valid_until < now status=expired越权 403
- **实现范围**DB 查询 + expired 计算 + customer_id 越权校验 + **task-095 confidence_score 赋值**;不含轮询逻辑(客户端实现)
- **验证**status=done 完整 QuoteResponse 4 + confidence_scorerpa/cache=0.95stale=0.70expired status=expired他人 quote_id 403TC-501
---
## task-017
- **ID**task-017
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现 GET /api/quotes/history 路由(强制分页)
- **输入**task-003Prisma QuoteRecordPRD §8.5
- **输出**`app/api/quotes/history/route.ts`;缺 page/size 400;返回 `{ list, total, page, size }`
- **实现范围**:分页查询;按 customer_id 过滤;不含跨租户
- **验证**:不传 page 400TC-506);传 page=1&size=20 200 + list
---
## task-042
- **ID**task-042
- **状态**:已完成
- **模块**Pricing
- **目标**:实现 GET /api/markup-configs 路由(分页列表)
- **输入**task-003Prisma MarkupConfig;技术设计 §4.3
- **输出**`app/api/markup-configs/route.ts`;分页返回 MarkupConfig 列表
- **实现范围**:鉴权(宿主 token+ 分页查询;不含写操作
- **验证**:有效 token 200 + list;无 token 401
---
## task-043
- **ID**task-043
- **状态**:已完成
- **模块**Pricing
- **目标**:实现 PUT /api/markup-configs/{customerId} 路由
- **输入**task-005RBAC pricing:markup:writePrisma MarkupConfigPRD §6.4 §6.5
- **输出**`app/api/markup-configs/[customerId]/route.ts`UPSERT 操作;0~30.0 范围校验
- **实现范围**:权限校验 + 范围校验 + UPSERT + 审计字段(operator_id
- **验证**markup=30.0 200markup=30.1 400TC-505);无权限 403TC-502);客户不存在 400
---
## task-018
- **ID**task-018
- **状态**:已完成
- **模块**Quote Engine
- **目标**:实现超时扫描定时任务(processing >30s → failed
- **输入**Prisma QuoteRecord技术设计 §2.2PRD §11.4
- **输出**`workers/scheduler/timeout-sweeper.ts`;每 10s 扫描 processing > 30s 的记录 → UPDATE status=failed + error_code=QUOTE_TIMEOUT
- **实现范围**:每 10s 扫描 processing > 30s → 先尝试 **task-092 L3 降级**;无 L3 则 UPDATE failed + QUOTE_TIMEOUT + 写预警
- **验证**:有 L3 时 31s → done stale无 L3 → failed QUOTE_TIMEOUTTC-208 TC-605
---
# Phase 5.0 — RPA 录制前置W2 前置CHG-T11/T12
> 执行顺序task-121 → task-122
> **必须在 task-123 之前完成**:无 env 则 adapter/probe 无法验收。
## task-121
- **ID**task-121
- **状态**:已完成
- **模块**RPA
- **目标**Playwright codegen 录制入口脚本
- **输入**PRD §8.2.3 GD-15技术设计 §9.2
- **输出**`scripts/record-mothership.sh`headed`RPA_HEADLESS=false`
- **实现范围**:启动 codegen禁止 dashboard.mothership.com / www.mothership.com/quote
- **验证**:脚本可执行;录制产出 goto URL 与 selector 可提取
---
## task-122
- **ID**task-122
- **状态**:已完成
- **模块**RPA
- **目标**:录制 SOP 与 env 产出 checklist
- **输入**task-121PRD §8.2.3 LA→Dallas 标准样例
- **输出**`docs/rpa-recording-sop.md`URL→`MOTHERSHIP_QUOTE_URLS`、selector→`RPA_SELECTOR_*` 映射表
- **实现范围**:文档化人工录制流程;不含自动化提取工具
- **验证**:人工 checklistenv 填齐 8 个 selector 后可跑 probe
---
# Phase 5 — RPA 基线W2已完成
> 执行顺序task-020 → … → task-100**全部已完成**v1.2 增量见下方 Phase 5 v1.2 重构)
## task-020
- **ID**task-020
- **状态**:已完成
- **模块**RPA
- **目标**:实现 QuoteProvider 接口定义
- **输入**:技术设计 §7.1PRD 附录 A
- **输出**`modules/providers/quote-provider.ts`TypeScript interface QuoteProvider + QuoteItem + QuoteRequest
- **实现范围**仅类型定义items.length === 4 约束注释
- **验证**TypeScript 编译无报错MothershipRPAProvider 实现该接口不报错
---
## task-021
- **ID**task-021
- **状态**:已完成
- **模块**RPA
- **目标**:实现 BullMQ 队列配置quote-rpa 队列)
- **输入**:技术设计 §7.4BullMQ ^5.x
- **输出**`workers/rpa/index.ts` 消费入口;队列名=quote-rpa并发=2单job超时=25s重试=1次
- **实现范围**Worker 创建 + 连接 Redis不含 RPA 业务逻辑
- **验证**Worker 启动无报错;向队列推入 job → Worker 消费到
---
## task-022
- **ID**task-022
- **状态**:已完成
- **模块**RPA
- **目标**:实现 session-manager.tsMothership 登录态维护)
- **输入**:技术设计 §7.2Playwright
- **输出**`workers/rpa/session-manager.ts``getSession()` 返回已登录 browser contextSESSION_EXPIRED 时重登1次
- **实现范围**:浏览器常驻 context + 登录状态检测 + 自动重登;不含报价抓取
- **验证**:冷启动 → 自动登录session 过期 → 重登成功;重登失败 → 抛 SESSION_EXPIRED
- **v1.2 说明**:基线已实现;行为变更由 task-12x 承接
---
## task-023
- **ID**task-023
- **状态**:已完成
- **模块**RPA
- **目标**:实现 preCheck()(页面健康检查)
- **输入**:技术设计 §7.2Playwright
- **输出**`workers/rpa/mothership.ts` 中 `preCheck()` 方法;检测 URL 非 login/captcha关键表单 selector 存在
- **实现范围**:仅检测,不填表单;失败抛对应错误分类
- **验证**:正常页面 → true被重定向到 /login → SESSION_EXPIRED验证码页 → RPA_CAPTCHAselector 消失 → STRUCT_CHANGE
- **v1.2 说明**:基线已实现;行为变更由 task-12x 承接
---
## task-024
- **ID**task-024
- **状态**:已完成
- **模块**RPA
- **目标**:实现地址联想点选逻辑(方案 Aplace_id方案 B联想下拉
- **输入**PRD §4.2.1;技术设计 §7.2.1GD-9
- **输出**`workers/rpa/mothership.ts` 中 `fillAddress()` 方法;方案 A 优先;方案 B 备用
- **实现范围**:输入街道 → waitForSelector 联想 → click 匹配项 → 断言锁定(联想消失);锁定失败 → ADDRESS_SUGGESTION_NOT_FOUND
- **验证**:正常地址 → 表单锁定;联想不出现 → 抛 ADDRESS_SUGGESTION_NOT_FOUND超5s → timeout
---
## task-025
- **ID**task-025
- **状态**:已完成
- **模块**RPA
- **目标**实现表单填写weight/dims/pallet_count/cargo_type
- **输入**PRD §4.2.2~4.2.4Playwright数据为 lb/in已换算
- **输出**`workers/rpa/mothership.ts` 中 `fillCargo()` 方法
- **实现范围**:填 pallet_count映射 Mothership Pallet quantity+ weight_lb + dims_in + cargo_type不含地址
- **验证**录制回放验证字段填入正确pallet_count=2 → Mothership quantity=2 Pallet
---
## task-026
- **ID**task-026
- **状态**:已完成
- **模块**RPA
- **目标**实现四档报价抓取standard/guaranteed × lowest/fastest
- **输入**:技术设计 §7.2 步骤4~7Playwright
- **输出**`workers/rpa/mothership.ts` 中 `scrapeQuotes()` 方法;返回 QuoteItem[4]
- **实现范围**:提交一次 → 在结果页分别点 standard/guaranteed → 各切换 lowest/fastest → 抓 rawFreight + transitDays严禁多次提交
- **验证**:实测返回 items.length===4每档 rawFreight>0transitDays 非空
---
## task-027
- **ID**task-027
- **状态**:已完成
- **模块**RPA
- **目标**:实现 RPA 数据一致性校验
- **输入**PRD §8.2;技术设计 §7.2
- **输出**`workers/rpa/mothership.ts` 中 `validateResult()` 方法
- **实现范围**4档均存在校验每档 rawFreight>0transitDays 非空;失败 → 抛 RPA_DATA_INVALID
- **验证**Vitest3档数据 → RPA_DATA_INVALIDprice=0 → RPA_DATA_INVALIDprice=-1 → RPA_DATA_INVALID
---
## task-028
- **ID**task-028
- **状态**:已完成
- **模块**RPA
- **目标**:实现 RPA 错误分类处理与熔断机制
- **输入**:技术设计 §7.3PRD §11.5task-036熔断 Redis key
- **输出**`workers/rpa/mothership.ts` 错误处理逻辑连续失败≥3次 → 写 circuit:rpa=open 10min
- **实现范围**错误分类CAPTCHA→暂停WorkerSTRUCT_CHANGE→不重试SESSION_EXPIRED→重登1次+ 熔断计数
- **验证**连续3次失败 → Redis circuit:rpa=open熔断期间 Worker 不消费新 jobTC-209
- **v1.2 说明**:基线已实现;行为变更由 task-12x 承接
---
## task-110
- **ID**task-110
- **状态**:已完成
- **模块**RPA
- **目标**:实现 RPA 业务错误码映射CARRIER_NO_CAPACITY / ADDRESS_NOT_SUPPORTED
- **输入**PRD §5.6
- **输出**`modules/rpa/error-mapper.ts`Mothership 页面文案 → 对应 error_code
- **实现范围**RPA 抓取阶段识别无运力/邮编不支持;映射后走 092 或 failed
- **验证**mock 无运力页 → error_code=CARRIER_NO_CAPACITY不支持邮编 → ADDRESS_NOT_SUPPORTED
- **v1.2 说明**:基线已实现;行为变更由 task-12x 承接
---
## task-029
- **ID**task-029
- **状态**:已完成
- **模块**RPA
- **目标**:实现 RPA 成功后写缓存 + 落库 + 偏差检测编排
- **输入**task-026task-032L2task-033L3task-031L1Prisma QuoteRecordtask-051偏差检测
- **输出**`workers/rpa/index.ts` 中 job 完成处理逻辑
- **实现范围**RPA成功 → 写L2(3min+jitter)+L3(30min) → UPDATE QuoteRecord(done) → 更新 quote_cache_meta → 偏差检测 → 写L1**RPA失败 → 调用 task-092**
- **验证**集成测试RPA 成功后 Redis L2/L3 有值DB source_type=rpa偏差≥5%时 alert_log 有 PRICE_DEVIATION失败时 092 被调用
---
## task-093
- **ID**task-093
- **状态**:已完成
- **模块**RPA
- **目标**:实现 GET /api/rpa/statusWorker/队列/熔断状态)
- **输入**PRD §3.1 管理端 RPA 进度;技术设计 §4.2 admin rpa:operate
- **输出**`app/api/rpa/status/route.ts`;返回 `{ workers[], queueDepth, circuitOpen, successRate24h }`
- **实现范围**:读 Redis circuit + BullMQ 队列 + Worker 心跳admin + rpa:operate 权限
- **验证**admin JWT → 200 + 字段非空;宿主 token → 403熔断时 circuitOpen=true
---
## task-099
- **ID**task-099
- **状态**:已完成
- **模块**RPA
- **目标**:实现 POST /api/rpa/worker/pause管理员手动暂停 Worker
- **输入**PRD §2.4「暂停 RPA Worker」task-005 rpa:operate
- **输出**`app/api/rpa/worker/pause/route.ts`body `{ worker_id, duration_minutes }`;写 Redis worker:pause:{id}
- **实现范围**admin 手动暂停;不含自动 CAPTCHA 暂停task-054
- **验证**admin 调用 → Worker 指定时间内不接 job非 admin → 403
---
## task-100
- **ID**task-100
- **状态**:已完成
- **模块**RPA
- **目标**:实现 POST /api/quotes/manual-fallback人工兜底录入
- **输入**PRD §2.4「触发人工兜底录入」
- **输出**`app/api/quotes/manual-fallback/route.ts`admin 录入四档原始价 → 写 L3 + UPDATE quote done(stale)
- **实现范围**:仅 admin校验四档 + 金额>0写 audit_log + alert_log(MANUAL_FALLBACK)
- **验证**admin 提交合法四档 → quote status=done source=stale非 admin → 403
---
# Phase 5 — RPA v1.2 重构PRD v0.6
> 执行顺序task-123 → task-124 → task-125 → task-126 → task-127 → task-128 → task-129 → task-130 → task-131
> **里程碑 M2v1.2**`RPA_MOCK_MODE=false` 下 `scripts/probe-rpa.ts` 连续 3 次 exit 0四档 `source_type=rpa`。
## task-123
- **ID**task-123
- **状态**:待执行
- **模块**RPA
- **目标**:实现 QuotePageAdapter 多 URL 探测
- **输入**:技术设计 §7.2.3 CHG-T05/T06task-122
- **输出**`workers/rpa/quote-page-adapter.ts``resolveQuoteEntry` / `preCheck` / `isLoginWithoutCredentials`
- **实现范围**:按 `MOTHERSHIP_QUOTE_URLS` 顺序 goto + preCheck全失败 → QUOTE_ENTRY_UNAVAILABLE
- **验证**:单测 mock 多 URL首个可用 URL 写入 activeUrl全失败抛 QUOTE_ENTRY_UNAVAILABLE
---
## task-124
- **ID**task-124
- **状态**:待执行
- **模块**RPA
- **目标**storageState 生命周期§7.5
- **输入**:技术设计 §7.5 CHG-T09task-120
- **输出**:重构 `workers/rpa/session-manager.ts``createContext` load、`persistContext` writeback、`invalidateStorageState`
- **实现范围**成功查价写回login 无凭据先 invalidate 再重试 goto
- **验证**:单测:存在 state 文件时 load成功后 persistinvalidate 删除文件
---
## task-125
- **ID**task-125
- **状态**:待执行
- **模块**RPA
- **目标**:地址联想 selector env 化
- **输入**:技术设计 §7.2.1 CHG-T07task-123
- **输出**`workers/rpa/mothership.ts` `fillAddress` 改用 `RPA_SELECTOR_PICKUP/DELIVERY/ADDRESS_SUGGESTION`
- **实现范围**:失败 → ADDRESS_SUGGESTION_NOT_FOUND不重试
- **验证**mock 页面:联想成功锁定;无下拉 → ADDRESS_SUGGESTION_NOT_FOUND
---
## task-126
- **ID**task-126
- **状态**:待执行
- **模块**RPA
- **目标**:表单填写与提交 selector env 化
- **输入**:技术设计 §7.2 CHG-T07task-125
- **输出**`fillCargo` + submit 改用 `RPA_SELECTOR_SUBMIT` 等 env
- **实现范围**:移除硬编码 data-testid全部读 `process.env.RPA_SELECTOR_*`
- **验证**录制回放字段填入正确submit 点击成功
---
## task-127
- **ID**task-127
- **状态**:待执行
- **模块**RPA
- **目标**:四档抓取 selector env 化
- **输入**:技术设计 §7.2 步骤 7 CHG-T07task-126
- **输出**`scrapeQuotes` 改用 `RPA_SELECTOR_STANDARD/GUARANTEED/LOWEST/FASTEST/PRICE`
- **实现范围**standard/guaranteed × lowest/fastest 各抓取一次items.length===4
- **验证**mock 结果页返回 4 档;每档 rawFreight>0
---
## task-128
- **ID**task-128
- **状态**:待执行
- **模块**RPA
- **目标**:错误分类 v0.6(入口 vs 抓取)
- **输入**PRD §5.6 §11.5 CHG-P03/P04技术设计 §7.3 CHG-T08
- **输出**`workers/rpa/error-mapper.ts` + job-handlerQUOTE_ENTRY_UNAVAILABLElogin 无凭据 → STRUCT_CHANGE
- **实现范围**:入口/地址错误不重试SESSION_EXPIRED 仅已配置凭据且曾成功登录
- **验证**单测各错误分支映射QUOTE_ENTRY_UNAVAILABLE 不触发 job 重试
---
## task-129
- **ID**task-129
- **状态**:待执行
- **模块**Quote Engine
- **目标**Fallback 入口错误处理
- **输入**PRD §2.5 CHG-P03task-128
- **输出**:增补 `modules/quote/fallback-orchestrator.ts`:入口类错误不消耗 RPA job 重试配额
- **实现范围**QUOTE_ENTRY_UNAVAILABLE / ADDRESS_SUGGESTION_NOT_FOUND 直接走 L3 或 400
- **验证**:单测:入口错误 job attempts=1PAGE_LOAD_TIMEOUT 仍可重试 1 次
---
## task-130
- **ID**task-130
- **状态**:待执行
- **模块**RPA
- **目标**:升级 probe 探针(连续 3 次 exit 0
- **输入**PRD TC-601 §12.7 CHG-P08/P09技术设计 CHG-T02
- **输出**:升级 `scripts/probe-rpa.ts` + `scripts/probe-rpa-3x.sh`;断言 items.length===4
- **实现范围**`RPA_MOCK_MODE=false` 真实探测3x 脚本循环调用
- **验证**`bash scripts/probe-rpa-3x.sh` 连续 3 次 exit 0输出 4 档 JSON
---
## task-131
- **ID**task-131
- **状态**:待执行
- **模块**RPA
- **目标**Patchright 可选驱动P1
- **输入**:技术设计 §6.2 `RPA_USE_PATCHRIGHT` CHG-T03
- **输出**`workers/rpa/session-manager.ts` 支持 `RPA_USE_PATCHRIGHT=true` 切换浏览器
- **实现范围**:默认 PlaywrightPatchright 为可选降级路径
- **验证**`RPA_USE_PATCHRIGHT=true` 时 worker 启动无报错false 时行为不变
---
# Phase 6 — 预警 / 审计 / 管理 API
> 执行顺序task-050 → task-051 → task-052 → task-053 → task-054 → task-055 → task-094 → task-105 → task-056 → task-057
## task-050
- **ID**task-050
- **状态**:已完成
- **模块**Alert
- **目标**:实现 AlertService.writeAlert() 通用写入函数
- **输入**Prisma AlertLogPRD §7.7
- **输出**`modules/alert/service.ts``writeAlert(type, quoteId?, cargoHash?, detail?)` 异步写 alert_log
- **实现范围**INSERT alert_log失败时仅 log error不影响主流程try-catch
- **验证**Vitest调用后 DB alert_log 新增1条DB 写失败 → 不抛出异常,主流程继续
---
## task-051
- **ID**task-051
- **状态**:已完成
- **模块**Alert
- **目标**:实现偏差检测逻辑(与 quote_cache_meta 比对)
- **输入**task-050Prisma QuoteCacheMetaPRD §7.5
- **输出**`modules/alert/deviation-detector.ts``detectDeviation(cargoHash, newRawTotals)` → 偏差≥5%时写 PRICE_DEVIATION
- **实现范围**abs(new-prev)/prev ≥0.05 触发;首次无基准不触发;触发后更新 quote_cache_meta
- **验证**TC-210prev=352new=3705.1%)→ PRICE_DEVIATIONTC-211偏差4.9%→不触发TC-212首次→不触发
---
## task-052
- **ID**task-052
- **状态**:已完成
- **模块**Alert
- **目标**:实现 STALE_FALLBACK 预警L3 降级时写入)
- **输入**task-050PRD §7.7
- **输出**:在 Fallback 流程中调用 `writeAlert('STALE_FALLBACK', quoteId, cargoHash)`
- **实现范围**:仅在 L3 命中路径写入不含通知机制站内仅DB
- **验证**L3 命中路径 → alert_log 新增 STALE_FALLBACKTC-205
---
## task-053
- **ID**task-053
- **状态**:已完成
- **模块**Alert
- **目标**:实现 RPA_FAILED 预警RPA失败无L3时写入
- **输入**task-050PRD §7.7
- **输出**:在 Fallback 无L3路径中调用 `writeAlert('RPA_FAILED', quoteId, cargoHash)`
- **实现范围**:仅在 L3 miss 路径写入
- **验证**L3 miss + RPA失败 → alert_log 新增 RPA_FAILEDTC-206
---
## task-054
- **ID**task-054
- **状态**:已完成
- **模块**Alert
- **目标**:实现 RPA_CAPTCHA 预警 + Worker 暂停
- **输入**task-050task-036熔断PRD §11.5
- **输出**RPA_CAPTCHA 错误处理:写 alert_log + 暂停当前 Worker 10min
- **实现范围**:写预警 + Redis 标记 Worker 暂停状态;不含多 Worker 调度
- **验证**RPA 触发验证码 → alert_log RPA_CAPTCHA + Worker 10分钟内不接新 jobTC-603
---
## task-055
- **ID**task-055
- **状态**:已完成
- **模块**Alert
- **目标**:实现 STRUCT_CHANGE 预警写入
- **输入**task-050PRD §11.5
- **输出**STRUCT_CHANGE 错误处理:写 alert_logpreCheck 失败触发
- **实现范围**:仅写预警;不含 RPA 重试(不重试)
- **验证**preCheck 失败 → alert_log STRUCT_CHANGETC-604
---
## task-094
- **ID**task-094
- **状态**:已完成
- **模块**Alert / DB
- **目标**:实现 audit_log 表 + AuditService 写入
- **输入**PRD §10.6 §11.9task-070 schema 含 AuditLog
- **输出**`modules/audit/service.ts``writeAudit(action, actorId, resource, detail)` → audit_log 表
- **实现范围**:越权/注入/敏感操作写入;失败 log 不阻断主流程
- **验证**TC-501 越权后 audit_log 有记录TC-504 注入尝试有 SECURITY audit
---
## task-105
- **ID**task-105
- **状态**:已完成
- **模块**Alert
- **目标**:实现 SESSION_EXPIRED / SECURITY 预警类型写入
- **输入**PRD §11.5 §11.9;附录 C alert_type
- **输出**:在 session 过期路径写 SESSION_EXPIREDIP 封禁/注入写 SECURITY alert
- **实现范围**:扩展 task-050 writeAlert 支持新 type不含通知推送
- **验证**SESSION_EXPIRED 触发 → alert_log 有记录IP 超限 → SECURITY alert
---
# 观测与指标Metrics
---
## task-056
- **ID**task-056
- **状态**:已完成
- **模块**Alert
- **目标**:实现 GET /api/alerts 路由分页筛选admin 权限)
- **输入**task-005alert:readPrisma AlertLogPRD §8.5
- **输出**`app/api/alerts/route.ts`;支持 type/status 筛选强制分页admin 权限
- **实现范围**:鉴权 + 分页 + 筛选;不含处理操作
- **验证**admin JWT + type=RPA_FAILED → 仅返回该类型;宿主 token → 403
---
## task-057
- **ID**task-057
- **状态**:已完成
- **模块**Alert
- **目标**:实现 POST /api/alerts/{id}/resolve 路由
- **输入**task-003Prisma AlertLogPRD §8.5
- **输出**`app/api/alerts/[id]/resolve/route.ts`UPDATE status=resolved + resolver_id + resolved_at
- **实现范围**鉴权admin+ DB 更新;不含通知
- **验证**admin 调用 → 200 + status=resolved非 admin → 403不存在 id → 404
---
# Phase 7 — 观测指标
> 执行顺序task-101 → task-102
## task-101
- **ID**task-101
- **状态**:已完成
- **模块**Metrics
- **目标**:实现 MetricsCollectorGD-4 三率 + 缓存命中率)
- **输入**PRD §10.2 GD-4 §12.7
- **输出**`modules/metrics/collector.ts`Redis 计数器:`api_success_rate` / `rpa_success_rate` / `realtime_rate` / `cache_hit_rate`
- **实现范围**POST/GET quotes 与 RPA 回调处埋点;不含可视化
- **验证**100 次 mock 请求后 GET 内部指标 API 可算出三率;公式与 PRD 一致
---
## task-102
- **ID**task-102
- **状态**:已完成
- **模块**Metrics
- **目标**:实现 GET /api/metrics/dashboardadmin 汇总指标)
- **输入**task-101PRD §12.7 Go-No-Go
- **输出**`app/api/metrics/dashboard/route.ts`返回三率、P95、队列深度、未处理预警数
- **实现范围**admin 只读;供 /admin/dashboard 消费
- **验证**admin → 200 + 含 GD-4 四指标;非 admin → 403
---
# 前端 UI 系统
---
# Phase 8 — 前端基础与嵌入组件
> 执行顺序task-060 → task-061 → task-062 → task-065 → task-066 → task-067 → task-068 → task-069 → task-106
## task-060
- **ID**task-060
- **状态**:已完成
- **模块**Frontend
- **目标**实现项目基础配置Tailwind + CSS 变量 + 字体)
- **输入**UI设计 §3.1~3.5 §4.4 §4.5
- **输出**`app/globals.css`CSS 变量);`tailwind.config.ts`primary=teal-600Geist 字体引入
- **实现范围**:仅样式基础配置;不含组件
- **验证**`--color-primary: #0D9488` 生效Geist Sans 字体加载
---
## task-061
- **ID**task-061
- **状态**:已完成
- **模块**Frontend
- **目标**:实现基础 UI 组件库7个通用组件
- **输入**UI设计 §3.6 §4.1
- **输出**`components/ui/` 下PrimaryButton / InputField / SelectField / LoadingSpinner / Skeleton / ErrorBanner / WarningBanner
- **实现范围**:各组件含 loading/disabled/error 状态phosphor-iconsUI-01~UI-11 规则
- **验证**Storybook/手动验证:每个组件 loading 状态 + error 状态正常渲染
---
## task-062
- **ID**task-062
- **状态**:已完成
- **模块**Frontend
- **目标**实现布局组件AppLayout + AdminLayout
- **输入**UI设计 §1.4 §4.6
- **输出**`components/layout/app-layout.tsx` + `components/layout/admin-layout.tsx`
- **实现范围**:顶栏导航 + 响应式侧栏;未登录 → 重定向 /login
- **验证**:客户路由使用 AppLayout 正确渲染;管理端路由使用 AdminLayout移动端单列布局
---
## task-065
- **ID**task-065
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 QuoteForm 组件(查价表单)
- **输入**UI设计 §2.4 表单字段布局PRD §4.2react-hook-form + zod
- **输出**`components/quote/quote-form.tsx`;含地址、单托重量/尺寸、托盘数、货物类型;**display_unit 公制/英制切换PRD §4.2.7,仅 UI**
- **实现范围**:表单字段 + onBlur 校验 + display_unit 切换;提交仍按 weight.unit/dimensions.unit
- **验证**zip=9001 → 「邮编格式无效」pallet_count=11 → 超范围kg/cm 切换 UI 正确selected_from_suggestions=false → 「请从地址列表中选择」
---
## task-066
- **ID**task-066
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 useQuotePolling hook2s 轮询 + 网络退避§11.3
- **输入**UI设计 §2.4PRD GD-5 §11.3
- **输出**`hooks/use-quote-polling.ts`;每 2s GET最多 15 次;**响应丢失时指数退避重试 GET**
- **实现范围**:轮询 + 退避逻辑;不含 UI 渲染
- **验证**mock 前 3 次网络失败第 4 次成功 → 最终得 done15 次仍 processing → QUOTE_TIMEOUT
---
## task-067
- **ID**task-067
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 QuoteCard 组件(四档报价展示)
- **输入**UI设计 §3.6 CardPRD §5.1 §5.4
- **输出**`components/quote/quote-card.tsx`Tabstandard/guaranteed子Tablowest/fastest价格 font-monois_realtime=false → WarningBanner角标
- **实现范围**Tab 切换 + 价格明细 breakdown 展示 + 非实时角标;不含倒计时
- **验证**4档数据渲染正确is_realtime=false → WarningBanner 显示UI-06金额 font-mono $1,234.56 格式
---
## task-068
- **ID**task-068
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 CountdownTimer 组件3分钟倒计时
- **输入**UI设计 §2.4PRD §7.4
- **输出**`components/quote/countdown-timer.tsx`<30s 时文字变 Warning 色;归零 ConfirmDialog
- **实现范围**:倒计时逻辑 + 颜色变化 + 过期确认弹窗
- **验证**valid_until 传入 正确倒计时;<30s warning 色;归零 ConfirmDialog 弹出(UI-05
---
## task-069
- **ID**task-069
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 QuoteResultPanel7种状态容器)
- **输入**UI设计 §2.4 页面状态机;task-067 task-068
- **输出**`components/quote/quote-result-panel.tsx`;根据 QuotePageStatus 渲染对应 UI
- **实现范围**idle→插画;processingSkeleton+进度条;success/fallbackQuoteCard+CountdownTimererrorErrorBannerexpiredConfirmDialog
- **验证**7种状态逐一切换,UI 对应正确
---
## task-106
- **ID**task-106
- **状态**:已完成
- **模块**Frontend
- **目标**:实现宿主内嵌查价组件 EmbeddedQuoteWidgetGD-11
- **输入**task-065~069task-015/016PRD §2.2 §3.1;技术设计 §8.1
- **输出**`components/embed/embedded-quote-widget.tsx` + `packages/embed/` `public/embed.js`props`serviceToken, customerId, apiBaseUrl`
- **实现范围**QuoteForm + QuoteResultPanel + 轮询 + 防重复提交;**无独立 /quote 路由**;供宿主 iframe/script 嵌入
- **验证**demo 宿主页嵌入 完整查价流程;TC-101 UIPOST 带宿主 token + customer_id
---
# Phase 8 — 管理端页面
> 执行顺序task-063 → task-064 → task-079 → task-103 → task-104 → task-080
## task-063
- **ID**task-063
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 P01 登录页 /login
- **输入**UI设计 §2.2task-002login API
- **输出**`app/login/page.tsx`;状态机:idle/loading/error/success;调 POST /api/auth/login
- **实现范围**:表单 + 状态机 + 跳转 /dashboard;不含注册
- **验证**:正确凭据 跳转 /dashboard;错误密码 ErrorBanner「用户名或密码错误」;loading 时按钮 disabled
---
## task-064
- **ID**task-064
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 P02 工作台 /dashboard**仅 admin**GD-11
- **输入**UI设计 §2.3admin 部分);PRD GD-11
- **输出**`app/dashboard/page.tsx`;快捷入口:预警中心、RPA 状态、指标看板;未处理预警角标
- **实现范围****不含 customer/operator 卡片**admin 登录后默认页
- **验证**admin 显示「预警中心」「RPA 状态」「指标看板」;无 customer 入口
---
## task-079
- **ID**task-079
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 P07 预警中心页 /admin/alerts(含管理操作)
- **输入**UI设计 §2.8task-056 task-057 task-099 task-100
- **输出**`app/admin/alerts/page.tsx`;筛选 + DataTable + Drawer + **标记已处理 / 跳转 RPA 暂停 / 人工兜底录入入口**
- **实现范围**:类型颜色标签 + 分页 + 处理按钮 + 链到 manual-fallback
- **验证**RPA_FAILED Error 标签;处理后 resolved;可跳转暂停 Worker 或人工录入
---
## task-103
- **ID**task-103
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 /admin/rpa RPA 状态与开发进度页
- **输入**PRD §3.1 管理端 RPAtask-093
- **输出**`app/admin/rpa/page.tsx`;展示 Worker 状态、队列深度、成功率、熔断状态;**暂停 Worker 按钮(调 task-099**
- **实现范围**:只读 + 暂停操作;不含 Worker 代码
- **验证**admin 页面渲染指标;点击暂停 Worker 停止接 job;非 admin 403
---
## task-104
- **ID**task-104
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 /admin/dashboard 指标汇总页
- **输入**task-102PRD §12.7 Go-No-Go
- **输出**`app/admin/dashboard/page.tsx`;展示 GD-4 三率、缓存命中率、P95、未处理预警
- **实现范围**:只读 dashboard;数据来自 GET /api/metrics/dashboard
- **验证**admin 四指标卡片有值;低于阈值时 Warning
---
## task-132
- **ID**task-132
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 /admin/queues Bull Board 队列监控页(P1
- **输入**:技术设计 §8.2 CHG-T10task-021
- **输出**`app/admin/queues/page.tsx` + Bull Board 挂载;admin RBAC
- **实现范围**:展示 quote-rpa 队列深度、失败 job、延迟;文案全中文
- **验证**admin 页面渲染队列指标;非 admin 403
---
## task-080
- **ID**task-080
- **状态**:已完成
- **模块**Frontend
- **目标**:实现 P08/P09 错误页(403/404
- **输入**UI设计 §1.1
- **输出**`app/403/page.tsx` + `app/not-found.tsx`;含返回按钮
- **实现范围**:静态错误页
- **验证**:访问 /403 显示「无访问权限」;未知路由 显示「页面不存在」
---
# 测试系统Test
---
# 已废止v1.1 不实施)
> 执行顺序task-075 → task-076 → task-077 → task-078
## ~~task-075~~v1.1 已废止)
- **ID**task-075
- **状态****已废止** task-106 替代(PRD GD-11 宿主嵌入,不做独立 `/quote` 页)
- **原目标**:独立查价页 /quote
---
## ~~task-076~~v1.1 已废止)
- **ID**task-076
- **状态****已废止** 嵌入组件内展示结果,不单独 `/quote/result/[id]`
---
## ~~task-077~~v1.1 已废止)
- **ID**task-077
- **状态****已废止** 询价历史由宿主系统调用 GET /api/quotes/history,中台不提供 C 端历史页
---
## ~~task-078~~v1.1 已废止)
- **ID**task-078
- **状态****已废止** PRD §2.3 禁止中台运营加价 UI;加价由宿主调 PUT /api/markup-configs
---
# Phase 9 — 测试与 CI建议随模块并行收尾全量回归
> 执行顺序task-081 → task-082 → task-083 → task-084 → task-085 → task-086 → task-087 → task-112 → task-113 → task-114 → task-115 → task-116 → task-088 → task-089 → task-090 → task-117 → task-118 → task-091
## task-081
- **ID**task-081
- **状态**:已完成
- **模块**Test
- **目标**:实现 PricingEngine 单元测试(TC-103
- **输入**task-041PRD §6.3 §12.1 TC-103
- **输出**`__tests__/pricing/engine.test.ts`;覆盖 raw_freight=320/surcharges=15/markup=10%含surcharge=0场景边界值markup=0/30
- **实现范围**:仅 PricingEngine 函数测试
- **验证**`npm run test:unit` 全部 passmarkup_amount=32.00final_total=367.00 精确到分
---
## task-082
- **ID**task-082
- **状态**:已完成
- **模块**Test
- **目标**:实现 ValidationModule 单元测试(TC-201~204+E4系列)
- **输入**task-010PRD §4.5 §12.2
- **输出**`__tests__/validation/validation.test.ts`;覆盖8类异常(缺字段/超范围/地址未点选/非UUID/超Mothership范围/注入/枚举外/件数字段)
- **实现范围**:仅校验函数测试
- **验证**:全部场景通过;边界值 pallet_count=25通过/26失败总重249975通过/249976失败
---
## task-083
- **ID**task-083
- **状态**:已完成
- **模块**Test
- **目标**:实现 cargo_hash + 单位换算 单元测试(TC-106 TC-107
- **输入**task-011 task-012
- **输出**`__tests__/quote/cargo-hash.test.ts` + `__tests__/quote/unit-converter.test.ts`
- **实现范围**:相同货物→相同hashservice_level不同→相同hash227kg500.05lb122cm48.03in
- **验证**:全部 pass
---
## task-084
- **ID**task-084
- **状态**:已完成
- **模块**Test
- **目标**:实现 IdempotencyModule 单元测试(TC-105 TC-207 TC-404
- **输入**task-013TestcontainersRedis
- **输出**`__tests__/quote/idempotency.test.ts`;并发10次相同 request_id 1DB记录
- **实现范围**Redis mock + DB 事务测试
- **验证**:并发10 DB 1条;重启后DB兜底返回原 quote_id
---
## task-085
- **ID**task-085
- **状态**:已完成
- **模块**Test
- **目标**:实现 POST /api/quotes 集成测试(TC-101~108主功能)
- **输入**task-015SupertestTestcontainersMySQL+Redis
- **输出**`__tests__/api/quotes.test.ts`;覆盖正常流程/L2命中/L1幂等/L3降级/失败
- **实现范围**HTTP 层集成测试(mock RPA
- **验证**TC-101~108 全部列于验证行;TC-101source=rpaTC-104cacheTC-105幂等TC-106/107换算/hashTC-108L2 TTL 过期,见 task-112TC-205/206Fallback
---
## task-086
- **ID**task-086
- **状态**:已完成
- **模块**Test
- **目标**:实现安全与权限集成测试(TC-501~506
- **输入**task-003 task-005Supertest
- **输出**`__tests__/api/security.test.ts`;覆盖越权/RBAC/限流/SQL注入
- **实现范围**HTTP 层安全测试
- **验证**TC-501(越权403+**task-094 audit**TC-502TC-503customer+**IP task-035-ip**TC-504(注入400+SECURITY alertTC-505TC-506
---
## task-087
- **ID**task-087
- **状态**:已完成
- **模块**Test
- **目标**:实现偏差预警集成测试(TC-210~212
- **输入**task-051Prisma QuoteCacheMeta
- **输出**`__tests__/alert/deviation.test.ts`;覆盖5.1%触发/4.9%不触发/首次不触发
- **实现范围**:仅偏差检测逻辑测试
- **验证**TC-210/TC-211/TC-212 全部 pass
---
## task-112
- **ID**task-112
- **状态**:已完成
- **模块**Test
- **目标**TC-108 L2 过期触发新 RPA 集成测试
- **输入**task-032task-014
- **输出**`__tests__/api/l2-expire.test.ts`mock TTL 过期或手动 DEL L2 POST source=rpa
- **验证**L2 不存在 触发 RPAmocksource_type=rpa
---
## task-113
- **ID**task-113
- **状态**:已完成
- **模块**Test
- **目标**TC-401 cache vs RPA 一致性测试
- **输入**task-032 task-051
- **输出**`__tests__/api/cache-consistency.test.ts`
- **验证**L2 raw_total 与写入时 RPA 一致;新 RPA 偏差≥5% 触发 PRICE_DEVIATION
---
## task-114
- **ID**task-114
- **状态**:已完成
- **模块**Test
- **目标**TC-403 加价可复算 DB 集成测试
- **输入**task-041
- **输出**`__tests__/pricing/recalc-from-db.test.ts`
- **验证**:从 DB raw_freight + markup 重算 final_total 误差 0.01
---
## task-115
- **ID**task-115
- **状态**:已完成
- **模块**Test
- **目标**FallbackOrchestrator 集成测试(TC-205/206/602
- **输入**task-092
- **输出**`__tests__/quote/fallback-orchestrator.test.ts`
- **验证**:有 L3 stale done + STALE_FALLBACK;无 L3 failed + RPA_FAILED
---
## task-116
- **ID**task-116
- **状态**:已完成
- **模块**Test
- **目标**RPA 状态 API + 管理员暂停集成测试
- **输入**task-093 task-099
- **输出**`__tests__/api/rpa-admin.test.ts`
- **验证**GET status 200POST pause Worker 不接 job
---
## task-088
- **ID**task-088
- **状态**:已完成
- **模块**Test
- **目标**:实现 RPA Worker E2E 测试(TC-601~605,使用 RPA mock
- **输入**task-021~029Playwright mock;技术设计 §11.1
- **输出**`e2e/rpa.test.ts`;模拟正常/验证码/DOM变更/超时场景
- **实现范围**Worker 链路测试(不真实调 Mothership
- **验证**TC-601**quotes=4 档**,非 PRD TC-601 笔误的 2 条);TC-602~605
- **v1.2 说明**:基线已实现;行为变更由 task-12x 承接
---
## task-089
- **ID**task-089
- **状态**:已完成
- **模块**Test
- **目标**:实现查价页 E2E 测试(Playwright,核心路径)
- **输入**task-106Playwright E2EPRD §12.8
- **输出**`e2e/quote-flow.test.ts`5 条核心路径(嵌入组件 demo 页)
- **实现范围**:浏览器级 E2Emock API 响应)
- **验证**5条路径全部 passprocessing Skeleton 显示;成功后显示4Tabstale WarningBanner 显示
---
## task-090
- **ID**task-090
- **状态**:已完成
- **模块**Test
- **目标**:实现限流性能测试(TC-303 TC-301
- **输入**k6task-035(限流);PRD §12.3
- **输出**`load-tests/rate-limit.js` + `load-tests/rpa-p95.js` + **`load-tests/l2-p95.js`TC-302**
- **实现范围**customer 60/minRPA P95<30s**L2 命中 P95<300ms**
- **验证**TC-303TC-301**TC-302 P95<300ms**
---
## task-117
- **ID**task-117
- **状态**:已完成
- **模块**Test
- **目标**Go-No-Go GD-4 指标验收脚本
- **输入**task-101 task-102PRD §12.7
- **输出**`scripts/go-no-go-check.ts`;输出 PASS/FAIL 与四指标实测值
- **验证**1000 mock 后脚本判定三率/命中率是否达标
- **v1.2 说明**:基线已实现;行为变更由 task-12x 承接
---
## task-118
- **ID**task-118
- **状态**:已完成
- **模块**Test
- **目标**E2E + Load nightly workflow
- **输入**task-089 task-090 task-117
- **输出**`.github/workflows/e2e-nightly.yml`
- **验证**cron 触发;artifact 上传 k6 报告
---
---
## task-133
- **ID**task-133
- **状态**:待执行
- **模块**Test
- **目标**TC-601 修订(四档 + probe 对齐 PRD v0.6
- **输入**PRD TC-601 CHG-P08task-130
- **输出**:修订 `e2e/rpa.test.ts` / `__tests__/integration/rpa-probe.test.ts`items=4 断言
- **实现范围**mock 关闭时 probe 四档;文档对齐 v0.6 口径
- **验证**TC-601 items.length===4 2
---
## task-134
- **ID**task-134
- **状态**:待执行
- **模块**Test
- **目标**Go-No-Go probe 3/3 门禁
- **输入**PRD §12.7 CHG-P09task-130
- **输出**`scripts/go-no-go-check.ts` probe 3/3 条件(`RPA_MOCK_MODE=false` 时启用)
- **实现范围**probe 失败 Go-No-Go FAILmock 模式跳过 probe 门禁
- **验证**mock 模式 PASS;真实 env probe 3/3 PASS
---
## task-135
- **ID**task-135
- **状态**:待执行
- **模块**Test
- **目标**CI nightly probe 步骤
- **输入**task-134task-118
- **输出**`.github/workflows/e2e-nightly.yml` 可选 headed probe 步骤(secrets MOTHERSHIP env
- **实现范围**nightly 不阻断 mergeprobe 失败上传 artifact
- **验证**workflow 语法有效;secrets 缺失时跳过 probe 步骤
---
## task-091
- **ID**task-091
- **状态**:已完成
- **模块**Test
- **目标**:配置 CI 门禁(GitHub Actions
- **输入**:技术设计 §11.2package.json scripts
- **输出**`.github/workflows/ci.yml`lint + test:unit + test:integration + build**`.github/workflows/e2e-nightly.yml` E2E + loadtask-118**
- **实现范围**CI 阻断 unit/integrationE2E/load nightly 不阻断 merge 但报告 Go-No-Go
- **验证**PR push unit/integration pass 才绿;nightly e2e + k6
---
## 附录 A验收用例 → Task 映射v1.2 全覆盖)
| TC | 主验证 Task | 辅助 Task |
|----|-------------|-----------|
| TC-101~108 | 085, 112 | 014, 032, 013, 011, 012 |
| TC-201~204 | 082, 010 | |
| TC-205~206 | 115, 092, **129** | 052, 053 |
| TC-207 | 084, 013 | |
| TC-208~209 | 018, 028, 036, **128** | 092 |
| TC-210~212 | 087, 051 | |
| TC-301~304 | 090, 018, 021 | |
| TC-401 | 113 | 032, 051 |
| TC-402~404 | 084, 019 | 013 |
| TC-403 | 114 | 041 |
| TC-501~506 | 086, 094, 035-ip | 004, 010 |
| TC-601~605 | 088, 115, **130, 133** | 026, 027, 092, 123127 |
| Go-No-Go | 117, 101, 102, **134** | 090, **130** |
| probe 3/3 | **130, 134, 135** | 121, 122 |
---
## 附录 B完整性矩阵PRD v0.6 + 技术设计 v1.2
### B.1 维度覆盖
| 维度 | v1.1 基线 Task | v1.2 增量 Task |
|------|----------------|----------------|
| PRD 功能点 | 001118(除废止) | GD-15(119122)、错误码(128129)、probe(130,133135)、Bull Board(132) |
| 技术模块 | Phase 已覆盖 | quote-page-adapter(123)、storageState(124)、selector env(125127)、probe(130) |
| UI 页面 | 106 + admin 6 | `/admin/queues`(132) |
| API(§8.5 七接口 + RPA admin | 015018, 042043, 056057, 029/093/099/100 | 无新增 REST |
| 数据表(6 张) | 070073 | 无新增表 |
### B.2 PRD v0.6 变更 → Task
| CHG ID | 章节 | Task |
|--------|------|------|
| CHG-P02 | GD-15 | 119, 121, 122 |
| CHG-P03 | §2.5 | 128, 129 |
| CHG-P04 | §5.6 | 128 |
| CHG-P05 | §8.2 | 123, 124 |
| CHG-P06 | §8.2.1~8.2.3 | 119, 121, 122, 125127 |
| CHG-P07 | §11.5 | 124, 128 |
| CHG-P08 | TC-601 | 130, 133 |
| CHG-P09 | §12.7 | 134, 135 |
### B.3 技术设计 v1.2 变更 → Task
| CHG ID | 章节 | Task |
|--------|------|------|
| CHG-T02 | §5 目录 | 121, 130 |
| CHG-T03 | §6.2 env | 119, 131 |
| CHG-T04 | §6.1 compose | 120 |
| CHG-T05~T07 | §7.2 | 123127 |
| CHG-T08 | §7.3 | 128 |
| CHG-T09 | §7.5 | 124, 120 |
| CHG-T10 | §8.2 | 132 |
| CHG-T11~T12 | §9.2 | 121, 122 |
### B.4 v1.1 Traceability Matrix 缺口(已闭合,基线)
| Matrix 缺口 | Task |
|-------------|------|
| Fallback 编排无独立 Task | task-092, 115 |
| GET /api/rpa/status + /admin/rpa | task-093, 103 |
| audit log | task-070(schema), 094 |
| confidence_score | task-095 |
| lib/response.ts / lib/prisma.ts | task-096, 097 |
| GD-4 metrics | task-101, 102, 104, 117 |
| IP 限流 | task-035-ip |
| 503 retry | task-098 |
| 管理员暂停 RPA | task-099, 103 |
| 人工兜底录入 | task-100, 079 |
| display_unit | task-065 |
| 客户端退避 | task-066 |
| 宿主嵌入 vs 独立页 | task-106(废止 075~077 |
| 中台加价 UI 漂移 | 废止 078 |
| TC-108/302/401/403 | task-112~114 |
| quote_id 冲突 | task-109 |
| CARRIER/ADDRESS 错误码 | task-110 |
| BR-5.5 四档齐全 | task-111 |
| SESSION_EXPIRED/SECURITY | task-105 |
| rpa:operate RBAC | task-005 |