N
NolimitHub Docs
Billing · Sync · Risk
v1.0 · Draft
P1 · High Tách cột + Migration FT-BILL-FUNDED-STATUS-01 Draft

Đồng Bộ & Hiển Thị Đúng Trạng Thái "Funded" Của Hóa Đơn

Bill thanh toán bằng credit / quỹ trả trước được Facebook gắn nhãn "Funded", nhưng hệ thống đang hiển thị "Thành công" (Paid). Nguyên nhân: 2 nguồn dữ liệu FB (API / cookie) trả ra 2 bộ status khác nhau nhưng đang dùng chung một cột payment_status, sync API ghi đè dần nhãn cookie. Tài liệu này tách cột để 2 path ghi độc lập, reader ưu tiên cookie.

Owner
CTO
Bill ví dụ
6ET7ZP9N52
Bảng dữ liệu
ad_account_bills
Row cookie cũ
~7,354 row

1. Thông Tin Chung

Metadata cơ bản, scope của RFC.

Mã tính năng (Feature ID)FT-BILL-FUNDED-STATUS-01
Người yêu cầu (Owner / PO)CTO
Độ ưu tiênP1 · High — sai trạng thái tài chính hiển thị cho người dùng + làm hỏng tính năng rủi ro Funded bills on starred.
Trạng tháiDraft
Ngày tạo03/06/2026
Ngày cập nhật cuối03/06/2026
Hệ thốngDashboard thuê TKQC — module workspaces / billing / risk. Bảng chính: ad_account_bills.
Quy môTách trạng thái crawl về thành 2 cột riêng (API FB / cookie), 2 path ghi độc lập, reader ưu tiên cột cookie. Kèm migration tách dữ liệu cột cũ.

2. Bối Cảnh & Mục Tiêu

Hai nguồn FB cho ra 2 bộ status khác nhau, vì sao nhãn cookie đang bị xoá dần.

2.1. Bối cảnh (Context)

Bill thanh toán bằng credit / quỹ trả trước được Facebook gắn nhãn "Funded", nhưng hệ thống đang hiển thị "Thành công" (Paid). Ví dụ: bill 6ET7ZP9N52 (TKQC 1683821496292014) — billing_hub hiển thị Funded, DB lưu payment_status='Paid'.

Nguyên nhân — 2 nguồn dữ liệu FB cho ra 2 bộ status khác nhau:

Hai nguồn crawl trả 2 bộ status khác nhau

Nguồn crawlTrả statusPhân biệt được Funded?
API FB (GET /act_{id}/transactions) COMPLETED / FAILED / PROCESSING Không — Funded vẫn = COMPLETED
Cookie (crawl billing_hub.php) Paid / Funded / Pending / Failed + nhãn tiếng Việt

Sync hiện tại chỉ dùng API FB, map COMPLETED → Paid / còn lại → Unpaid nên không bao giờ tạo ra Funded → re-sync vô ích vì input API không hề có thông tin Funded.

Tệ hơn — bom hẹn giờ DB hiện còn ~7.354 row nhãn từ crawl cookie cũ (gồm Funded 4 row, Đã thanh toán, Đang chờ, Pending, Không thành công, Failed) nằm lẫn cùng một cột payment_status với kết quả API. Mỗi lần sync API ghi đè chính cột đó → đang xoá dần nhãn cookie.

2.2. Mục tiêu (Objectives)

O1
Bill Funded hiển thị đúng "Funded" trên /dashboard/billing, /finance/bills, /admin/risk/funded-bills-on-starred.
O2
Khôi phục độ chính xác tính năng Funded bills on starred (đã announce ở changelog v3.62.0).
O3
2 nguồn crawl (API / cookie) không bao giờ ghi đè nhau → không mất dữ liệu.

3. Luồng Nghiệp Vụ & Sơ Đồ Hoạt Động

Actor và các edge cases khi triển khai.

