Bỏ qua nội dung

Crawl listings từ nguồn ngoài (Muaban, Nhà Tốt, Batdongsan)

Feature URL
Module
crawler
Status
draft
Priority
P1
Platforms
fe · be
AC progress
0 / 25
Last reviewed
2026-05-29

Mục tiêu

Thu thập tin đăng BĐS từ 3 nguồn bên thứ ba (Muaban.net, Nhà Tốt, Batdongsan.com.vn), chuẩn hóa về một format chung để tái dùng đúng các endpoint hiện có POST /propertiesPOST /listings nhằm tạo property + listing chính thức trong V-Nexus. Sau khi crawl, dữ liệu được chuẩn hóa thành 4 nhóm: thông tin property, thông tin listing, thông tin contact, thông tin nguồn crawl. Pipeline: chống trùng listing theo source + source_id (đã có thì bỏ qua, không tạo property/contact, không gọi POST /listings); tái dùng property nếu khớp address + area_m2 + property_type_id, nếu chưa có thì gọi POST /properties; resolve liên hệ theo số điện thoại (tra/tạo phone_registries rồi tra/tạo contacts); rồi map sang CreateListingRequest và gọi POST /listings. Tin crawl đi chung luồng với tin tạo từ app — không dùng chế độ ingest, không bỏ qua validate user-facing; Backend tính trust_score, route tin trust_score < 80 vào Data Marketplace (public) và tin trust_score ≥ 80 vào kho lưu trữ Admin, đồng thời push realtime qua WebSocket như mọi listing thường. Các trường nguồn (source, source_id, source_url) lưu trực tiếp trên bảng listings; thông tin liên hệ lưu ở bảng contacts mới (tham chiếu qua listings.contact_id), còn số điện thoại liên hệ lưu ở phone_registriescontacts trỏ tới qua khóa ngoại phone_registry_id. Bỏ hoàn toàn bảng staging data_sources, chế độ ingest, và logic resolve user/owner theo số điện thoại (không resolve users; phone_registries chỉ là nơi lưu số điện thoại, không suy ra owner).

Phạm vi

Trong phạm vi (In scope):

  • Crawl tin đăng từ 3 nguồn: Muaban.net, Nhà Tốt, Batdongsan.com.vn; crawl chạy liên tục — xong lượt nào bắt đầu lượt kế tiếp ngay, không chờ interval cố định
  • Mỗi lượt crawl lấy tin trong time_windows = 2 phút lùi từ thời điểm hiện tại ([now − 2 phút, now])
  • Chuẩn hóa dữ liệu crawl thành 4 nhóm: property, listing, contact, thông tin nguồn — khớp với request của POST /propertiesPOST /listings
  • Chống trùng listing: trước khi xử lý, tra bảng listings theo cặp source + source_id; nếu đã tồn tại → bỏ qua tin đó (không tạo property, không tạo contact, không gọi POST /listings)
  • Loại tin thiếu số điện thoại: sau khi lấy chi tiết, nếu số điện thoại liên hệ null/rỗng/không hợp lệ → drop tin tại crawl, không tạo phone_registries/contact/property/listing
  • Tái dùng property: tra property theo address + area_m2 + property_type_id; khớp → dùng property_id hiện có; không khớp → gọi POST /properties rồi lấy property_id vừa tạo
  • Resolve liên hệ: tra/tạo bản ghi phone_registries theo số điện thoại, rồi tra/tạo contacts trỏ tới phone_registry_id đó; đã có → dùng contact_id hiện có
  • Tạo bảng contacts lưu thông tin liên hệ (một-nhiều với listings); thêm khóa ngoại contact_id vào listings; contacts có khóa ngoại phone_registry_idphone_registries (nơi lưu số điện thoại)
  • Lưu các trường nguồn (source, source_id, source_url) trực tiếp trên listings
  • Map dữ liệu sang CreateListingRequest (kèm property_id, contact_id, source, source_id, source_url) và gọi POST /listings — đi chung luồng tin app, validate đầy đủ, không ingest
  • Backend tính trust_score, route trust_score < 80 → Data Marketplace (public), trust_score ≥ 80 → kho lưu trữ Admin; push event WebSocket khi listing trong Data Marketplace mới / cập nhật / đổi trust_score
  • Frontend nhận event và phản ánh thay đổi listing trên giao diện

