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

68 KiB

查价系统 工程任务拆解清单 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.mdv0.6)· 查价系统-技术设计.mdv1.2)· 查价系统-UI设计.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.2RPA_MOCK_MODE=falsescripts/probe-rpa.ts 连续 3 次 exit 0,四档 source_type=rpaTC-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_UNAVAILABLEADDRESS_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

  • IDtask-072
  • 状态:已完成
  • 模块:数据库
  • 目标:创建 Docker Compose 配置4容器
  • 输入:技术设计 §6.1
  • 输出docker-compose.yml,含 mysql/redis/next-app/rpa-worker含 healthcheck 和 shm_size
  • 实现范围:仅基础设施配置,不含应用代码
  • 验证docker compose up -d 四容器全部 healthydocker compose ps 状态 running

task-073

  • IDtask-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

  • IDtask-119
  • 状态:待执行
  • 模块Lib/Infra
  • 目标v0.6 RPA 环境变量模板GD-15
  • 输入PRD §8.2.1;技术设计 §6.2 CHG-T03
  • 输出.env.exampleMOTHERSHIP_QUOTE_URLSRPA_STORAGE_STATE_PATHRPA_SELECTOR_*8 项)、RPA_USE_PATCHRIGHT
  • 实现范围:禁止内置 dashboard / /quote 默认 URLMOTHERSHIP_QUOTE_URLS 时 rpa-worker fail-fast
  • 验证.env.example 含全部 RPA 必填项;未配置 URL 列表时 worker 启动报错退出

task-120

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-097
  • 状态:已完成
  • 模块Lib
  • 目标:实现 lib/prisma.ts Prisma 客户端单例
  • 输入:技术设计 §5
  • 输出lib/prisma.ts;导出 prisma 单例dev 热重载防多实例
  • 实现范围:仅 ORM 连接;不含业务查询
  • 验证prisma.$connect() 成功;多模块 import 同一实例

task-030

  • IDtask-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

  • IDtask-096
  • 状态:已完成
  • 模块Lib
  • 目标:实现 lib/response.ts 统一 API 响应包络
  • 输入:技术设计 §4.1PRD §8.5
  • 输出lib/response.tsok(data) / fail(code, message, httpStatus);所有路由复用
  • 实现范围:仅响应格式化;自动附加 Cache-Control: no-store 辅助函数
  • 验证Vitestok → { code:0, message:'ok', data }fail → { code, message, data:null } + 正确 HTTP 状态码

task-031

  • IDtask-031
  • 状态:已完成
  • 模块Cache
  • 目标:实现 L1 缓存idem:{request_id}24h
  • 输入task-030PRD §7.2GD-2
  • 输出modules/cache/redis-cache.tsgetL1(request_id) / setL1(request_id, data)
  • 实现范围SETNX + GETTTL=24hvalue=完整响应快照 JSON
  • 验证set → get 返回相同值TTL 校验 ≈ 86400s重复 SETNX → 不覆盖

task-032

  • IDtask-032
  • 状态:已完成
  • 模块Cache
  • 目标:实现 L2 缓存quote:{cargo_hash}3min+jitter
  • 输入task-030PRD §7.2GD-2
  • 输出modules/cache/redis-cache.tsgetL2(cargo_hash) / setL2(cargo_hash, data)
  • 实现范围SET + GETTTL=180+random(0~30)svalue=四档原始报价 JSON不含加价
  • 验证set → get 返回相同值TTL 在 180~210s 之间(随机 jitter 验证分布)

task-033

  • IDtask-033
  • 状态:已完成
  • 模块Cache
  • 目标:实现 L3 缓存stale:{cargo_hash}30min只读降级
  • 输入task-030PRD §7.2GD-2
  • 输出modules/cache/redis-cache.tsgetL3(cargo_hash) / setL3(cargo_hash, data)(仅 RPA 成功时写入)
  • 实现范围SET + GETTTL=1800s正常路径禁止读取 L3(只在 RPA 失败 fallback 时读)
  • 验证RPA 成功后 L3 有值L2 命中路径不访问 L3

