Appearance
Go-Live Checklist — Prepaid Card Analytics Tab
Date: 2026-05-04 · Phase: 1 (MVP — 4 sub-tab) Parent: prd.md · dev-spec.md · qa-test-plan.md
E1. Tiêu chí cổng (Gate Criteria)
| Gate | Owner | Pass condition |
|---|---|---|
| G1 — Code complete | Tech Lead | All P0 tasks per plan.md merged to main |
| G2 — QA sign-off | QA Lead | qa-test-plan Exit criteria đạt 100% P0 + ≥95% P1 |
| G3 — Reconciliation | Kế toán + BE | Số liệu MV match báo cáo cũ ± 0.1% trên 3 tháng |
| G4 — Security review | DevOps + Security | RBAC v2 fine-grained 3 actions (view · export · view_full_phone) hoạt động · SDT masked theo permission · Export audit log per-export-type · BE enforce (không chỉ trust FE) |
| G5 — Performance | BE + DevOps | Tổng quan < 500ms · Export 50K < 60s · MV refresh < 30s/MV |
| G6 — Rollback drill | DevOps | Feature flag toggle off ≤ 1 phút khôi phục tab cũ |
| G7 — Stakeholder sign-off | PO | PO + Tech Lead + Kế toán đại diện approve |
E2. Checklist trước deploy (Day −1)
E2.1 Cơ sở dữ liệu (Database)
[ ] Verify
region_branchdata:sqlSELECT COUNT(*) FROM region_branch; -- expect ≥ 4 SELECT COUNT(*) FROM branch WHERE region_id IS NULL AND deleted_at IS NULL; -- expect 0Nếu có CN missing region_id → seed thủ công trước deploy.
[ ] Verify schema fields đã match Section 0:
order_item.prepaid_value_into_walletexistsorder_item.product_idexists, JOINprepaid_card_vieworder.total(KHÔNGtotal_amount)paid_amount,paid_atderive trạng thái
[ ] 4 P1 MVs đã deploy on staging (v3 topology — đã tách order/card-level để fix double count):
mv_prepaid_order_daily⭐ (order-level KPIs)mv_prepaid_card_daily⭐ (card-level chart)mv_prepaid_customer_stats(KH segment + behavior)mv_prepaid_finance_daily(PTTT split — đã bỏtotal_wallet_topupđể tránh double count)
[ ] Indexes (Section 9.3) deployed:
idx_order_prepaid_report(composite)idx_order_prepaid_debt(partial — dùngpaid_amount < total, khôngpaid_statusenum)idx_invoice_order_paididx_invoice_wallet_usageidx_txreq_commission_order(wallet schema)
[ ] Functions deployed:
compute_prepaid_alerts(...)(alert function — filterbalance > 0, querywallet_balance_result)set_current_timestamp_updated_at()(existing helper)
[ ]
export_jobtable created (audit + progress tracking)[ ] Dynamic Permission v2 seeded:
- Module
report.prepaid_analyticsregistered - 3 actions:
view,export,view_full_phone - Default grants per role (Section 5.3 prd.md matrix)
- Module
E2.2 Dịch vụ Backend
- [ ] export-api running + endpoint
/actions/export-prepaid-reportready - [ ] scripts service có cron MV refresh (4 MVs P1):cron
*/15 * * * * REFRESH MATERIALIZED VIEW CONCURRENTLY mv_prepaid_order_daily */15 * * * * REFRESH MATERIALIZED VIEW CONCURRENTLY mv_prepaid_card_daily */15 * * * * REFRESH MATERIALIZED VIEW CONCURRENTLY mv_prepaid_finance_daily */30 * * * * REFRESH MATERIALIZED VIEW CONCURRENTLY mv_prepaid_customer_stats - [ ] Redis running cho
wallet_balance_resultcache (TTL 10 phút) - [ ] MinIO/GCS sẵn sàng nhận file export
- [ ] ⚠️
notification-apiKHÔNG cần cho Sub-tab Khách hàng — bulk SMS/ZNS đã bỏ khỏi tab Analytics (review L5)
E2.3 Backfill MV (chạy 1 lần)
- [ ] Backfill script chạy cho dữ liệu lịch sử (4 MVs P1):bash
# Refresh đầy đủ (NOT CONCURRENT lần đầu để build full dataset) psql -c "REFRESH MATERIALIZED VIEW mv_prepaid_order_daily;" psql -c "REFRESH MATERIALIZED VIEW mv_prepaid_card_daily;" psql -c "REFRESH MATERIALIZED VIEW mv_prepaid_customer_stats;" psql -c "REFRESH MATERIALIZED VIEW mv_prepaid_finance_daily;" - [ ] Verify row counts:
order_daily~150K rows ·card_daily~500K ·customer_stats~100K ·finance_daily~500K - [ ] First refresh time logged trong backfill report
E2.4 Frontend (FE)
- [ ] Build artifact test trên staging (admin variant) — không có error console
- [ ] Feature flag
FEATURE_PREPAID_ANALYTICS_V2 = truetrên staging - [ ] Routes registered đúng (4 routes P1):
/r/reports/prepaid-card-analytics/overview/r/reports/prepaid-card-analytics/transactions/r/reports/prepaid-card-analytics/customers/r/reports/prepaid-card-analytics/finance
- [ ] Routes
/marketingvà/staffKHÔNG có (defer P3+)
E2.5 Permissions (RBAC v2 fine-grained — 3 actions)
- [ ] Module
report.prepaid_analyticsđã add vào Dynamic Permission v2 registry - [ ] 3 actions seeded:
view,export,view_full_phone - [ ] Default grants per role (theo prd.md Section 5.3 matrix):
- admin:
[view, export, view_full_phone](branch_mode=all) - area_manager:
[view, export](branch_mode=scoped) - branch_manager:
[view, export](branch_mode=self) - accountant:
[view, export, view_full_phone](cần xem SDT đầy đủ để gọi nợ) - marketing:
[view]only (KHÔNG export bulk, KHÔNG SDT) - staff:
[](tab ẩn)
- admin:
- [ ] Test với từng role trên staging:
viewaction → tab visible/hidden đúngexportaction → 5 nút "Xuất{Tên báo cáo}" + 1 nút "Xuất Excel" hide/show đúng (tất cả cùng 1 permission — DEC-U10)view_full_phoneaction → SDT mask/unmask đúng trong UI table + export file
- [ ] BE enforce — KHÔNG chỉ trust FE: thử bypass FE check bằng curl trực tiếp endpoint export → phải trả 403
- [ ] Audit log working — mỗi export ghi vào
export_jobvớiphone_unmaskflag
E2.6 Đối soát (Reconciliation)
- [ ] Run reconciliation script: so sánh số liệu MV vs báo cáo cũ trên 3 tháng gần nhất
- [ ] Acceptable delta: ≤ 0.1% (do tab cũ có bug skip 1000 rows export + exclude flexible)
- [ ] Document delta trong reconciliation report
E3. Triển khai ngày 0 (Day-0)
E3.1 Deployment sequence (ưu tiên thứ tự)
- 17:00 — DB migrations (low traffic)
- [ ] Apply migrations P1 (KHÔNG
branch_region— đã có; 4 MVs + indexes + 1 functioncompute_prepaid_alerts+export_jobtable) - [ ] Verify 4 MVs P1 created
- [ ] Apply migrations P1 (KHÔNG
- 17:30 — Backfill MV (background, ~10-15 phút)
- [ ] Run REFRESH non-CONCURRENT lần đầu cho 4 MVs P1
- 18:00 — Cron MV refresh (enable)
- [ ] Add cron entries cho 4 MVs P1
- [ ] Verify first auto-refresh hoạt động
- 18:30 — Backend services deploy
- [ ] export-api restart với endpoint mới
- [ ] Hasura metadata reload — track 4 MVs P1 + 1 function + permissions theo 3 actions +
export_jobtable. KHÔNG tracksearch_prepaid_global/mv_prepaid_staff_stats/mv_prepaid_campaign_stats - [ ] Action handler
prepaid_top_staff_p1nếu cần (Top NV Overview compute trực tiếp)
- 19:00 — Frontend deploy
- [ ] Deploy build với feature flag =
true - [ ] CDN cache invalidate
- [ ] Deploy build với feature flag =
- 19:15 — Smoke test
- [ ] Login admin → vào tab → 4 sub-tab P1 (Tổng quan / Giao dịch / Khách hàng / Tài chính) load < 1s
- [ ] Routes
/marketingvà/staffKHÔNG accessible (404 hoặc redirect) - [ ] Test 1 export → file download được, audit log ghi đúng
- [ ] Test SDT mask theo role
- [ ] Verify cron refresh chạy đúng cho 4 MVs
E3.2 Truyền thông
- [ ] T-1 day: Notify Kế toán + Marketing + Quản lý "Tab Analytics ra mắt mai 19:00"
- [ ] T-0 19:30: Send announcement với link onboarding video / quick start
- [ ] T+1 day: Monitor user feedback channel (Slack/Telegram)
E4. Theo dõi ngày 1 (24h sau deploy)
E4.1 Metrics theo dõi
| Metric | Target | Alert threshold | Channel |
|---|---|---|---|
| Tab load time (P95) | < 500ms | > 1000ms | DataDog |
| MV refresh success rate | 100% | < 95% | Cron logs |
| Export success rate | > 98% | < 90% | export-api logs |
| Error rate FE | < 0.5% | > 2% | Sentry |
| User adoption (DAU) | ≥ 30% kế toán | — | Analytics |
E4.2 Reconciliation check (Day-1 morning)
- [ ] So sánh KPI hôm trước trên tab mới vs tab cũ
- [ ] Nếu chênh lệch > 0.5% → escalate Tech Lead + BE
E4.3 Sẵn sàng hotfix
- [ ] DevOps on-call 24h sau deploy
- [ ] Hotfix branch
hotfix/prepaid-analytics-day1ready - [ ] Rollback plan documented (Section E6)
E5. Ký duyệt (Sign-off)
| Role | Name | Sign-off date | Notes |
|---|---|---|---|
| Product Owner | _______________ | __________ | |
| Tech Lead | _______________ | __________ | |
| QA Lead | _______________ | __________ | |
| BE Lead | _______________ | __________ | |
| FE Lead | _______________ | __________ | |
| DevOps | _______________ | __________ | |
| Kế toán đại diện | _______________ | __________ |
E6. Runbook rollback
Scenario 1: Critical bug — sai số liệu tài chính
Trigger: Kế toán report số liệu sai > 1% so với báo cáo cũ.
Steps:
- Immediate (< 5 phút): Toggle feature flag
FEATURE_PREPAID_ANALYTICS_V2 = false→ user quay lại tab cũ - Investigate root cause (BE log + MV state)
- Fix → deploy hotfix → re-enable flag
Scenario 2: MV refresh fail liên tiếp
Trigger: Cron log "REFRESH ... FAILED" 3 lần liên tiếp.
Steps:
- Check DB load → nếu cao → throttle other queries
- Check MV size + index health
- Manual REFRESH non-CONCURRENT (chấp nhận lock ngắn)
- Nếu vẫn fail → drop MV + recreate (có thể mất data ngắn)
Scenario 3: Export crash (OOM hoặc timeout)
Trigger: export-api OOM, file không generate.
Steps:
- Reduce chunk size từ 1000 → 500 rows
- Restart export-api với memory tăng tạm thời
- User retry → nếu vẫn fail → manual SQL extract gửi qua email
Scenario 4: MV refresh gây tải DB cao
Trigger: DB CPU > 80% trong refresh window.
Steps:
- Tăng interval cron: 15 phút → 30 phút (summary, finance) · 30 → 60 phút (customer)
- Move refresh sang off-peak hours (2-4 AM)
- Nếu vẫn cao → drop indexes phụ tạm thời, profile query
Scenario 5: Schema field mismatch (chưa verify hết)
Trigger: Migration apply fail, hoặc query return 0 rows.
Steps:
- Toggle feature flag OFF
- Verify schema vs dev-spec Section 0 — find mismatched field
- Update SQL trong MV definition
- Re-deploy migration → re-enable flag
E7. Phase 2 / Phase 3+ readiness
Khi nào enable Phase 2 (Global Search)?
Trigger: ≥ 1 tháng Phase 1 stable, có user feedback "cần search xuyên sub-tab".
Action:
- [ ] Run migration
create_search_prepaid_global(Phase 2) - [ ] Add
pg_trgmGIN index - [ ] Build component
PrepaidAnalyticsGlobalSearch.tsx - [ ] Integrate vào shared filter bar
Khi nào enable Phase 3+ (Marketing + Nhân viên sub-tab)?
Trigger: Org có nhu cầu rõ ràng (Marketing yêu cầu báo cáo CD chuyên sâu / Quản lý vùng cần coaching data).
Action:
- [ ] Run migrations
create_mv_prepaid_staff_stats,create_mv_prepaid_campaign_stats - [ ] Build 9 components Phase 3+ (Marketing 6 + Staff 4)
- [ ] Enable routes
/marketing,/staff - [ ] Update navigation tooltip → enable click
- [ ] QA test cycle riêng cho Phase 3+
Reference:
- Implementation: plan.md
- Test cases: qa-test-plan.md
- Handoff: handoff.md