Ngoài phạm vi (Out of scope):

  • Crawl nguồn khác ngoài 3 website trên (phase sau)
  • Thiết kế chi tiết màn hình listing trên Frontend (feature FE riêng nếu cần)
  • Công thức/trọng số chính xác tính trust_score (Dev quyết ở repo BE)
  • Thuật toán/threshold normalization để match property khi resolve (Dev quyết ở repo BE)
  • Thiết kế schema DB chi tiết (kiểu cột, index), API contract kỹ thuật, lựa chọn tech stack crawler (thuộc repo source code)
  • Logic xử lý nội bộ của POST /propertiesPOST /listings (thuộc feature/endpoint tương ứng ở repo source)
  • Kiểm duyệt thủ công listing crawl trước khi publish
  • Giao diện admin xem kho lưu trữ Admin (feature admin riêng)
  • Resolve user/owner, tài khoản shadow, claim tài khoản — đã loại khỏi luồng crawl (số điện thoại lưu ở phone_registries nhưng không dùng để suy ra owner)

User Stories

  • hệ thống, tôi muốn crawl tin đăng từ Muaban.net, Nhà Tốt, Batdongsan.com.vn để có nguồn dữ liệu listing bên ngoài.
  • hệ thống, tôi muốn chuẩn hóa tin crawl thành property/listing/contact/nguồn để tái dùng đúng POST /propertiesPOST /listings hiện có, không cần endpoint riêng.
  • hệ thống, tôi muốn trước khi xử lý kiểm tra listings theo source + source_id; nếu đã có thì bỏ qua để không tạo trùng property/contact/listing.
  • hệ thống, tôi muốn tái dùng property đã tồn tại (theo address + area_m2 + property_type_id) hoặc tạo mới qua POST /properties để mỗi BĐS chỉ có một property.
  • hệ thống, tôi muốn lưu số điện thoại liên hệ ở phone_registries và gắn contacts tới đó qua phone_registry_id, gom các tin cùng số điện thoại về một contact, để quản lý liên hệ tập trung mà không định danh user.
  • Backend, tôi muốn nhận CreateListingRequest kèm property_id, contact_id, source, source_id, source_url và xử lý như một request tạo listing bình thường (validate đầy đủ).
  • Backend, tôi muốn tính trust_score rồi route tin trust_score < 80 vào Data Marketplace, tin trust_score ≥ 80 vào kho lưu trữ Admin — như mọi listing khác.
  • user trên Frontend, tôi muốn thấy listing mới hoặc cập nhật trong Data Marketplace ngay khi hệ thống xử lý xong, không cần refresh trang.
  • admin, tôi muốn tin có trust_score ≥ 80 tự động vào kho lưu trữ Admin để bảo vệ khỏi phân phối đại trà.

Luồng chức năng

sequenceDiagram
    participant Source as Nguồn ngoài<br/>(Muaban / Nhà Tốt / Batdongsan)
    participant Crawler as Crawler
    participant Normalizer as Normalizer
    participant BE as Backend
    participant DM as Data Marketplace
    participant AA as Kho lưu trữ Admin
    participant WS as WebSocket
    participant FE as Frontend

    loop Crawl liên tục (window now lùi 2 phút)
        Crawler->>Source: Liệt kê tin trong window
        Source-->>Crawler: Danh sách tin ứng viên
        Crawler->>Crawler: Tra listings theo source + source_id
        alt source + source_id đã tồn tại
            Crawler->>Crawler: Bỏ qua tin (không xử lý tiếp)
        else chưa tồn tại
            Crawler->>Source: Lấy chi tiết tin
            Source-->>Crawler: Dữ liệu gốc
            Crawler->>Normalizer: Payload thô theo nguồn
            Normalizer->>Normalizer: Chuẩn hóa thành property, listing, contact, nguồn
            alt số điện thoại trống hoặc không hợp lệ
                Normalizer->>Normalizer: Bỏ tin (không gửi Backend)
            else có số điện thoại hợp lệ
                Normalizer->>BE: Tra property theo address + area_m2 + property_type_id
                alt property đã tồn tại
                    BE-->>Normalizer: property_id hiện có
                else chưa tồn tại
                    Normalizer->>BE: POST /properties
                    BE-->>Normalizer: property_id mới tạo
                end
                Normalizer->>BE: Tra phone_registries theo số điện thoại
                alt số điện thoại đã có trong phone_registries
                    BE-->>Normalizer: phone_registry_id hiện có
                else chưa có
                    Normalizer->>BE: Tạo phone_registries lưu số điện thoại
                    BE-->>Normalizer: phone_registry_id mới tạo
                end
                Normalizer->>BE: Tra contact theo phone_registry_id
                alt contact đã tồn tại
                    BE-->>Normalizer: contact_id hiện có
                else chưa tồn tại
                    Normalizer->>BE: Tạo contact gắn phone_registry_id
                    BE-->>Normalizer: contact_id mới tạo
                end
                Normalizer->>BE: POST /listings (property_id, contact_id, source, source_id, source_url)
            end
        end
    end

    Note over BE: POST /listings (auth tài khoản broker tạo sẵn) xử lý như tin thường

    BE->>BE: Tạo listing gắn property_id + contact_id
    BE->>BE: Tính trust_score + bổ sung field hệ thống

    alt trust_score < 80
        BE->>DM: Lưu vào Data Marketplace (public)
        BE->>WS: LISTING_CREATED hoặc LISTING_UPDATED
        WS->>FE: Push realtime
        FE->>FE: Cập nhật listing trên UI
    else trust_score ≥ 80
        BE->>AA: Lưu vào kho lưu trữ Admin (admin-only)
        BE->>WS: Event nội bộ admin (Dev quyết)
    end

    alt trust_score thay đổi
        BE->>WS: LISTING_TRUST_SCORE_UPDATED
    end