task-034

  • IDtask-034
  • 状态:已完成
  • 模块Cache
  • 目标实现缓存击穿锁lock:quote:{cargo_hash}
  • 输入task-030PRD §11.6
  • 输出modules/cache/redis-cache.tsacquireLock(cargo_hash) / releaseLock(cargo_hash)
  • 实现范围SETNX lock keyTTL=5s获取失败 → 等待2s后读L2用完后 DEL
  • 验证100并发同一 cargo_hash miss → 只触发1次 RPA其余等待后命中 L2TC-11.6

task-035

  • IDtask-035
  • 状态:已完成
  • 模块Cache
  • 目标:实现限流 Redis Key令牌桶60次/分钟/customer
  • 输入task-030PRD §10.3 §11.7GD-4
  • 输出modules/cache/rate-limiter.tscheckRateLimit(customer_id) → 超限返回 RATE_LIMITED
  • 实现范围ratelimit:customer:{id} INCR + EXPIRE 60s超60 → 429
  • 验证60次 → 全部通过第61次 → 429 RATE_LIMITEDTC-303 TC-503

task-035-ip

  • IDtask-035-ip
  • 状态:已完成
  • 模块Cache
  • 目标:实现 IP 级限流1000次/分钟,超限封禁 10 分钟)
  • 输入PRD §11.9
  • 输出modules/cache/ip-rate-limiter.tsratelimit:ip:{ip} + ban:ip:{ip} TTL=600s
  • 实现范围middleware 调用;>1000/min → 429 + 写 SECURITY 预警task-105
  • 验证:单 IP 1200 次/分钟 → 429封禁 10 分钟内全部拒绝TC-503 IP 维度)

加价系统Markup


task-036

  • IDtask-036
  • 状态:已完成
  • 模块Cache
  • 目标实现熔断状态管理circuit:rpa Redis key
  • 输入task-030PRD §10.3 §11.5GD-4
  • 输出modules/cache/circuit-breaker.tsisCircuitOpen() / 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

  • IDtask-001
  • 状态:已完成
  • 模块Auth
  • 目标:实现 JWT 工具函数jose 库:签发/校验/解码)
  • 输入:技术设计 §4.2jose ^5.x
  • 输出modules/auth/jwt.ts,导出 signToken(payload) / verifyToken(token) / decodeToken(token)
  • 实现范围JWT 操作只;不含数据库查询
  • 验证Vitest 单元测试:签发 → 校验通过;篡改 → 抛异常;过期 → 抛异常

task-002

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-098
  • 状态:已完成
  • 模块Lib
  • 目标:实现 gateway 503 单次重试中间件
  • 输入PRD §11.4
  • 输出middleware.tslib/gateway-retry.ts5xx 时 retry 1 次后仍失败 → 503 INTERNAL_ERROR
  • 实现范围:仅网关层重试;不含业务降级
  • 验证mock 首次 503 第二次 200 → 客户端得 200连续 503 → 503 + INTERNAL_ERROR

用户系统Auth


Phase 3 — 加价基础

执行顺序task-040 → task-041 → task-044

task-040

  • IDtask-040
  • 状态:已完成
  • 模块Pricing
  • 目标:实现 roundHalfUp 工具函数
  • 输入PRD GD-10技术设计 §4.5
  • 输出lib/math.tsroundHalfUp(value, decimals) 使用 Number.EPSILON 修正
  • 实现范围:仅数学函数
  • 验证Vitest0.105×2 → 0.21不是0.2032.005 → 32.01;边界值含负数