3.1. Các đối tượng tham gia

Người dùng workspace
Bấm "Đồng bộ hóa đơn", xem trạng thái bill.
Super Admin
Soát trang Funded bills on starred (TKQC gắn sao có bill Funded = bất thường tài chính).
Sync API (writer 1) & Crawl cookie (writer 2)
Mỗi bên ghi 1 cột riêng — không bao giờ đụng cột của nhau.
Reader
Funded feature / dashboard billing / billing filter — đọc trạng thái ưu tiên cookie.

3.2. Xử lý các kịch bản lỗi (Edge cases)

Dev tự tư duy & bổ sung thêm khi triển khai.
EC-01 Cookie / token chết
TKQC 1683821496292014 đang disabled, token đã chết (test Graph API trực tiếp → fail). Crawl cookie phải dùng cookie + proxy của VIA còn quyền trên BM, không phụ thuộc token TKQC.
EC-02 billing_hub đổi cấu trúc HTML
Parser dễ vỡ → log lỗi rõ + cảnh báo về NolimitHub.
EC-03 Thống nhất nhãn
Hai cột cần map nhãn FB về chung 1 bộ canonical (tránh đẻ biến thể), nhưng giữ độc lập theo nguồn.
EC-04 Lệch timezone / tiền tệ
Khi đối chiếu 2 nguồn theo tracking_id.

4. Chi Tiết Yêu Cầu Chức Năng

User stories & business rules.

4.1. Danh sách chức năng (User Stories)

IDVai tròMuốnĐểƯu tiên
US-01 Người dùng workspace Bill trả bằng credit hiện đúng "Funded" Biết đúng bản chất giao dịch P1
US-02 Super Admin Trang Funded bills on starred đếm / liệt kê đúng Soát đúng rủi ro tài chính P1
US-03 Hệ thống Crawl API & cookie không ghi đè nhau Không mất dữ liệu khi sync P0

4.2. Quy tắc nghiệp vụ (Business Rules)

BR-01 Tách nguồn — tách cột

Trạng thái từ API FB và từ cookie lưu vào 2 cột riêng; mỗi path chỉ ghi cột của mình, không đụng cột còn lại.

BR-02 Reader ưu tiên cookie

Giá trị hiển thị = cột cookie nếu có, không thì rơi về cột API (cookie ?? api). Funded chỉ tồn tại ở cột cookie.

BR-03 Canonical chung

Hai cột dùng chung bộ giá trị (Paid, Unpaid, Funded, Pending, Failed + nhãn tiếng Việt tương ứng); không phát sinh biến thể mới.

5. Thiết Kế Kỹ Thuật Sơ Bộ

Database 2 cột, writer 2 path, reader ưu tiên cookie, tài liệu tham chiếu.

Path app/... nằm ở repo product (không phải repo tài liệu này); số dòng gần đúng, dev mở repo code đối chiếu.

5.1. Database — thêm 2 cột trạng thái

CộtTypeMục đích
payment_status_apitextKết quả map từ API FB (Paid / Unpaid).
payment_status_cookietextNhãn crawl từ billing_hub qua cookie (Funded / Paid / Pending / Failed / nhãn tiếng Việt).

Giá trị hiển thị = COALESCE(payment_status_cookie, payment_status_api). Gợi ý: tạo cột generated / view hoặc xử lý ở query để reader đọc 1 chỗ, ưu tiên cookie. (Dev tự chọn cách tối ưu.)

Migration cột payment_status cũ (idempotent)

  • Giá trị Paid / Unpaid (do API sinh) → đổ sang payment_status_api.
  • Các nhãn còn lại (Funded, Đã thanh toán, Đang chờ, Pending, Không thành công, Failed) là crawl cookie cũ → đổ sang payment_status_cookie.

5.2. Writer — 2 path ghi độc lập

Writer 1 Sync API