Phân vai nghiệp vụ:

Vai tròTrách nhiệm
CrawlerCrawl liên tục từng nguồn; tra listings theo source + source_id trước khi xử lý, bỏ qua tin đã có; loại tin thiếu số điện thoại; xử lý lỗi kết nối/parse cơ bản
NormalizerChuẩn hóa dữ liệu thành 4 nhóm (property, listing, contact, nguồn); orchestrate: tra/tạo property qua POST /properties, tra/tạo phone_registries theo số điện thoại + tra/tạo contacts, map CreateListingRequest rồi gọi POST /listings
BackendCung cấp POST /properties, POST /listings, logic contact + phone_registries; validate đầy đủ như tin app; tính trust_score; route Data Marketplace / kho Admin; lưu DB + phát event
WebSocketĐẩy event realtime tới Frontend (public Data Marketplace) hoặc admin channel (kho Admin)
FrontendSubscribe event, cập nhật UI listing trong Data Marketplace

Acceptance Criteria

  • AC-1: Hệ thống crawl được tin đăng từ đủ 3 nguồn: Muaban.net, Nhà Tốt, Batdongsan.com.vn.
  • AC-2: Giá trị source chỉ nhận một trong: MUABAN, NHATOT, BATDONGSAN.
  • AC-3: Giá trị listing_types chỉ nhận: bán hoặc cho thuê.
  • AC-4: Sau crawl, dữ liệu được chuẩn hóa thành 4 nhóm — property, listing, contact, thông tin nguồn — khớp request của POST /propertiesPOST /listings.
  • AC-5: Trước khi xử lý một tin, hệ thống tra listings theo cặp source + source_id. Nếu đã tồn tại → bỏ qua: không tạo property, không tạo contact, không gọi POST /listings.
  • AC-6: Nếu source + source_id chưa tồn tại → tiếp tục xử lý property và contact.
  • AC-7: Tra property theo address + area_m2 + property_type_id. Khớp → dùng property_id hiện có (không tạo mới, không ghi đè). Không khớp → gọi POST /properties, lấy property_id vừa tạo.
  • AC-8: property_id (tái dùng hoặc mới tạo) được gắn vào CreateListingRequest.
  • AC-9: Tồn tại bảng contacts với tối thiểu các field: id, contact_name, phone_registry_id (FK → phone_registries.id), created_at, updated_at (có thể bổ sung status, source, note). Số điện thoại không lưu trên contacts mà ở phone_registries.
  • AC-10: contact_name và số điện thoại không lưu trực tiếp trên listings. contact_name lưu ở contacts; số điện thoại lưu ở phone_registries (contacts trỏ tới qua phone_registry_id). listings tham chiếu liên hệ qua contact_id.
  • AC-11: Quan hệ contactslistingsmột-nhiều: một contact có nhiều listings, một listing chỉ gắn một contact. Không tạo bảng trung gian listing_contacts.
  • AC-12: Resolve liên hệ theo số điện thoại: tra/tạo phone_registries theo số điện thoại, rồi tra/tạo contacts trỏ tới phone_registry_id. Đã có → dùng contact_id hiện có; chưa có → tạo mới. Nhiều tin cùng số điện thoại → cùng một phone_registry → cùng một contact.
  • AC-13: Tin thiếu số điện thoại hợp lệ bị loại tại crawl — không tạo phone_registries, không tạo contact, không tạo property, không gọi POST /listings.
  • AC-14: CreateListingRequest nhận được property_id, contact_id, source, source_id, source_url.
  • AC-15: Tin crawl được tạo qua POST /listings (đi chung luồng tin tạo từ app). Không dùng chế độ ingest; không bỏ qua validate user-facing — Backend xử lý như request tạo listing bình thường.
  • AC-16: source, source_id, source_url lưu trực tiếp trên listings, không qua bảng staging data_sources.
  • AC-17: Không đặt unique constraint (source, source_id) ở DB. Chống trùng chỉ dựa vào kiểm tra tại crawl (tra listings theo source + source_id trước khi xử lý — xem AC-5).
  • AC-18: Không resolve users/owner theo số điện thoại; phone_registries chỉ là nơi lưu số điện thoại mà contacts tham chiếu (qua phone_registry_id), không dùng để suy ra user sở hữu listing. contact_phone chỉ là số liên hệ, không phải căn cứ định danh user.
  • AC-19: Không còn bảng staging data_sources; các trường cần thiết từ nguồn map trực tiếp vào request POST /properties/POST /listings và lưu trên listings.
  • AC-20: Backend tính trust_score, trust_score_breakdown, trust_score_calculated_at; phía crawl không gán các field này.
  • AC-21: Tin trust_score < 80 auto-publish vào Data Marketplace (public) ngay sau khi Backend xử lý; tin trust_score ≥ 80 route vào kho lưu trữ Admin (admin-only), không publish public.
  • AC-22: Khi listing (trust_score < 80) mới được tạo → event LISTING_CREATED qua WebSocket public; khi cập nhật → LISTING_UPDATED; khi trust_score thay đổi → LISTING_TRUST_SCORE_UPDATED.
  • AC-23: Frontend nhận event WebSocket public và phản ánh thay đổi listing trên giao diện.
  • AC-24: Hai tin khác source + source_id nhưng resolve về cùng property_id → giữ listing riêng cho từng tin, cùng trỏ tới một property (không merge).
  • AC-25: Lỗi crawl một nguồn không làm dừng pipeline các nguồn còn lại; lỗi chuẩn hóa một bản ghi không fail cả batch (log kèm source, source_id).