task-041

  • IDtask-041
  • 状态:已完成
  • 模块Pricing
  • 目标:实现 PricingEngine.applyMarkup()
  • 输入task-040PRD §6.3
  • 输出modules/pricing/engine.tsapplyMarkup(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

  • IDtask-044
  • 状态:已完成
  • 模块Pricing
  • 目标:实现未配置客户默认 0% 逻辑MarkupConfig 查询)
  • 输入Prisma MarkupConfigPRD BR-6.3
  • 输出modules/pricing/engine.tsgetMarkupPercent(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

  • IDtask-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

  • IDtask-011
  • 状态:已完成
  • 模块Quote Engine
  • 目标实现单位换算函数kg→lbcm→in
  • 输入PRD §4.2.2 §4.2.3GD-13
  • 输出modules/quote/unit-converter.tskgToLb(kg) / cmToIn(cm)ROUND_HALF_UP 2位
  • 实现范围:仅数学换算;不含校验逻辑
  • 验证Vitest227kg → 500.05lb±0.01122cm → 48.03in;精度 ROUND_HALF_UP

task-012

  • IDtask-012
  • 状态:已完成
  • 模块Quote Engine
  • 目标:实现 cargo_hash 算法MD5
  • 输入PRD BR-4.4;技术设计 §3.7
  • 输出modules/quote/cargo-hash.tsbuildCargoHash(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

  • IDtask-095
  • 状态:已完成
  • 模块Quote Engine
  • 目标:实现 confidence_score 赋值逻辑F5.6
  • 输入PRD §5.3 F5.6
  • 输出modules/quote/confidence.tsgetConfidenceScore(sourceType) → rpa/cache=0.95stale=0.70
  • 实现范围:仅映射函数;在 GET /quotes 与落库时调用
  • 验证Vitestsource=rpa → 0.95source=stale → 0.70source=cache → 0.95

task-111

  • IDtask-111
  • 状态:已完成
  • 模块Quote Engine
  • 目标:实现 BR-5.5 四档齐全校验done 前 gates
  • 输入PRD BR-5.5GD-1
  • 输出modules/quote/quote-completeness.tsassertFourTiers(quotes[]) → 不足 4 档抛 RPA_DATA_INVALID
  • 实现范围:校验 standard/guaranteed × lowest/fastest 组合齐全orchestrator 与 RPA worker 共用
  • 验证3 档 → 抛错走 Fallback4 档 → 通过TC-102

RPA 系统


task-013

  • IDtask-013
  • 状态:已完成
  • 模块Quote Engine
  • 目标:实现 IdempotencyModuleRedis L1 + DB 双保险)
  • 输入task-031L1 RedisPrisma IdempotencyRecordPRD §7.3 §10.4
  • 输出modules/quote/idempotency.tscheckIdempotency(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

  • IDtask-019
  • 状态:已完成
  • 模块Quote Engine
  • 目标:实现 quote_id 生成函数
  • 输入PRD §5.2 示例格式QTE_20260616_0001
  • 输出modules/quote/quote-id.tsgenerateQuoteId() 含日期+序号;保证唯一性
  • 实现范围:仅 ID 生成;使用 DB 自增或 UUID+日期前缀
  • 验证:并发 100次调用 → 无重复TC-402DB 唯一键冲突 → INTERNAL_ERROR + 写 audittask-109

task-092

  • IDtask-092
  • 状态:已完成
  • 模块Quote Engine
  • 目标:实现 FallbackOrchestratorRPA 失败 → L3 降级完整编排)
  • 输入task-033L3task-041加价task-050~053预警PRD §7.6 §8.4 §2.5
  • 输出modules/quote/fallback-orchestrator.tshandleRpaFailure(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

  • IDtask-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

  • IDtask-014
  • 状态:已完成
  • 模块Quote Engine
  • 目标:实现 QuoteOrchestrator 主流程L1→L2→入队
  • 输入task-010~013task-032L2BullMQPrisma QuoteRecord技术设计 §2.3
  • 输出modules/quote/orchestrator.tssubmitQuote(body) 完整主流程
  • 实现范围:换算 → 校验 → L1 → L2命中则加价+落库+写L1+返回done→ 未命中则 INSERT processing + 入队 → 返回 processingRPA 失败时委托 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

  • IDtask-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

  • IDtask-016
  • 状态:已完成
  • 模块Quote Engine
  • 目标:实现 GET /api/quotes/{quoteId} 路由(轮询 + expired 检测)
  • 输入task-003Prisma QuoteRecordPRD §5.2 §5.3
  • 输出app/api/quotes/[quoteId]/route.tsvalid_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

  • IDtask-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

  • IDtask-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

  • IDtask-043
  • 状态:已完成
  • 模块Pricing
  • 目标:实现 PUT /api/markup-configs/{customerId} 路由
  • 输入task-005RBAC pricing:markup:writePrisma MarkupConfigPRD §6.4 §6.5
  • 输出app/api/markup-configs/[customerId]/route.tsUPSERT 操作0~30.0 范围校验
  • 实现范围:权限校验 + 范围校验 + UPSERT + 审计字段operator_id
  • 验证markup=30.0 → 200markup=30.1 → 400TC-505无权限 → 403TC-502客户不存在 → 400

task-018

  • IDtask-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

  • IDtask-121
  • 状态:已完成
  • 模块RPA
  • 目标Playwright codegen 录制入口脚本
  • 输入PRD §8.2.3 GD-15技术设计 §9.2
  • 输出scripts/record-mothership.shheadedRPA_HEADLESS=false
  • 实现范围:启动 codegen禁止 dashboard.mothership.com / www.mothership.com/quote
  • 验证:脚本可执行;录制产出 goto URL 与 selector 可提取

task-122

  • IDtask-122
  • 状态:已完成
  • 模块RPA
  • 目标:录制 SOP 与 env 产出 checklist
  • 输入task-121PRD §8.2.3 LA→Dallas 标准样例
  • 输出docs/rpa-recording-sop.mdURL→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

  • IDtask-020
  • 状态:已完成
  • 模块RPA
  • 目标:实现 QuoteProvider 接口定义
  • 输入:技术设计 §7.1PRD 附录 A
  • 输出modules/providers/quote-provider.tsTypeScript interface QuoteProvider + QuoteItem + QuoteRequest
  • 实现范围仅类型定义items.length === 4 约束注释
  • 验证TypeScript 编译无报错MothershipRPAProvider 实现该接口不报错

task-021

  • IDtask-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

  • IDtask-022
  • 状态:已完成
  • 模块RPA
  • 目标:实现 session-manager.tsMothership 登录态维护)
  • 输入:技术设计 §7.2Playwright
  • 输出workers/rpa/session-manager.tsgetSession() 返回已登录 browser contextSESSION_EXPIRED 时重登1次
  • 实现范围:浏览器常驻 context + 登录状态检测 + 自动重登;不含报价抓取
  • 验证:冷启动 → 自动登录session 过期 → 重登成功;重登失败 → 抛 SESSION_EXPIRED
  • v1.2 说明:基线已实现;行为变更由 task-12x 承接

task-023

  • IDtask-023
  • 状态:已完成
  • 模块RPA
  • 目标:实现 preCheck()(页面健康检查)
  • 输入:技术设计 §7.2Playwright
  • 输出workers/rpa/mothership.tspreCheck() 方法;检测 URL 非 login/captcha关键表单 selector 存在
  • 实现范围:仅检测,不填表单;失败抛对应错误分类
  • 验证:正常页面 → true被重定向到 /login → SESSION_EXPIRED验证码页 → RPA_CAPTCHAselector 消失 → STRUCT_CHANGE
  • v1.2 说明:基线已实现;行为变更由 task-12x 承接

task-024

  • IDtask-024
  • 状态:已完成
  • 模块RPA
  • 目标:实现地址联想点选逻辑(方案 Aplace_id方案 B联想下拉
  • 输入PRD §4.2.1;技术设计 §7.2.1GD-9
  • 输出workers/rpa/mothership.tsfillAddress() 方法;方案 A 优先;方案 B 备用
  • 实现范围:输入街道 → waitForSelector 联想 → click 匹配项 → 断言锁定(联想消失);锁定失败 → ADDRESS_SUGGESTION_NOT_FOUND
  • 验证:正常地址 → 表单锁定;联想不出现 → 抛 ADDRESS_SUGGESTION_NOT_FOUND超5s → timeout

task-025

  • IDtask-025
  • 状态:已完成
  • 模块RPA
  • 目标实现表单填写weight/dims/pallet_count/cargo_type
  • 输入PRD §4.2.2~4.2.4Playwright数据为 lb/in已换算
  • 输出workers/rpa/mothership.tsfillCargo() 方法
  • 实现范围:填 pallet_count映射 Mothership Pallet quantity+ weight_lb + dims_in + cargo_type不含地址
  • 验证录制回放验证字段填入正确pallet_count=2 → Mothership quantity=2 Pallet

task-026

  • IDtask-026
  • 状态:已完成
  • 模块RPA
  • 目标实现四档报价抓取standard/guaranteed × lowest/fastest
  • 输入:技术设计 §7.2 步骤4~7Playwright
  • 输出workers/rpa/mothership.tsscrapeQuotes() 方法;返回 QuoteItem[4]
  • 实现范围:提交一次 → 在结果页分别点 standard/guaranteed → 各切换 lowest/fastest → 抓 rawFreight + transitDays严禁多次提交
  • 验证:实测返回 items.length===4每档 rawFreight>0transitDays 非空

task-027

  • IDtask-027
  • 状态:已完成
  • 模块RPA
  • 目标:实现 RPA 数据一致性校验
  • 输入PRD §8.2;技术设计 §7.2
  • 输出workers/rpa/mothership.tsvalidateResult() 方法
  • 实现范围4档均存在校验每档 rawFreight>0transitDays 非空;失败 → 抛 RPA_DATA_INVALID
  • 验证Vitest3档数据 → RPA_DATA_INVALIDprice=0 → RPA_DATA_INVALIDprice=-1 → RPA_DATA_INVALID

task-028

  • IDtask-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

  • IDtask-110
  • 状态:已完成
  • 模块RPA
  • 目标:实现 RPA 业务错误码映射CARRIER_NO_CAPACITY / ADDRESS_NOT_SUPPORTED
  • 输入PRD §5.6
  • 输出modules/rpa/error-mapper.tsMothership 页面文案 → 对应 error_code
  • 实现范围RPA 抓取阶段识别无运力/邮编不支持;映射后走 092 或 failed
  • 验证mock 无运力页 → error_code=CARRIER_NO_CAPACITY不支持邮编 → ADDRESS_NOT_SUPPORTED
  • v1.2 说明:基线已实现;行为变更由 task-12x 承接

task-029

  • IDtask-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 → 偏差检测 → 写L1RPA失败 → 调用 task-092
  • 验证集成测试RPA 成功后 Redis L2/L3 有值DB source_type=rpa偏差≥5%时 alert_log 有 PRICE_DEVIATION失败时 092 被调用

task-093

  • IDtask-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

  • IDtask-099
  • 状态:已完成
  • 模块RPA
  • 目标:实现 POST /api/rpa/worker/pause管理员手动暂停 Worker
  • 输入PRD §2.4「暂停 RPA Worker」task-005 rpa:operate
  • 输出app/api/rpa/worker/pause/route.tsbody { worker_id, duration_minutes };写 Redis worker:pause:{id}
  • 实现范围admin 手动暂停;不含自动 CAPTCHA 暂停task-054
  • 验证admin 调用 → Worker 指定时间内不接 job非 admin → 403

task-100

  • IDtask-100
  • 状态:已完成
  • 模块RPA
  • 目标:实现 POST /api/quotes/manual-fallback人工兜底录入
  • 输入PRD §2.4「触发人工兜底录入」
  • 输出app/api/quotes/manual-fallback/route.tsadmin 录入四档原始价 → 写 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.2RPA_MOCK_MODE=falsescripts/probe-rpa.ts 连续 3 次 exit 0四档 source_type=rpa

task-123

  • IDtask-123
  • 状态:待执行
  • 模块RPA
  • 目标:实现 QuotePageAdapter 多 URL 探测
  • 输入:技术设计 §7.2.3 CHG-T05/T06task-122
  • 输出workers/rpa/quote-page-adapter.tsresolveQuoteEntry / preCheck / isLoginWithoutCredentials
  • 实现范围:按 MOTHERSHIP_QUOTE_URLS 顺序 goto + preCheck全失败 → QUOTE_ENTRY_UNAVAILABLE
  • 验证:单测 mock 多 URL首个可用 URL 写入 activeUrl全失败抛 QUOTE_ENTRY_UNAVAILABLE

task-124

  • IDtask-124
  • 状态:待执行
  • 模块RPA
  • 目标storageState 生命周期§7.5
  • 输入:技术设计 §7.5 CHG-T09task-120
  • 输出:重构 workers/rpa/session-manager.tscreateContext load、persistContext writeback、invalidateStorageState
  • 实现范围成功查价写回login 无凭据先 invalidate 再重试 goto
  • 验证:单测:存在 state 文件时 load成功后 persistinvalidate 删除文件

task-125

  • IDtask-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

  • IDtask-126
  • 状态:待执行
  • 模块RPA
  • 目标:表单填写与提交 selector env 化
  • 输入:技术设计 §7.2 CHG-T07task-125
  • 输出fillCargo + submit 改用 RPA_SELECTOR_SUBMIT 等 env
  • 实现范围:移除硬编码 data-testid全部读 process.env.RPA_SELECTOR_*
  • 验证录制回放字段填入正确submit 点击成功

task-127

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-050
  • 状态:已完成
  • 模块Alert
  • 目标:实现 AlertService.writeAlert() 通用写入函数
  • 输入Prisma AlertLogPRD §7.7
  • 输出modules/alert/service.tswriteAlert(type, quoteId?, cargoHash?, detail?) 异步写 alert_log
  • 实现范围INSERT alert_log失败时仅 log error不影响主流程try-catch
  • 验证Vitest调用后 DB alert_log 新增1条DB 写失败 → 不抛出异常,主流程继续

task-051

  • IDtask-051
  • 状态:已完成
  • 模块Alert
  • 目标:实现偏差检测逻辑(与 quote_cache_meta 比对)
  • 输入task-050Prisma QuoteCacheMetaPRD §7.5
  • 输出modules/alert/deviation-detector.tsdetectDeviation(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

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-055
  • 状态:已完成
  • 模块Alert
  • 目标:实现 STRUCT_CHANGE 预警写入
  • 输入task-050PRD §11.5
  • 输出STRUCT_CHANGE 错误处理:写 alert_logpreCheck 失败触发
  • 实现范围:仅写预警;不含 RPA 重试(不重试)
  • 验证preCheck 失败 → alert_log STRUCT_CHANGETC-604

task-094

  • IDtask-094
  • 状态:已完成
  • 模块Alert / DB
  • 目标:实现 audit_log 表 + AuditService 写入
  • 输入PRD §10.6 §11.9task-070 schema 含 AuditLog
  • 输出modules/audit/service.tswriteAudit(action, actorId, resource, detail) → audit_log 表
  • 实现范围:越权/注入/敏感操作写入;失败 log 不阻断主流程
  • 验证TC-501 越权后 audit_log 有记录TC-504 注入尝试有 SECURITY audit

task-105

  • IDtask-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

  • IDtask-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

  • IDtask-057
  • 状态:已完成
  • 模块Alert
  • 目标:实现 POST /api/alerts/{id}/resolve 路由
  • 输入task-003Prisma AlertLogPRD §8.5
  • 输出app/api/alerts/[id]/resolve/route.tsUPDATE status=resolved + resolver_id + resolved_at
  • 实现范围鉴权admin+ DB 更新;不含通知
  • 验证admin 调用 → 200 + status=resolved非 admin → 403不存在 id → 404

Phase 7 — 观测指标

执行顺序task-101 → task-102

task-101

  • IDtask-101
  • 状态:已完成
  • 模块Metrics
  • 目标:实现 MetricsCollectorGD-4 三率 + 缓存命中率)
  • 输入PRD §10.2 GD-4 §12.7
  • 输出modules/metrics/collector.tsRedis 计数器:api_success_rate / rpa_success_rate / realtime_rate / cache_hit_rate
  • 实现范围POST/GET quotes 与 RPA 回调处埋点;不含可视化
  • 验证100 次 mock 请求后 GET 内部指标 API 可算出三率;公式与 PRD 一致

task-102

  • IDtask-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

  • IDtask-060
  • 状态:已完成
  • 模块Frontend
  • 目标实现项目基础配置Tailwind + CSS 变量 + 字体)
  • 输入UI设计 §3.1~3.5 §4.4 §4.5
  • 输出app/globals.cssCSS 变量);tailwind.config.tsprimary=teal-600Geist 字体引入
  • 实现范围:仅样式基础配置;不含组件
  • 验证--color-primary: #0D9488 生效Geist Sans 字体加载

