Báo cáo công việc tuần

Chic Data — Tổng kết tuần

Giai đoạn: 25/08 – 31/08/2026 (gồm phần việc rạng sáng 01/09) · Tổng hợp từ 12 commit chicdata_dashboard, 13 phiên làm việc Claude trên 3 repo, một đợt gọi thử toàn bộ 173 endpoint, và số liệu vận hành truy vấn trực tiếp từ DB chicstay, chicgo + API production ngày 01/09
Người thực hiện: jc-hello
Ngày lập: 01/09/2026
Phạm vi: ChicStay · ChicData + 1 dự án theo dõi vận hành

Tổng quan tuần

Hai tuần trước là dựng bộ máy đồng bộ rồi mở rộng độ phủ. Tuần này chia làm hai hướng rõ rệt: ChicStay có thêm một lớp dữ liệu mới hoàn toàn (review khách từ 5 sàn OTA), còn ChicData mở nền tảng ra ngoài (khoá master + tài liệu đủ 173 endpoint).

364
review OTA mới
173
endpoint có tài liệu +173
40
chỗ tài liệu sai đã sửa
265
/431 phòng nối nguồn +8

Sang tuần thứ năm — chicgo_data vẫn đứng im, và vẫn là con số 0. Enrich chết 32 ngày (lượt cuối 31/07), place mới dừng 23 ngày (09/08), không một lượt BD confirm nào trong cả tuần (lượt cuối 15/08). 37.232 place vẫn nằm chờ enrich. Chi tiết mục C3.

A. ChicStay — dữ liệu lưu trú

A1. Review OTA — lớp dữ liệu mới

Yêu cầu đầu tuần: gom review từ mọi sàn OTA về theo cơ sở, dùng tên + địa chỉ + toạ độ để xác định trùng và ghép. Đã viết xong bộ thu thập trong chicstay-data:

Thành phầnNội dung
Nguồn đã viếtBooking · Agoda · Trip.com · Google Maps · Go2Joy — 5 adapter riêng
Bộ ghép cơ sởreviews/match.py — ghép theo tên + địa chỉ + khoảng cách toạ độ, có match_confidence và match_method
Lưu trữMigration 0014_ota_reviews.sql — bảng ota_reviews + external_listings
Kiểm thửtests/test_reviews_match.py — 187 dòng cho riêng bộ ghép
Quy mô2.528 dòng trên 11 file

Traveloka bỏ qua có chủ ý — được đánh giá là quá khó so với giá trị mang lại, ghi lại để sau này khỏi làm lại từ đầu.

364
review đã gom · TB 4,18/5
24
/86 cơ sở có review
46
listing đã ghép chắc
125
listing chờ soi tay

Phân bố nguồn: Google Maps 129 · Go2Joy 128 · Booking 78 · Agoda 29. Trip.com viết xong adapter nhưng chưa có review nào về — cần kiểm lại lượt chạy. Còn 56 cơ sở chưa ghép được listing nào.

Hai điểm cần xử lý sớm.

1. Toàn bộ 2.528 dòng crawler đang nằm ngoài Git — 11 file chưa commit trong chicstay-data, gồm cả migration và bộ test. Cả tuần công sức hiện chỉ tồn tại trên một máy.

2. Chạy được đúng một lượt rồi dừng. App Fly chicstay-reviews có máy reviews-run-v5 tạo lúc 03:17 ngày 31/08, chạy tới 08:21 rồi stopped. Đúng khớp mốc last_crawled_at 08:15. Chưa có lịch chạy lại, nên số review sẽ đứng yên cho tới khi chạy tay lần nữa.

A2. Đưa review vào panel cơ sở cho BD sửa

Mở một cơ sở ở /chicstay → mục "Review khách". Chỉ hiện ở cấp cơ sở — review gắn với property_id chứ không gắn từng phòng.

BD sửa được mọi trường: tên người viết · ảnh đại diện · quốc gia · kiểu khách · nền tảng · điểm và thang · ngày viết · ngày ở · tên phòng · tiêu đề · nội dung · điểm cộng · điểm trừ · phản hồi chủ nhà · ảnh kèm. Cộng thêm review mới và xoá review tự nhập.

