docs(plan): IA 计划加 Task 0 订单过期态后端 + 前端 expired 处理 + 部署步骤
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
**Goal:** 把已评审的 IA(`docs/account-ia-reorg-design.html`)落成 Flutter:账户/设置/联系去重归位,Account 提为桌面一级项,顶栏加通知铃铛,账户页加邀请入口,并为 Spec ②推广激励 / ③系统通知 留占位屏与接口。
|
||||
|
||||
**Architecture:** 复用现有 Riverpod + shell(desktop/mobile/tablet) + `open(NavView, mobilePage)` 下钻模式。多数是改造现有页面(account_page/settings_page/account_screens)+ 导航(navigation_provider/desktop_shell);新建仅 2 个占位屏(InviteScreen/NotificationsScreen)+ 铃铛 widget。邀请奖励引擎、通知下发机制**不在本计划**(各自 Spec)。
|
||||
**Architecture:** 复用现有 Riverpod + shell(desktop/mobile/tablet) + `open(NavView, mobilePage)` 下钻模式。多数是改造现有页面(account_page/settings_page/account_screens)+ 导航(navigation_provider/desktop_shell);新建仅 2 个占位屏(InviteScreen/NotificationsScreen)+ 铃铛 widget。**唯一后端改动 = 订单过期态(Task 0,display-only 零迁移)**——付款/订单核心后端已完成并部署生产。邀请奖励引擎、通知下发机制**不在本计划**(各自 Spec ②③,前后端一起)。
|
||||
|
||||
**Tech Stack:** Flutter / Dart · flutter_riverpod 2.x · 现有 `PangolinIcons`(生成,勿手改) · `AppText` 抽象基类 + 6 语言 strings。
|
||||
|
||||
@@ -18,6 +18,77 @@
|
||||
|
||||
---
|
||||
|
||||
### Task 0: 后端 — 订单过期态(display-only,零迁移)
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/internal/pay/handler.go`(`orderViewFromRow` + `orderPendingTTL` 常量)
|
||||
- Test: `server/internal/pay/handler_test.go`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: 订单视图 `status` 新增可能值 `"expired"`(供前端映射)。判定:本地台账 `status=="created"` 且 `created_at + orderPendingTTL < now` → 视图显 `expired`(DB 不改,与金额兜底同为展示层)。
|
||||
|
||||
- [ ] **Step 1: 写过期判定测试(失败)**
|
||||
|
||||
在 `handler_test.go` 加:
|
||||
```go
|
||||
// 老 created 单超 TTL → 列表视图显 expired;近期 created → 仍 created。
|
||||
func TestList_ExpiredWhenStale(t *testing.T) {
|
||||
router, st := newHandlerRig(t, nil)
|
||||
ctx := context.Background()
|
||||
// 直接构造两条 created 单,改 created_at 到很久以前 / 刚刚
|
||||
if err := st.Insert(ctx, 1, "uuid-1", "pro_month", "old", "alipay", 2999, "CNY"); err != nil { t.Fatal(err) }
|
||||
if err := st.Insert(ctx, 1, "uuid-1", "pro_month", "fresh", "alipay", 2999, "CNY"); err != nil { t.Fatal(err) }
|
||||
// 把 old 的 created_at 回拨到 TTL 之前
|
||||
if _, err := st.db.ExecContext(ctx,
|
||||
`UPDATE pay_purchases SET created_at = ? WHERE out_trade_no = 'old'`,
|
||||
time.Now().Add(-2*orderPendingTTL).UTC()); err != nil { t.Fatal(err) }
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, authed(httptest.NewRequest(http.MethodGet, "/v1/pay/orders", nil), 1))
|
||||
var resp struct{ Orders []orderView `json:"orders"` }
|
||||
_ = json.Unmarshal(w.Body.Bytes(), &resp)
|
||||
got := map[string]string{}
|
||||
for _, o := range resp.Orders { got[o.OrderNo] = o.Status }
|
||||
if got["old"] != "expired" { t.Fatalf("old 应过期, got %q", got["old"]) }
|
||||
if got["fresh"] != "created" { t.Fatalf("fresh 应 created, got %q", got["fresh"]) }
|
||||
}
|
||||
```
|
||||
> 注:`st.db` 是 `Store` 的私有字段,测试同包(`package pay`)可访问。
|
||||
|
||||
- [ ] **Step 2: 跑测试确认失败**
|
||||
|
||||
Run: `cd server && go test ./internal/pay/ -run TestList_ExpiredWhenStale`
|
||||
Expected: FAIL(old 仍为 created)。
|
||||
|
||||
- [ ] **Step 3: 实现过期判定**
|
||||
|
||||
`handler.go` 加常量 + 在 `orderViewFromRow` 里判定:
|
||||
```go
|
||||
// 未付订单展示层过期窗口(近似 pay 会话时效;仅影响列表/详情显示,不改台账)。
|
||||
const orderPendingTTL = 30 * time.Minute
|
||||
```
|
||||
在 `orderViewFromRow` 组装 `v` 后、`return v` 前加:
|
||||
```go
|
||||
if row.Status == "created" && row.CreatedAt.Add(orderPendingTTL).Before(time.Now()) {
|
||||
v.Status = "expired" // 展示层:台账仍 created,可继续支付/取消
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 跑测试确认通过**
|
||||
|
||||
Run: `cd server && go test ./internal/pay/`
|
||||
Expected: ok(含新测试 + 原有全绿)。
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add server/internal/pay/handler.go server/internal/pay/handler_test.go
|
||||
git commit -m "feat(server/pay): 订单展示层过期态(created 超 TTL 显 expired,零迁移)"
|
||||
```
|
||||
|
||||
> **部署**:本任务改 server,需重编 linux 二进制 + 部署 pangolin1(Task 8 统一部署,或单独发)。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 导航枚举加 invite / notifications
|
||||
|
||||
**Files:**
|
||||
@@ -87,6 +158,8 @@ git commit -m "feat(nav): NavView 加 invite/notifications + kAccountSubViews
|
||||
String get settingsGroupConn; // 连接 / Connection
|
||||
String get settingsGroupAppearance;// 外观 / Appearance
|
||||
String get settingsGroupAbout; // 关于 / About
|
||||
// ── 订单过期态(Task 0 后端产出) ──
|
||||
String get orderStatusExpired; // 已过期 / Expired
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 6 份 strings 各实现(带 @override)**
|
||||
@@ -365,6 +438,36 @@ git commit -m "feat(settings): 删购买/订单卡 + 归连接/外观/关于三
|
||||
|
||||
---
|
||||
|
||||
### Task 7.5: 订单页处理 expired 态
|
||||
|
||||
**Files:**
|
||||
- Modify: `client/lib/screens/orders_page.dart`(状态→pill 映射)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: 后端 `status=="expired"`(Task 0)、`t.orderStatusExpired`(Task 2)。
|
||||
|
||||
- [ ] **Step 1: orders_page 状态映射加 expired**
|
||||
|
||||
`orders_page.dart` 的 `_statusPill`(created→connecting / paid→connected / canceled→neutral)加一支:
|
||||
```dart
|
||||
'expired' => (status: PangolinStatus.neutral, label: t.orderStatusExpired),
|
||||
```
|
||||
过期单动作沿用 created 的「继续支付」(台账仍可 retry;retry 若遇 pay 会话过期会 409→客户端已有重新下单兜底)。
|
||||
|
||||
- [ ] **Step 2: analyze**
|
||||
|
||||
Run: `cd client && flutter analyze lib/screens/orders_page.dart`
|
||||
Expected: No issues found。
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add client/lib/screens/orders_page.dart
|
||||
git commit -m "feat(client/orders): 订单列表/详情显示 expired 过期态"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: 全量验收 + 收尾
|
||||
|
||||
**Files:** 无(验收)
|
||||
@@ -384,15 +487,24 @@ Expected: All tests passed。
|
||||
Run: `cd /Users/wangjia/code/pangolin/.claude/worktrees/pay-v2-integration && node tools/check-l1-sync.mjs && node design/prototype/tools/check-ds.mjs`
|
||||
Expected: 图标同集 OK + l10n 完整 OK + check-ds 5 项过。
|
||||
|
||||
- [ ] **Step 4: 更新决策日志**
|
||||
- [ ] **Step 4: 服务端重编 + 部署(Task 0 改了 server)**
|
||||
|
||||
`docs/pay-v2-dev-log.md` 追加「IA 重构落地」step。
|
||||
```bash
|
||||
cd server && go test ./... && GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -o /tmp/pgl-new ./cmd/server
|
||||
scp /tmp/pgl-new pangolin1:/tmp/pgl-new
|
||||
ssh pangolin1 'cp -a /usr/local/bin/pangolin-server /usr/local/bin/pangolin-server.bak-ia && mv /tmp/pgl-new /usr/local/bin/pangolin-server && chmod +x /usr/local/bin/pangolin-server && systemctl restart pangolin-server && sleep 2 && systemctl is-active pangolin-server'
|
||||
```
|
||||
Expected: `active`。验证 `curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/v1/pay/orders` → 401(路由在)。
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
- [ ] **Step 5: 更新决策日志**
|
||||
|
||||
`docs/pay-v2-dev-log.md` 追加「IA 重构落地 + 订单过期态」step。
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/pay-v2-dev-log.md
|
||||
git commit -m "docs(pay-v2): IA 重构落地验收记录"
|
||||
git commit -m "docs(pay-v2): IA 重构 + 订单过期态 落地验收记录"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user