task-061

  • IDtask-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

  • IDtask-062
  • 状态:已完成
  • 模块Frontend
  • 目标实现布局组件AppLayout + AdminLayout
  • 输入UI设计 §1.4 §4.6
  • 输出components/layout/app-layout.tsx + components/layout/admin-layout.tsx
  • 实现范围:顶栏导航 + 响应式侧栏;未登录 → 重定向 /login
  • 验证:客户路由使用 AppLayout 正确渲染;管理端路由使用 AdminLayout移动端单列布局

task-065

  • IDtask-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

  • IDtask-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

  • IDtask-067
  • 状态:已完成
  • 模块Frontend
  • 目标:实现 QuoteCard 组件(四档报价展示)
  • 输入UI设计 §3.6 CardPRD §5.1 §5.4
  • 输出components/quote/quote-card.tsxTabstandard/guaranteed子Tablowest/fastest价格 font-monois_realtime=false → WarningBanner角标
  • 实现范围Tab 切换 + 价格明细 breakdown 展示 + 非实时角标;不含倒计时
  • 验证4档数据渲染正确is_realtime=false → WarningBanner 显示UI-06金额 font-mono $1,234.56 格式

task-068

  • IDtask-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

  • IDtask-069
  • 状态:已完成
  • 模块Frontend
  • 目标:实现 QuoteResultPanel7种状态容器
  • 输入UI设计 §2.4 页面状态机task-067 task-068
  • 输出components/quote/quote-result-panel.tsx;根据 QuotePageStatus 渲染对应 UI
  • 实现范围idle→插画processing→Skeleton+进度条success/fallback→QuoteCard+CountdownTimererror→ErrorBannerexpired→ConfirmDialog
  • 验证7种状态逐一切换UI 对应正确