Quy tắc nghiệp vụ

  • Mỗi tin từ nguồn ngoài định danh duy nhất bởi cặp source + source_id; source chỉ nhận MUABAN / NHATOT / BATDONGSAN.
  • Crawl liên tục: xong lượt nào bắt đầu lượt kế tiếp ngay (không chờ interval cố định). time_windows = [now − 2 phút, now] — chỉ lấy tin có thời điểm đăng/cập nhật tại nguồn trong khung này.
  • Chống trùng (tại crawl, lớp duy nhất): trước khi lấy chi tiết/xử lý, tra listings theo source + source_id; đã có → bỏ qua tin (không fetch tiếp, không tạo property/contact, không gọi POST /listings). Không đặt unique constraint (source, source_id) ở DB làm chốt cuối — chống trùng chỉ ở lớp crawl này.
  • Loại tin thiếu liên hệ: số điện thoại null/rỗng/không hợp lệ → drop tại crawl (tin không liên hệ được coi là rác).
  • Chuẩn hóa 4 nhóm: property, listing, contact, thông tin nguồn — map trực tiếp vào request POST /propertiesPOST /listings; không qua staging.
  • Tái dùng property: tra theo address + area_m2 + property_type_id. Khớp → dùng property_id hiện có, không tạo mới và không ghi đè. Không khớp → POST /properties → lấy property_id mới. Thuật toán normalization địa chỉ/threshold match do Dev quyết ở repo BE.
  • Số điện thoại lưu ở phone_registries: số điện thoại liên hệ không lưu trên contacts mà ở phone_registries; contacts có khóa ngoại phone_registry_idphone_registries.id. phone nên là khóa tra duy nhất trong phone_registries.
  • Resolve liên hệ theo số điện thoại: tra/tạo phone_registries theo số điện thoại → tra/tạo contacts theo phone_registry_id. Đã có → dùng lại; chưa có → tạo mới. Cùng số điện thoại ở nhiều tin → cùng một phone_registry → cùng một contact.
  • Quan hệ contact–listing là một-nhiều: khóa ngoại contact_id đặt trực tiếp trên listings; không tạo bảng trung gian listing_contacts. Một contact có nhiều listings, một listing gắn đúng một contact.
  • Contact chỉ để hiển thị/liên hệ: không dùng contact/số điện thoại để resolve users/owners; không xác định user sở hữu listing qua contact.
  • Không resolve user/owner theo số điện thoại: phone_registries được tái dùng làm nơi lưu số điện thoại (contacts trỏ tới qua phone_registry_id), không dùng để xác định user/owner của listing; không đi từ phone_registries.user_id để gán owner.
  • Tạo listing qua POST /listings (luồng thường): CreateListingRequest nhận property_id, contact_id, source, source_id, source_url. Validate đầy đủ như tin app; không ingest, không bỏ qua validate. Vì dùng chung validate user-facing, payload crawl phải đáp ứng ràng buộc của tin app (field bắt buộc, property_id hợp lệ, ảnh theo chuẩn hệ thống) — cách đáp ứng ràng buộc ảnh cho tin crawl (vd re-host) do Dev quyết.
  • Owner tin crawl = tài khoản broker tạo sẵn: POST /listings được gọi bằng một tài khoản broker (seed) đã tạo trước; owner của listing crawl là tài khoản broker này (gắn theo JWT như tin app). Vẫn không resolve user/owner theo SĐT — owner đến từ tài khoản broker, không suy ra từ phone_registries.
  • Trường nguồn trên listings: source (tên nguồn crawl), source_id (id gốc tin tại nguồn), source_url (link gốc tin).
  • Bỏ bảng data_sources: không lưu staging; thông tin nguồn → listings, thông tin liên hệ → contacts (listing tham chiếu qua listings.contact_id), số điện thoại → phone_registries.
  • Thứ tự pipeline: source + source_id (bỏ nếu đã có) → kiểm tra số điện thoại (bỏ nếu thiếu) → property (tái dùng/tạo) → phone_registries (tra/tạo theo số điện thoại) → contact (tra/tạo theo phone_registry_id) → POST /listings.
  • trust_score + routing (giữ — chạy trong luồng POST /listings thường): Backend tính trust_score; trust_score < 80 → Data Marketplace (public, auto-publish, không moderation thủ công); trust_score ≥ 80 → kho lưu trữ Admin (admin-only, không public). Phía crawl không gán trust_score.
  • 3 nguồn bắt buộc gồm Batdongsan (nguồn mới bổ sung) — backend phải chấp nhận source = BATDONGSAN đầy đủ như 2 nguồn còn lại; backend hiện mới nhận nhatot/muaban nên cần mở rộng (cách hiện thực do Dev quyết ở repo BE).
  • Đã có sự cho phép crawl từ 3 nguồn (Muaban.net, Nhà Tốt, Batdongsan.com.vn); vận hành phải tuân thủ điều khoản đã thỏa thuận.
  • Listings trong kho lưu trữ Admin không phát event công khai; event nội bộ admin do Dev quyết.
  • Thông tin liên hệ tuân thủ chính sách masking/permission hiện có của hệ thống (tham chiếu RBAC listing).