Bốn quyết định đáng ghi lại

A3. Đồng bộ lịch phòng

Cộng thời gian dọn phòng vào khoảng bận

Phòng vừa có khách ra không bán lại được ngay. Từ nay khoảng bận kéo dài thêm đúng số phút dọn của từng nhà, nên API cấp cho ChicStay không còn chào bán khe giờ mà thực tế đang dọn.

NhàThời gian dọn
Bum · Abri · Fish · Amoureux · A Là1 giờ
Homnaykhongngu30 phút

Tô riêng đuôi dọn phòng trên lịch

Trên trang đồng bộ, mỗi thanh bận trước đây liền một mạch — BD đọc ra là còn khách tới tận end_at, trong khi khách đã đi từ checkout_at và phòng chỉ đang chờ dọn, tức là tính nhầm khe trống. Nay đuôi dọn tô hổ phách kèm sọc ngược hướng với sọc chéo của "chủ khoá phòng", có chú giải trong bảng màu.

Onboard 2 home mới — La Sol và The Palette

Viết script nhập dữ liệu thẳng từ Google Sheet của team vào DB (sheet có sẵn cả thông tin home lẫn link sync phòng), rồi onboard 2 home ngày 27/08:

HomeCơ sởPhòngNguồn lịchTình trạng
La Sol Homestay
M0032
48 Hàng Vải, Hoàn Kiếm 4 — P102, P202, P302, P402 pms:gsheet Chạy tốt — đọc lịch mỗi phút, 15 khoảng bận
The Palette Homestay
M0033
35 Nguyễn Bỉnh Khiêm 4 — Dreamy, Playful, Refined, Thoughtful pms:gsheet qua OAuth Đứng 5 ngày — xem cảnh báo dưới

Cả 8 phòng đều ghép được với nguồn lịch ở trạng thái MATCHED, không phòng nào phải soi tay.

The Palette onboard xong nhưng lịch đứng im từ 27/08 — và dashboard vẫn báo "ổn".

Sheet của The Palette chỉ chia sẻ riêng cho ecom@chicmedia.vn nên khoá Google Sheets dùng chung không mở được. Đã viết đường đọc bằng OAuth của chính hòm thư đó và deploy ngày 28/08 — nhưng secret GOOGLE_OAUTH_JSON chưa bao giờ được đặt trên Fly. Kiểm fly secrets list -a chicstay-room-state: không có biến này.

Hệ quả đo được lúc 11:19 ngày 01/09: cả 4 phòng có fetched_at = 27/08 18:50, tức đứng 5 ngày, trong khi La Sol cùng loại nguồn đọc lúc 11:19 cùng ngày. Đáng lo hơn: sync_status của cả 4 phòng vẫn là SUCCEEDED, và phòng Dreamy vẫn đang báo "bận tới 02/09 06:00" — một kết luận dựng từ dữ liệu 5 ngày tuổi.

Đúng loại lỗi đã nêu ở báo cáo tuần trước: hệ thống báo ổn trong lúc nói sai. Sửa bằng một lệnh fly secrets set GOOGLE_OAUTH_JSON=…, nhưng cảnh báo "nguồn đứng" cũng cần bắt được ca này.

Hai việc nhỏ khác

A4. Độ phủ hiện tại

265
/431 phòng nối nguồn — 61%
7
loại hệ thống nguồn
169
phòng đang có khách
723
thay đổi lịch trong 24h

Phân bố: gsheet 74 · KiotViet 71 · ezCloud 42 · GoHost 41 · GAS 20 · Dayladau 13 · Fish 4. Còn 96 liên kết chờ soi tay và 11 phòng có ảnh chụp lịch đã cũ.

Kho dữ liệu ChicStay: 29 brand · 73 cơ sở · 359 phòng · 1.898 gói giá · 5.523 ảnh. 204/359 phòng đã qua QA.

B. ChicData — nền tảng & API