task-106

  • IDtask-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.jspropsserviceToken, 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

  • IDtask-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

  • IDtask-064
  • 状态:已完成
  • 模块Frontend
  • 目标:实现 P02 工作台 /dashboard仅 adminGD-11
  • 输入UI设计 §2.3admin 部分PRD GD-11
  • 输出app/dashboard/page.tsx快捷入口预警中心、RPA 状态、指标看板;未处理预警角标
  • 实现范围不含 customer/operator 卡片admin 登录后默认页
  • 验证admin → 显示「预警中心」「RPA 状态」「指标看板」;无 customer 入口

task-079

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-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-075v1.1 已废止)

  • IDtask-075
  • 状态已废止 — 由 task-106 替代PRD GD-11 宿主嵌入,不做独立 /quote 页)
  • 原目标:独立查价页 /quote

task-076v1.1 已废止)

  • IDtask-076
  • 状态已废止 — 嵌入组件内展示结果,不单独 /quote/result/[id]

task-077v1.1 已废止)

  • IDtask-077
  • 状态已废止 — 询价历史由宿主系统调用 GET /api/quotes/history中台不提供 C 端历史页

task-078v1.1 已废止)

  • IDtask-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

  • IDtask-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

  • IDtask-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

  • IDtask-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不同→相同hash227kg→500.05lb122cm→48.03in
  • 验证:全部 pass