Dữ liệu & Trạng thái

Bảng contacts (mới) — lưu thông tin liên hệ, quan hệ một-nhiều với listings; số điện thoại nằm ở phone_registries:

FieldMô tảBắt buộc
idID contact
contact_nameTên người liên hệ✓ (tối thiểu)
phone_registry_idFK → phone_registries.id — nơi lưu số điện thoại liên hệ
statusTrạng thái contactoptional
sourceNguồn của contact (vd CRAWL)optional
noteGhi chúoptional
created_atThời điểm tạo
updated_atThời điểm cập nhật
  • contact_name = tên người liên hệ; số điện thoại không lưu trên contacts mà truy cập qua phone_registry_idphone_registries.phone.
  • Contact chỉ phục vụ hiển thị/liên lạc; không dùng để resolve users/owners.

Bảng phone_registries (tái dùng) — nơi lưu số điện thoại mà contacts tham chiếu:

FieldMô tả
idID bản ghi
phoneSố điện thoại liên hệ (khóa tra, nên unique)
user_id(cột hệ thống hiện có) không dùng để resolve owner trong luồng crawl
is_blocked / block_reason(cột hệ thống hiện có) tuỳ chính sách
created_at / updated_atThời điểm tạo / cập nhật
  • Trong luồng crawl, phone_registries chỉ đóng vai kho lưu số điện thoại; không đi từ phone_registries.user_id để xác định user/owner của listing.