B1. Mở API cho bên thứ 3

Trước tuần này API chỉ nhận cookie phiên. Hệ thống ngoài muốn lấy dữ liệu thì phải giả lập đăng nhập rồi tự giữ cookie jar — không ai làm vậy được lâu dài.

curl -H "x-api-key: $CHICDATA_API_KEY" \
     "https://chicdata.fly.dev/api/places?category=cafe&page_size=20"

Không đăng nhập, không cookie, không refresh token.

Dùng lại quy ước đã có. App Fly anh em chicstay-room-state đã chạy khoá API từ trước: header x-api-key, env API_KEY cho khoá nội bộ và API_KEYS_JSON khai khoá riêng từng bên gọi. chicdata làm y hệt — bên tích hợp học một lần dùng được cả hai hệ thống.

BiếnÝ nghĩa
API_KEYKhoá của chính đội mình, log ghi tên internal
API_KEYS_JSONKhoá riêng từng bên: {"doi-tac-a":"…"} — log biết ai gọi, thu hồi được đúng một bên
API_KEY_READONLYtrue = chỉ GET/HEAD, mọi lệnh ghi trả 403

Không phải sửa dòng nào trong 173 handler. Middleware chạy trước domain-access và maintenance, khoá hợp lệ thì dựng sẵn một phiên super-admin — mọi guard phía sau đều thấy như đã đăng nhập. Không sinh cookie, không tốn crypto mỗi request.