task-084

  • IDtask-084
  • 状态:已完成
  • 模块Test
  • 目标:实现 IdempotencyModule 单元测试TC-105 TC-207 TC-404
  • 输入task-013TestcontainersRedis
  • 输出__tests__/quote/idempotency.test.ts并发10次相同 request_id → 仅1条DB记录
  • 实现范围Redis mock + DB 事务测试
  • 验证并发10次 → DB 仅1条重启后DB兜底返回原 quote_id

task-085

  • IDtask-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

  • IDtask-086
  • 状态:已完成
  • 模块Test
  • 目标实现安全与权限集成测试TC-501~506
  • 输入task-003 task-005Supertest
  • 输出__tests__/api/security.test.ts;覆盖越权/RBAC/限流/SQL注入
  • 实现范围HTTP 层安全测试
  • 验证TC-501越权403+task-094 auditTC-502TC-503customer+IP task-035-ipTC-504注入400+SECURITY alertTC-505TC-506

task-087

  • IDtask-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

  • IDtask-112
  • 状态:已完成
  • 模块Test
  • 目标TC-108 L2 过期触发新 RPA 集成测试
  • 输入task-032task-014
  • 输出__tests__/api/l2-expire.test.tsmock TTL 过期或手动 DEL L2 后 POST → source=rpa
  • 验证L2 不存在 → 触发 RPAmocksource_type=rpa

