Tính năng nghiên cứu đối thủ cạnh tranh
Tổng quan
| Mục | Nội dung |
|---|---|
| Trạng thái | 🔵 Đề xuất |
| Issue | - |
| Phụ trách | - |
Tính năng tổng hợp danh sách các cửa hàng đối thủ xuất hiện cùng cửa hàng của khách hàng theo từ khóa × địa điểm đo, cung cấp biểu đồ biến động xếp hạng của từng đối thủ, còn thông tin chi tiết GBP được hiển thị qua nhúng Google Maps. Chỉ sử dụng tầng IDs Only (miễn phí) của Places API, không lưu trữ và không hiển thị trực tiếp dữ liệu GBP của đối thủ trên giao diện của hệ thống — toàn bộ phần hiển thị chi tiết giao cho Google vẽ trực tiếp. Nhờ vậy duy trì chi phí API thêm $0 và tuân thủ tuyệt đối Điều khoản dịch vụ của Google Maps Platform.
| Mục | Nội dung |
|---|---|
| Phương thức đo | Lưu toàn bộ place_id trong phản hồi Places API (New) Text Search hiện có |
| Dữ liệu tự lưu trữ | Xếp hạng / biến động xếp hạng / phát hiện đối thủ mới và đối thủ rời top |
| Thông tin GBP của đối thủ | Chỉ thông qua iframe Google Maps Embed (tên, đánh giá, số review, ảnh, giờ mở cửa) |
| Phạm vi | MAPPY (tiên phong) → GCOR / PIPIT tiếp theo |
| Chi phí API | $0 (duy trì SKU IDs Only, Maps Embed API miễn phí không giới hạn) |
Nội dung đề xuất
Bối cảnh và vấn đề
- Khách hàng đưa ra yêu cầu: "Cần tính năng nghiên cứu đối thủ. Có thể tìm kiếm và xem được thông tin GBP cùng thứ hạng của các cửa hàng đó"
- Tính năng xếp hạng hiện tại chỉ xử lý xếp hạng của cửa hàng của khách, các cửa hàng đối thủ xuất hiện song song trong kết quả tìm kiếm bị bỏ qua
- Phản hồi của Places API (New) đã chứa tới 60 place_id ở vị trí cao nhất — đã có sẵn trong implementation hiện tại nhưng chưa được tận dụng
- Trong giai đoạn chuyển đổi từ scraping sang Places API, "duy trì chi phí API ở mức IDs Only ($0)" là điều đã thống nhất với khách hàng
- Theo Điều khoản dịch vụ Google, tên, đánh giá, số review, giờ mở cửa của đối thủ không được lưu cache hoặc hiển thị trực tiếp trên giao diện của hệ thống bên thứ ba (chỉ place_id được lưu vô thời hạn, vĩ độ/kinh độ tối đa 30 ngày)
- → Bằng cách giao toàn bộ phần hiển thị chi tiết cho Google Maps Embed, có thể đồng thời đáp ứng yêu cầu khách hàng, tuân thủ điều khoản, và không phát sinh chi phí
Giải pháp đề xuất
Lấy toàn bộ place_id từ phản hồi của Places API Text Search hiện có, lưu cùng với xếp hạng. Trên màn hình, truyền place_id vào iframe Google Maps Embed để Google trực tiếp vẽ tên, đánh giá, review, ảnh, giờ mở cửa và chỉ đường ngay trong giao diện chính thức của họ. Hệ thống chỉ lưu dữ liệu xếp hạng.
Đặc điểm chính:
- Duy trì chi phí API $0: FieldMask vẫn chỉ là
places.id, không phát sinh request mới - Tuân thủ điều khoản hoàn toàn: Chỉ lưu place_id (được phép vô thời hạn) và xếp hạng. Tên, đánh giá không được giữ trong hệ thống
- Biến động xếp hạng của đối thủ có thể cung cấp hoàn chỉnh bằng dữ liệu tự thu thập (dùng lại thiết kế bảng giống xếp hạng cửa hàng của khách)
- Phát hiện đối thủ mới và đối thủ rời top: Tự động phát hiện "đối thủ mới xuất hiện trong tháng" và "đối thủ rời khỏi top" qua phép so sánh tập hợp place_id theo ngày
- Xem chi tiết qua iframe Maps Embed (miễn phí không giới hạn) hoặc link ngoài định dạng
https://www.google.com/maps/place/?q=place_id:XXX
Danh sách tính năng
| # | Tên tính năng | Mô tả | Ưu tiên |
|---|---|---|---|
| 1 | Lưu place_id của đối thủ | Lưu tất cả place_id trong phản hồi Places API cùng với xếp hạng | Cao |
| 2 | Hiển thị danh sách đối thủ | Hiển thị N cửa hàng top theo từ khóa × ngày, làm nổi bật cửa hàng của khách | Cao |
| 3 | Biểu đồ biến động xếp hạng | So sánh xếp hạng theo thời gian giữa cửa hàng của khách và 1〜5 đối thủ tùy chọn | Cao |
| 4 | Preview Maps Embed | Mở modal Google Maps iframe khi click vào dòng đối thủ | Cao |
| 5 | Link ngoài Google Maps | Nút "Xem trên Google Maps↗" mở tab mới | Cao |
| 6 | Phát hiện đối thủ mới | Đánh dấu NEW cho place_id chưa từng xuất hiện trong top N ngày qua | Trung |
| 7 | Phát hiện đối thủ rời top | Đánh dấu các place_id từng ở top trong N ngày qua nhưng nay không còn | Trung |
| 8 | Thống kê tần suất xuất hiện | Đếm số từ khóa mà một đối thủ (place_id) xuất hiện ở top | Trung |
| 9 | Chuyển đổi nhóm xếp hạng | Biến động hàng tháng giữa các nhóm xếp hạng (1〜3 / 4〜10 / 11〜20 / Ngoài top) | Thấp |
| 10 | Xuất CSV (chỉ xếp hạng) | Xuất CSV chỉ chứa place_id + xếp hạng (không có tên, đánh giá) | Thấp |
Các vấn đề thiết kế
Có thể làm và không thể làm (tiền đề quan trọng)
| Thông tin | Lưu vào DB nội bộ | Hiển thị trên UI của hệ thống (text/số) | Hiển thị trong Maps Embed |
|---|---|---|---|
| place_id | ✅ Vô thời hạn | ✅ Khóa nội bộ | — |
| Xếp hạng (cửa hàng khách & đối thủ) | ✅ | ✅ Cho phép số liệu và biểu đồ | — |
| Tên cửa hàng đối thủ | ❌ Vi phạm điều khoản | ❌ | ✅ Google vẽ |
| Địa chỉ đối thủ | ❌ | ❌ | ✅ |
| Đánh giá đối thủ (★) | ❌ | ❌ | ✅ |
| Số review của đối thủ | ❌ | ❌ | ✅ |
| Giờ mở cửa của đối thủ | ❌ | ❌ | ✅ |
| Ảnh của đối thủ | ❌ | ❌ | ✅ |
| Insight của đối thủ (PV/cuộc gọi v.v.) | ❌ | ❌ | ❌ (chỉ chủ GBP) |
Những điều không thể làm theo điều khoản
- Hiển thị tên, đánh giá, số review của đối thủ trong bảng trên UI hệ thống
- Biểu đồ biến động đánh giá / số review của đối thủ
- Tải ảnh của đối thủ về server của hệ thống
- Xuất CSV chứa tên, đánh giá của đối thủ
Những điều trên vi phạm điều khoản "Không được lưu hoặc cache nội dung Places ngoài place_id" của Google Maps Platform Terms of Service. Nếu thực hiện sẽ có rủi ro bị thu hồi quyền truy cập API.
Lý do lựa chọn thiết kế
| Phương án | Chi phí thêm hàng tháng | Đánh giá | Quyết định |
|---|---|---|---|
| Phương án này (IDs Only + Maps Embed) | $0 | Tuân thủ điều khoản, chi phí 0, đáp ứng phần lõi yêu cầu của khách hàng | Chọn |
| Sử dụng Pro tier (hiển thị tên, địa chỉ) | $30〜$100/tháng | Vẫn không được cache nên phải fetch mỗi lần, UX cải thiện không nhiều | Không chọn |
| Enterprise tier (hiển thị đánh giá, review) | $100〜$500/tháng | Không được lưu DB nên không vẽ được biểu đồ biến động, chi phí không tương xứng | Không chọn |
| Google Business Profile API | — | Lấy dữ liệu đối thủ bị cấm rõ ràng (lead generation / competitive analysis) | Không chọn |
| Scraping Google Search | (chi phí ẩn lớn) | Vi phạm điều khoản, reCAPTCHA, không ổn định | Không chọn |
Đề xuất mở rộng schema DB
Mở rộng từ mappy_place_search_rankings hiện có để cũng lưu các dòng đối thủ ngoài cửa hàng của khách:
-- Snapshot đối thủ (lưu N place_id top ngoài cửa hàng của khách)
CREATE TABLE mappy_competitor_snapshots (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
gbp_location_id BIGINT NOT NULL, -- Location của cửa hàng khách (chủ thể quan sát)
keyword_id BIGINT NOT NULL,
competitor_place_id VARCHAR(255) NOT NULL, -- place_id của đối thủ (được lưu vô thời hạn)
ranking SMALLINT NOT NULL, -- 1〜60 / 0=Ngoài top (về lý thuyết dòng đối thủ chỉ có 1〜60)
ranking_at DATE NOT NULL,
search_at DATETIME NOT NULL,
source VARCHAR(20) DEFAULT 'places_api',
system_id INT NOT NULL,
created_at DATETIME,
INDEX idx_loc_kw_date (gbp_location_id, keyword_id, ranking_at),
INDEX idx_place (competitor_place_id, ranking_at)
);- Dòng của cửa hàng khách vẫn dùng
mappy_place_search_rankingshiện có (không lưu trùng lặp) - Lý do tách bảng đối thủ: Số dòng phình lên xấp xỉ N lần (tối đa 60 lần), cần tách index
- Thời gian lưu: 13 tháng (khoảng ngắn nhất cho phép so sánh với cùng kỳ năm trước)
- Khoảng 200 B/rec × N từ khóa × 30〜60 dòng/ngày × 13 tháng → quy mô khách hàng 100 công ty thì khoảng 5〜10 GB
Cách dùng Maps Embed API
<!-- Trong modal chi tiết đối thủ -->
<iframe
src="https://www.google.com/maps/embed/v1/place?key={EMBED_KEY}&q=place_id:ChIJ..."
width="100%" height="450" loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
allowfullscreen>
</iframe>| Mục | Đặc điểm |
|---|---|
| Loại API | Maps Embed API (SKU riêng biệt với Places API) |
| Giá | Hoàn toàn miễn phí, không giới hạn |
| Key cần có | Key dành cho Maps Embed (khác với key Places API. Phát hành 1 key dùng chung toàn công ty là đủ) |
| Cách quản lý | Có thể nhúng key vào frontend (cấu hình giới hạn HTTP referrer) |
| Nội dung hiển thị | Tên cửa hàng, danh mục, đánh giá, số review, ảnh, giờ mở cửa, nút chỉ đường |
Cấu trúc chi phí (ước tính hàng tháng)
| Mục | Ước tính |
|---|---|
| Số request Places API thêm | 0 (chỉ trích xuất place_id từ phản hồi đã có) |
| Tăng chi phí Places API | $0 |
| Sử dụng Maps Embed API | Hoàn toàn miễn phí, không giới hạn |
| Tăng dung lượng RDS AWS (lưu 13 tháng) | Khoảng +$0.5〜$1.0/tháng |
| Tăng phí truyền dữ liệu AWS | Rất nhỏ |
| Tổng chi phí thêm hàng tháng | Khoảng ¥100〜200/tháng (gần như bằng 0) |
Điểm trình bày với khách hàng
- Chi phí API duy trì hoàn toàn $0 (tiếp tục chính sách IDs Only hiện tại)
- Đáp ứng yêu cầu khách hàng dưới dạng "Thông tin chi tiết của đối thủ có thể xem trực tiếp trên Google Maps"
- Cung cấp giá trị độc đáo của nền tảng như biến động xếp hạng, phát hiện đối thủ mới
- Không cần chuyển chi phí lên khách hàng (có thể cung cấp như giá trị gia tăng trong gói hiện tại)
- Vì là thiết kế tuân thủ điều khoản, đảm bảo ưu thế pháp lý mà các đối thủ trong ngành MEO khó vượt qua
Liên hệ với các dự án và implementation hiện có
- Là mở rộng phía sử dụng phản hồi của Lấy ranking qua Places API. Không thêm request
- Khi kết hợp với dự án #11 Đo lường đa địa điểm (Geo-Grid), có thể tạo ra danh sách đối thủ theo từng điểm đo (khả năng mở rộng)
- Dự án #7 Phân tích & so sánh xếp hạng theo nhóm hiện có là so sánh giữa các cửa hàng của khách trong nhóm, còn dự án này là so sánh với đối thủ bên ngoài nhóm. Mối quan hệ bổ sung chức năng
Mockup màn hình
競合店舗調査
| 順位 | 店舗 | 前月比 | 推移 | 詳細 |
|---|---|---|---|---|
| 1 | place_id: ChIJAbcDefGh… | — | ━━━━━ | |
| 2 | place_id: ChIJXyzPqrSt… | +1 | ╲━━━╱ | |
| 3 | ★ サンプル美容室 渋谷店(自店) | -2 | ╲╲━━━ | — |
| 4 | place_id: ChIJNew00011…NEW | NEW | ----╱ | |
| 5 | place_id: ChIJEfgHijKl… | — | ━━━━━ | |
| 6 | place_id: ChIJDrop0001…↓圏外へ | +4 | ╲╲╲╲━ | |
| 7 | place_id: ChIJNopQrsTu… | -1 | ╱━━━━ | |
| 8 | place_id: ChIJWxyZab00… | +2 | ━━╲━━ | |
| 9 | place_id: ChIJCdeFghIj… | — | ━━━━━ | |
| 10 | place_id: ChIJLmnOpqRs… | +1 | ━╲━━━ |
クリックすると Google マップ Embed が開き、店名・評価・口コミ・写真・営業時間などが Google から直接表示されます。
Giới hạn hiển thị theo thiết kế
"Cửa hàng A", "Cửa hàng B" v.v. trong mockup này là giá trị placeholder, trên môi trường production chỉ hiển thị place_id. Tên, đánh giá, số review thực tế sẽ được Google trực tiếp vẽ trong iframe Google Maps Embed bên trong modal (không xuất hiện trong UI của hệ thống).
Cấu trúc màn hình
| Vùng | Nội dung |
|---|---|
| Header | Chọn từ khóa / chọn ngày / chuyển tab "Biến động xếp hạng" và "Danh sách đối thủ" |
| Bảng danh sách đối thủ | Xếp hạng / place_id (hiển thị che bớt) / nút Xem trên Google Maps / biểu đồ nhỏ biến động / nhãn NEW・rời top |
| Highlight dòng cửa hàng khách | Chỉ dòng của cửa hàng khách mới hiển thị tên + màu nhấn |
| Biểu đồ biến động xếp hạng | So sánh xếp hạng theo thời gian giữa cửa hàng của khách và các đối thủ đã chọn (tối đa 5) bằng đường gấp khúc |
| Modal Maps Embed | Mở khi click vào dòng đối thủ. Google trực tiếp vẽ tên, đánh giá, ảnh v.v. trong iframe Google Maps |
| Nhãn NEW・rời top | Các nhãn "NEW", "Rời khỏi top↓" |
| Xuất | Tải CSV chỉ có xếp hạng + place_id (không bao gồm tên v.v.) |
Công ước tính (Tiền đề có AI)
Nhân sự
| Vai trò | Số người | Nội dung phụ trách |
|---|---|---|
| Người thiết kế | 1 | Xác nhận yêu cầu → chỉ đạo AI tạo tài liệu thiết kế → review → chỉ đạo bộ phận sản xuất |
| Người sản xuất | 1 | Chỉ đạo AI tạo dựa trên ISSUE → code review → thực hiện test → deploy |
Chi tiết công
| # | Hạng mục | Số lần AI làm lại | Review | Công (người-ngày) | Phụ trách |
|---|---|---|---|---|---|
| 1 | Xác nhận yêu cầu, tài liệu thiết kế (gồm thiết kế tuân thủ điều khoản) | 2 lần | 0.5 ngày/lần | 1.0 | Người thiết kế |
| 2 | Thiết kế DB schema và migration | 1 lần | 0.5 ngày/lần | 0.5 | Người thiết kế |
| 3 | Thực thi DB migration | 1 lần | 0.5 ngày/lần | 0.5 | Người sản xuất |
| 4 | Phía places_api: thêm logic lưu toàn bộ place_id | 1 lần | 0.5 ngày/lần | 0.5 | Người sản xuất |
| 5 | Phía mappy: triển khai CompetitorService (API lấy danh sách) | 2 lần | 0.5 ngày/lần | 1.0 | Người sản xuất |
| 6 | Phía mappy: API lấy biến động xếp hạng | 1 lần | 0.5 ngày/lần | 0.5 | Người sản xuất |
| 7 | Phía mappy: logic phát hiện đối thủ mới và đối thủ rời top | 2 lần | 0.5 ngày/lần | 1.0 | Người sản xuất |
| 8 | Frontend: màn hình danh sách đối thủ + modal Maps Embed | 2 lần | 0.5 ngày/lần | 1.5 | Người sản xuất |
| 9 | Frontend: biểu đồ biến động xếp hạng (chart.js / tái sử dụng có sẵn) | 1 lần | 0.5 ngày/lần | 1.0 | Người sản xuất |
| 10 | Phát hành key Maps Embed, cấu hình giới hạn referrer | 1 lần | 0.5 ngày/lần | 0.5 | Người sản xuất |
| 11 | Xuất CSV (chỉ place_id + xếp hạng) | 1 lần | 0.5 ngày/lần | 0.5 | Người sản xuất |
| 12 | Test tích hợp, đối chiếu checklist tuân thủ điều khoản | 1 lần | 0.5 ngày/lần | 1.0 | Người sản xuất |
| 13 | Deploy, kiểm tra hoạt động | 1 lần | 0.5 ngày/lần | 0.5 | Người sản xuất |
Tổng: 9.5 người-ngày
Tiền đề và ràng buộc
- Chi phí API duy trì Places API IDs Only ($0). Mở rộng Field Mask nằm ngoài phạm vi dự án này
- Nếu khách hàng yêu cầu hiển thị tên, đánh giá, số review của đối thủ trực tiếp trên UI của hệ thống, khuyến nghị giải thích ràng buộc trong Google Maps Platform Terms of Service và tách thành dự án riêng để xem xét tính phí Pro/Enterprise tier
- Nội dung hiển thị trong iframe Maps Embed (tên, đánh giá v.v.) phụ thuộc vào thông số kỹ thuật của Google. Khi Google thay đổi UI có thể thay đổi nội dung hiển thị (nằm ngoài tầm kiểm soát của hệ thống)
- Đối tượng lưu chỉ là place_id + xếp hạng. Vĩ độ/kinh độ có giới hạn 30 ngày theo điều khoản nên không lưu
- Vì thiết kế sử dụng phản hồi của request Places API hiện có, không phát sinh request API mới chỉ vì tính năng này
Các điểm cần xác nhận với khách hàng
- Giới hạn số đối thủ lưu: Top 10 / 20 / toàn bộ 60 — lưu đến mức nào
- Thời gian lưu: 13 tháng (so sánh cùng kỳ năm trước) / 24 tháng (biến động 2 năm) / 6 tháng (vận hành nhẹ)
- Tần suất đo: Có dùng tần suất hàng ngày giống với đo cửa hàng khách hiện tại không
- Cách hiển thị chi tiết đối thủ: iframe Maps Embed trong modal / chỉ link ngoài Google Maps / cả hai
- Quyền truy cập: Mở cho toàn bộ tài khoản / tùy chọn chỉ cho gói cao cấp / khởi đầu thí điểm với một số khách hàng
- Đối ứng yêu cầu "muốn xếp tên cửa hàng trong bảng": Cho phép tiến tới tính phí Pro tier (tháng $30〜$100) hoặc kết thúc bằng phương án miễn phí
Lịch trình
| タスク | 担当 | 日数 | 6/15 | 6/16 | 6/17 | 6/18 | 6/19 | 6/20 | 6/21 | 6/22 | 6/23 | 6/24 | 6/25 | 6/26 | 6/27 | 6/28 | 6/29 | 6/30 | 7/1 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 月 | 火 | 水 | 木 | 金 | 土 | 日 | 月 | 火 | 水 | 木 | 金 | 土 | 日 | 月 | 火 | 水 | |||
| Xác nhận yêu cầu, thiết kế | Thiết kế | 1d | |||||||||||||||||
| Thiết kế DB schema | Thiết kế | 1d | |||||||||||||||||
| DB migration | Thực thi | 1d | |||||||||||||||||
| Logic lưu place_id | Thực thi | 1d | |||||||||||||||||
| CompetitorService | Thực thi | 1d | |||||||||||||||||
| API biến động | Thực thi | 1d | |||||||||||||||||
| Phát hiện NEW・rời top | Thực thi | 1d | |||||||||||||||||
| Màn hình danh sách + Maps Embed | Thực thi | 2d | |||||||||||||||||
| Biểu đồ biến động | Thực thi | 1d | |||||||||||||||||
| Key Embed・CSV | Thực thi | 1d | |||||||||||||||||
| Test tích hợp | Test | 1d | |||||||||||||||||
| Deploy | Deploy | 1d |