Bảng listings — field bổ sung/liên quan luồng crawl (các field khác giữ như tin tạo từ app):

FieldMô tảAi điền
idID listingBackend
property_idFK → properties (tái dùng nếu khớp)Crawl resolve
contact_idFK → contacts.id (một-nhiều) — mớiCrawl resolve
title, description, priceNội dung tinCrawl
listing_typesbán / cho thuêCrawl
image_urlsDanh sách URL ảnhCrawl
statusTrạng thái listingBackend
sourceNguồn crawl: MUABAN / NHATOT / BATDONGSAN — mới (trên listings)Crawl
source_idID tin tại nguồn gốc — mớiCrawl
source_urlLink tin gốc — mớiCrawl
posted_atThời điểm đăng tại nguồnCrawl
scraped_atThời điểm crawl vềBackend/Crawl
trust_scoreĐiểm uy tín (0–100)Backend
trust_score_breakdownChi tiết thành phần điểmBackend
trust_score_calculated_atThời điểm tính trust_scoreBackend
published_atThời điểm publish Data Marketplace (chỉ trust_score < 80)Backend
created_at / updated_atThời điểm tạo / cập nhậtHệ thống
  • Không lưu contact_name / số điện thoại trên listings; liên hệ truy cập qua contact_idcontactsphone_registries.
  • Các field hệ thống khác của listing (counters, exclusive, expired_at, …) giữ như tin tạo từ app.

Property — resolve qua endpoint hiện có:

  • Match theo address + area_m2 + property_type_id: khớp → tái dùng property_id; không khớp → POST /properties.
  • Schema/payload đầy đủ của property thuộc endpoint POST /properties (feature properties) — requirement này chỉ dùng property_id trả về. Thuật toán normalization/threshold match do Dev quyết.

Quan hệ dữ liệu:

  • contacts.id 1 — N listings.contact_id (một contact, nhiều listings).
  • contacts.phone_registry_idphone_registries.id (số điện thoại lưu ở phone_registries; phone nên unique nên mỗi số ↔ một phone_registry ↔ một contact).
  • listings.property_idproperties.id (tái dùng nếu khớp address + area_m2 + property_type_id).
  • listings lưu source, source_id, source_url.

Đã loại khỏi luồng crawl: resolve user/owner theo số điện thoại (không resolve users), bảng staging data_sources. (phone_registries được tái dùng làm nơi lưu số điện thoại, không dùng resolve owner.)

Trạng thái listing (status):

  • Backend quản lý vòng đời listing (vd draft, published, archived, expired… — giá trị cụ thể do Dev quy ước ở repo source).
  • trust_score < 80 → public trong Data Marketplace (auto-publish, ghi published_at).
  • trust_score ≥ 80 → archived trong kho lưu trữ Admin, không ghi published_at public.

Event WebSocket:

EventKhi nào phátChannel
LISTING_CREATEDListing mới (trust_score < 80) trong Data MarketplacePublic
LISTING_UPDATEDListing (trust_score < 80) được cập nhậtPublic
LISTING_TRUST_SCORE_UPDATEDtrust_score thay đổi sau xử lý BackendPublic (nếu listing đang trong Data Marketplace)
Admin event (Dev quyết)Listing route vào kho lưu trữ Admin (trust_score ≥ 80)Admin-only

Trạng thái xử lý pipeline crawl:

  • normalized — đã chuẩn hóa 4 nhóm
  • skipped_duplicatesource + source_id đã có, bỏ qua
  • dropped_no_contact — thiếu số điện thoại, bỏ tin
  • submitted — đã gọi POST /listings
  • published_marketplacetrust_score < 80, vào Data Marketplace
  • admin_archivedtrust_score ≥ 80, vào kho lưu trữ Admin
  • failed — lỗi crawl hoặc chuẩn hóa

Liên quan

  • Phụ thuộc: Chưa có
  • Ảnh hưởng: broker-daily-listing-distribution — Data Marketplace (tin trust_score < 80) là pool cho Auto Distribution paid tier; routing trust_score ≥ 80 ảnh hưởng pool có sẵn cho broker. Lưu ý: số điện thoại tin crawl nay nằm ở phone_registries.phone, truy cập qua listings.contact_idcontacts.phone_registry_idphone_registries (không qua users/owner) — feature đó cần điều chỉnh cách lấy phone_full cho tin crawl theo đường này.