On this page
Câu hỏi khách hay hỏi: "Số Shopper Segments ở Báo cáo hiệu suất thương mại — tính từ đâu, mỗi sàn riêng hay gộp?"
Hai segment xuất hiện#
| Nhãn (router) | Nhãn hiển thị | Định nghĩa |
|---|---|---|
new |
Khách mới | Shopper có đơn hàng đầu tiên (đời) rơi vào khoảng ?from..?to của báo cáo |
current |
Khách quay lại | Shopper có đơn trong khoảng ?from..?to nhưng đơn đầu tiên đời họ là trước khoảng đó |
KPI = số shopper riêng biệt, không phải số đơn. Một shopper có 5 đơn trong kỳ chỉ tính 1.
SQL (rút gọn — apps/web/src/server/routers/reports.ts ~155)#
WITH shopper_firsts AS (
SELECT shopper_id, MIN(placed_at)::date AS first_day
FROM orders
WHERE org_id = $orgId AND shopper_id IS NOT NULL
AND platform = ANY($platforms) -- nếu FilterBar chọn sàn
AND status = ANY($statuses)
GROUP BY shopper_id
),
shopper_window AS (
SELECT DISTINCT shopper_id
FROM orders
WHERE org_id = $orgId AND shopper_id IS NOT NULL
AND placed_at BETWEEN $from AND $to
AND platform = ANY($platforms)
AND status = ANY($statuses)
)
SELECT
CASE WHEN sf.first_day BETWEEN $fromDate AND $toDate THEN 'new' ELSE 'current' END AS segment,
COUNT(*)::int AS shoppers
FROM shopper_window sw
JOIN shopper_firsts sf USING (shopper_id)
GROUP BY 1;
Mỗi sàn xử lý thế nào#
- FilterBar chọn 1 sàn (vd "Shopee") → kết quả phản ánh chỉ Shopee shoppers (đơn của họ ở Shopee). Một người mua cả TikTok và Shopee chỉ tính ở Shopee bucket.
- FilterBar chọn nhiều sàn / để trống → gộp tất cả sàn được chọn. KPI là số shopper riêng biệt cross-platform: một người mua ở Shopee + Lazada chỉ tính 1.
first_dayquyết định "new" vs "current" — tính trên toàn lịch sử org (không reset theo cửa sổ thời gian). Tức là một khách lần đầu mua ở TikTok tháng 1 và quay lại Shopee tháng 5, khi xem báo cáo Shopee tháng 5 họ làcurrent(vìfirst_daylà tháng 1 trên TikTok).- Hệ thống không đếm "khách mới của Shopee" tách biệt với "khách mới của Lazada" trong query này — đó là cross-platform identity. Nếu cần per-platform first-touch attribution, phải đổi
MIN(placed_at)trongshopper_firststhànhMIN(placed_at) WHERE platform=...— chưa có yêu cầu nên chưa làm.
shopper_id từ đâu ra#
CSV upload thường mask danh tính khách: TikTok cho "Buyer Username" (vd nga_267), Shopee cho "Người Mua", Lazada cho customerName + shippingPhone. Các giá trị này không phải PII gốc nhưng stable per shopper trên cùng sàn.
Worker promoter (apps/worker/src/promoters/orders.ts) hash chúng:
const identityKey = `${orgId}|${platform}|${primary}|${secondary}`;
const shopperIdHash = createHash('sha256').update(identityKey).digest('hex').slice(0, 64);
→ ghi vào orders.shopper_id (foreign key tới shoppers table). Cùng buyer-username Shopee → cùng shopper_id. Khác sàn → khác hash → xem là 2 shopper khác nhau ở mức backend, NHƯNG shopper_firsts ở SQL trên dùng MIN(placed_at) qua tất cả sàn, nên nếu cùng shopper_id lặp lại trên nhiều sàn (vd masked PII identical giữa nguồn) thì gộp.
Thực tế: mỗi sàn = identity space riêng biệt vì hash bao gồm platform. Cross-platform de-dup chỉ xảy ra khi worker derive ra cùng hash, hiện tại không có. Nếu khách hỏi "có biết X mua cả Shopee + Lazada không?" — trả lời: không, vì giới hạn mask của CSV (không có anchor cross-platform như email/phone hash chung).
Độ phủ dữ liệu#
- Đơn có
shopper_idmới vào segment KPI. Đơn anonymous (nguồn không chứa identity hint) vẫn đếm vào GMV/orders nhưng không vào segment KPI; tỷ lệ phủ tùy chất lượng nguồn của từng org.
Edge cases khách hay hỏi#
| Hỏi | Trả lời |
|---|---|
"Vì sao tổng new + current < số Đơn hàng?" |
Bucket là shopper, không phải đơn. 1 shopper có 5 đơn = 1 ở segment, 5 ở orders. |
| "Anonymous orders đi đâu?" | Không vào segment KPI (vì không có shopper_id). Vào tổng GMV/Orders bình thường. |
"Quay lại bao lâu thì là current?" |
Bất kỳ. Miễn first_day < ?from. Không có lookback cap. Nếu cần, đổi SQL thành first_day BETWEEN ?from - INTERVAL 'X days' AND ?from |
"Mỗi sàn new/current riêng có được không?" |
Hiện chưa, vì identity hash gồm platform. Cross-platform MIN(first_day) chỉ kích hoạt nếu hash trùng — hiếm. |
Code references#
- Query:
apps/web/src/server/routers/reports.ts:155 - Identity derivation:
apps/worker/src/promoters/orders.ts:383 - FE display:
apps/web/src/app/(dashboard)/reports/commerce-performance/_components/commerce-performance-report.tsx:129