task-113

  • IDtask-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

  • IDtask-114
  • 状态:已完成
  • 模块Test
  • 目标TC-403 加价可复算 DB 集成测试
  • 输入task-041
  • 输出__tests__/pricing/recalc-from-db.test.ts
  • 验证:从 DB 读 raw_freight + markup 重算 final_total 误差 ≤0.01

task-115

  • IDtask-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

  • IDtask-116
  • 状态:已完成
  • 模块Test
  • 目标RPA 状态 API + 管理员暂停集成测试
  • 输入task-093 task-099
  • 输出__tests__/api/rpa-admin.test.ts
  • 验证GET status 200POST pause 后 Worker 不接 job

task-088

  • IDtask-088
  • 状态:已完成
  • 模块Test
  • 目标:实现 RPA Worker E2E 测试TC-601~605使用 RPA mock
  • 输入task-021~029Playwright mock技术设计 §11.1
  • 输出e2e/rpa.test.ts;模拟正常/验证码/DOM变更/超时场景
  • 实现范围Worker 链路测试(不真实调 Mothership
  • 验证TC-601quotes=4 档,非 PRD TC-601 笔误的 2 条TC-602~605
  • v1.2 说明:基线已实现;行为变更由 task-12x 承接

task-089

  • IDtask-089
  • 状态:已完成
  • 模块Test
  • 目标:实现查价页 E2E 测试Playwright核心路径
  • 输入task-106Playwright E2EPRD §12.8
  • 输出e2e/quote-flow.test.ts5 条核心路径(嵌入组件 demo 页)
  • 实现范围:浏览器级 E2Emock API 响应)
  • 验证5条路径全部 passprocessing Skeleton 显示成功后显示4档Tabstale 时 WarningBanner 显示

task-090

  • IDtask-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.jsTC-302
  • 实现范围customer 60/minRPA P95<30sL2 命中 P95<300ms
  • 验证TC-303TC-301TC-302 P95<300ms

task-117

  • IDtask-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

  • IDtask-118
  • 状态:已完成
  • 模块Test
  • 目标E2E + Load nightly workflow
  • 输入task-089 task-090 task-117
  • 输出.github/workflows/e2e-nightly.yml
  • 验证cron 触发artifact 上传 k6 报告


task-133

  • IDtask-133
  • 状态:待执行
  • 模块Test
  • 目标TC-601 修订(四档 + probe 对齐 PRD v0.6
  • 输入PRD TC-601 CHG-P08task-130
  • 输出:修订 e2e/rpa.test.ts / __tests__/integration/rpa-probe.test.tsitems=4 断言
  • 实现范围mock 关闭时 probe 四档;文档对齐 v0.6 口径
  • 验证TC-601 items.length===4非 2 条

task-134

  • IDtask-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

  • IDtask-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

  • IDtask-091
  • 状态:已完成
  • 模块Test
  • 目标:配置 CI 门禁GitHub Actions
  • 输入:技术设计 §11.2package.json scripts
  • 输出.github/workflows/ci.ymllint + 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