EndpointKhông gửi khoáCó khoá
/api/chicstay/*, products, events, chiko, ecom, scholarships403200
/api/admin/users, commits, archive/places, stats/my-stats401200

Đo thật trên production sau khi deploy. Hành vi cũ của dashboard không đổi: không gửi header thì mọi thứ chạy y như trước.

B2. Tài liệu API — 173 endpoint, một file duy nhất

173
endpoint · 153 đường dẫn
84
schema dữ liệu
9.963
dòng tài liệu
7
miền dữ liệu · 7 database

Mỗi endpoint có: mô tả, mức quyền, bảng tham số đường dẫn, bảng tham số query, bảng body, bảng đầu ra trải phẳng tới từng trường lồng nhau với kiểu / bắt buộc / ràng buộc / mô tả, bảng mã lỗi, và ví dụ curl chạy được ngay. Kèm Swagger UI bấm thử tại chicdata.fly.dev/api-docs/.

Sinh tự động bằng pnpm docs:api. Mục 0–5 viết tay (kiến trúc, phân quyền, quy ước, bẫy nghiệp vụ từng miền), mục 6 tự sinh và chỉ ghi đè phần sau marker — chạy bao nhiêu lần cũng không đụng phần viết tay.

B3. Gọi thử từng endpoint bằng máy — 40 chỗ tài liệu tả sai

pnpm test:api đọc openapi.json, tự lấy id thật từ các endpoint danh sách rồi dùng cho endpoint chi tiết, gọi lần lượt cả 173 endpoint và so phản hồi thật với schema trong tài liệu.

An toàn: dev server nối thẳng vào database production, nên mọi lệnh ghi chỉ được gọi bằng id giả và body rỗng — chạm tới lớp kiểm tra đầu vào rồi dừng. Không bao giờ ghi hay xoá dữ liệu thật.

Bản đầu chỉ so khoá tầng ngoài nên để lọt cả một tầng: /api/chicstay/reviews/listings có vỏ {rows, total} đúng nhưng mọi tên cột bên trong rows[] đều sai. Vá lại để soi cả phần tử mảng — lòi thêm 28 chỗ nữa.

ChỗTài liệu ghiThật ra là
Điểm bản đồ ChicStaylat / lnglatitude / longitude
Từ khoá Ecomidkeyword_id
Listing OTAlisting_id, platformexternal_listing_id, source_platform
Thống kê categoryverified, pending4 cột *_count
Lượt scrape sự kiệnfound, insertedevents_scraped, events_new
/api/stats/by-provincemảngobject {provinces, unknown, total}

Một chỗ đáng nói riêng: trạng thái phòng. Tài liệu hứa có cột state trong phản hồi /api/chicstay/room-state. Thật ra API không hề trả cột đó — busy/free/unknown/unmapped được suy ở phía client từ busy_until + fetched_at + sync_status. Bên thứ 3 code theo tài liệu cũ sẽ đọc undefined mà không hiểu vì sao. Đây đúng là endpoint ChicStay gọi sang nhiều nhất.

B4. Dọn hạ tầng — Railway đã tắt hẳn

Chốt lại việc chuyển từ tuần trước: chicdata, chicdata-metabase và chicstay-room-state nay chạy trên Fly, service Railway đã xoá sau khi đối chiếu ba nguồn độc lập từng phòng (Fly ↔ Railway ↔ PMS). Dọn thêm hai service chết còn giữ 21 biến mỗi cái (citycrawl dừng từ 27/07, chicgo-enrich-local dừng từ 29/07) và llm_call.

C. Rủi ro đang mở — cần đội quyết

C1. Một endpoint công khai có thể làm sập production

/api/stats/provinces gọi loadProvinceIndex(), hàm này chạy SELECT … FROM public.places không LIMIT, kéo cả 61.448 dòng kèm hai cột jsonb vào RAM. Máy Fly 1 GB không chịu nổi nên bị giết giữa chừng — quan sát được máy restart hai lần trong đợt gọi thử.

Endpoint này không yêu cầu đăng nhập. Bất kỳ ai trên internet gọi nó lúc cache nguội (TTL 120 giây) đều có thể làm production restart. Cùng hàm đó còn phục vụ by-province, by-category, rating-distribution, enrich-progress, reviews-timeline.

C2. Ba endpoint đang lỗi + CI đỏ liên tục

Vấn đềNguyên nhân
/api/places/{id}/verify-lock — 500 cả 3 methodBảng place_verify_locks không tồn tại — chỉ có ở migration legacy/008 chưa từng chạy. Kéo theo tính năng khoá verify của BD đang chết.
/api/stats/bd-performance — 500(bd_data->>'bd_score')::int gặp giá trị float "82.0". Có ở 8 chỗ trong handler.
DELETE /api/settings/ce-environments/{id} — 500 thay vì 400Không kiểm id có phải số trước khi đưa vào SQL.
CI đỏ 100/100 lầnKhông một lần xanh trong 100 lượt gần nhất, sớm nhất lấy được là 04/08 — đỏ liên tục gần một tháng. Hỏng ở bước Lint: 2.558 lỗi, trong đó 2.339 tự sửa được bằng --fix. CI không chặn deploy nên mọi commit vẫn lên production bình thường.

C3. chicgo_data — tuần thứ năm đứng im

Chỉ sốLượt cuốiĐứng bao lâu
Enrich place31/07/2026 04:3032 ngày
Enrich Perplexity31/07/202632 ngày
Place mới về09/08/202623 ngày
BD confirm15/08/2026 06:0317 ngày

Biểu đồ enrich 14 ngày gần nhất: 0 mỗi ngày, không sót ngày nào. Trong tuần có 0 lượt BD confirm và 0 place mới. Kho: 61.448 place, 23.891 đã enrich (39%), 37.232 đang chờ, 19.929 đã BD confirm.

Con số không nhúc nhích so với báo cáo tuần trước. Đây là tuần thứ năm liên tiếp — nếu là dừng có chủ ý thì nên ghi rõ để thôi theo dõi; nếu không thì cần người nhận việc khởi động lại.

C4. 27 endpoint đang mở công khai

Đo thật: /api/places?category=cafe&page_size=20 trả 984 KB dữ liệu thật — tên, địa chỉ, toạ độ, ảnh, điểm, social — không cần khoá, không cần đăng nhập. Cùng nhóm còn /api/stats/overview, /api/categories, /api/tags, /api/provinces, /api/progress/daily, /api/stats/top-places. routeRules lại bật CORS cho toàn bộ /api/**. Hành vi có sẵn từ trước, không phải do lớp khoá sinh ra.

Việc tuần tới