app/api/workspaces/[workspaceId]/ad-accounts/[adAccountId]/check-bill/route.ts, ≈ dòng 240–262: đổi để ghi vào payment_status_api, không đụng payment_status_cookie. → diệt luôn bug ghi đè.

Writer 2 Crawl cookie (billing_hub)

Mở https://business.facebook.com/billing_hub.php?asset_id=act_{id} bằng cookie + proxy của VIA còn quyền, parse HTML lấy nhãn theo tracking_id, ghi vào payment_status_cookie. (Nếu path này chưa có, dev dựng theo pattern các sync cookie khác — xem 5.4.)

Khoá row (dev xác minh): UPSERT đang dùng khoá transaction_id, còn billing_hub trả nhãn theo tracking_id → cần xác minh quan hệ tracking_idtransaction_id trên ad_account_bills để ghi nhãn cookie vào đúng row.

5.3. Reader — đọc ưu tiên cookie

Các điểm sau hiện query payment_status='Funded', đổi sang đọc giá trị ưu tiên (cookie-first):

Nơi đọcFile (trong repo product)
Funded bills aggregation & detailrisk/funded-bills-on-starred/route.ts (~90) & .../[adAccountId]/route.ts (~54)
Dashboard billing paneldashboard/billing/route.ts (~163)
Billing page filter trạng tháibilling/route.ts (~24–27)
UI page riskapp/(dashboard)/w/[workspaceId]/admin/risk/funded-bills-on-starred/page.tsx

5.4. Tài liệu tham chiếu (repo product)

Cookie / EAAB / EAAG cho crawl cookie: docs/FORAI/facebook-credential-architecture.md
Decrypt token + gọi Graph API trực tiếp (đã fail với TKQC token chết → cần cookie / proxy): docs/FORAI/debug-guide.md

6. Tiêu Chí Nghiệm Thu & Kịch Bản Kiểm Thử (UAT)

Acceptance criteria + test cases.

6.1. Tiêu chí nghiệm thu (Acceptance Criteria)

6.2. Kịch bản kiểm thử (Test Cases)

R
Reader ưu tiên cookie
TC-01
Row có cookie=Funded, api=Paid → reader hiển thị Funded.
TC-02
Row chỉ có api=Paid (chưa crawl cookie) → reader hiển thị Paid (fallback).
W
Writer độc lập
TC-03
Trước có cookie=Funded → chạy sync API → payment_status_cookie giữ nguyên, chỉ payment_status_api cập nhật.
TC-04
Crawl cookie TKQC chứa 6ET7ZP9N52payment_status_cookie='Funded' → trang Risk hiển thị đúng.
M
Migration
TC-05
Chạy migration 2 lần → kết quả không đổi (idempotent).
TC bổ sung: dev tự dựng test cho lệch timezone / tiền tệ, cookie chết, HTML billing_hub đổi cấu trúc.

7. Quy Trình Bàn Giao & Review (CTO Handover)

Các bước chốt & deploy.

  1. DecisionQuyết định cần chốt

    Bill 6ET7ZP9N52 — chờ crawl cookie hay update tay payment_status_cookie='Funded' để hiển thị đúng ngay.

  2. Bàn giaoTest Report + Demo + Approve

    Sau khi xong + UAT trên staging, dev chuẩn bị Test Report kèm bằng chứng (ảnh / video: 6ET7ZP9N52 hiện đúng Funded; demo sync API không làm mất nhãn cookie). Họp review trực tiếp với CTO duyệt cơ chế 2 cột + ưu tiên cookie + migration. Chỉ khi CTO Approve mới deploy Production.

End of document
FT-BILL-FUNDED-STATUS-01 · Draft · Last reviewed 2026-06-03 · Owner: CTO
Tách trạng thái crawl thành 2 cột riêng (API FB / cookie), 2 path ghi độc lập, reader ưu tiên cột cookie. Kèm migration tách dữ liệu cột cũ.