Tích hợp BBS
Tổng quan
| Mục | Nội dung |
|---|---|
| Trạng thái | 🔵 Đề xuất |
| Ngày bắt đầu | 2026/06/23 |
| Phụ trách | - |
Nội dung đề xuất
Bối cảnh và vấn đề
Sử dụng API do BBS (pub-api.optimize-business.com) cung cấp để có thể quản lý tài khoản, location và xem trạng thái citation từ màn hình quản lý GMAC MEO.
Màn hình đối tượng và flow điều hướng
[1] Quản lý tài khoản BBS
├─ Danh sách tài khoản (tìm kiếm, phân trang)
├─ Tạo mới tài khoản
├─ [click tên tài khoản] → Chi tiết / Cập nhật tài khoản
└─ [click "Location"] → [2] Danh sách location
[2] Danh sách location (theo tài khoản đã chọn)
├─ [click tên location] → Chi tiết / Cập nhật location
│ └─ Mapping BBS location ↔ Mappy location
└─ [click "Citation"] → [3] Danh sách citation
[3] Danh sách citation (theo location đã chọn)
└─ Trạng thái đăng tải trên từng platform / AI listing / voice assistant| Tên màn hình | Mô tả |
|---|---|
| Quản lý tài khoản BBS | Danh sách・tìm kiếm・tạo mới・chỉnh sửa tài khoản trên BBS |
| Danh sách location | Danh sách location theo tài khoản đã chọn (phí・trạng thái liên kết・đại lý v.v.) |
| Chi tiết / Chỉnh sửa location | Form tạo mới・chỉnh sửa location (35 trường) + setting mapping với Mappy location |
| Danh sách citation | Xem trạng thái đăng tải trên trang citation theo từng location |
Thiết kế kỹ thuật
Chiến lược lưu trữ dữ liệu
Không lưu data BBS vào Mappy — gọi API on-demand mỗi khi cần.
BBS là nguồn dữ liệu gốc (source of truth) cho tài khoản, location và citation. Nếu Mappy lưu lại thì phải giải quyết bài toán đồng bộ khi BBS cập nhật, làm tăng độ phức tạp không cần thiết. Màn hình này là công cụ quản trị nội bộ nên độ trễ API vài trăm ms là chấp nhận được.
Thêm vào đó, API spec ghi rõ access token không có thời hạn → không cần cơ chế refresh token, gọi thẳng mỗi lần là được.
| Dữ liệu | Lưu ở đâu | Lý do |
|---|---|---|
| Danh sách / chi tiết tài khoản BBS | Gọi API on-demand | BBS là nguồn gốc |
| Danh sách / chi tiết location BBS | Gọi API on-demand | BBS là nguồn gốc |
| Trạng thái citation | Gọi API on-demand | BBS là nguồn gốc |
| Mapping BBS location ↔ Mappy location | Lưu trong Mappy DB | Thông tin Mappy-specific, BBS không quản lý |
Thay đổi DB phía Mappy
Bảng mới mappy_bbs_accounts — lưu thông tin đăng nhập và token BBS theo từng tài khoản:
| Cột | Kiểu | Ghi chú |
|---|---|---|
id | BIGINT UNSIGNED PK | |
bbs_account_id | BIGINT UNSIGNED | ID tài khoản bên BBS |
email | VARCHAR(255) | Email đăng nhập BBS |
password | VARCHAR(255) | Mật khẩu đã mã hóa (encrypted) |
token | TEXT | Token lấy từ BBS sau khi tạo tài khoản |
created_at / updated_at / deleted_at | TIMESTAMP NULL |
- UNIQUE
(bbs_account_id) - API key dùng chung cho toàn bộ tài khoản → lưu trong ENV (
BBS_API_KEY), không lưu DB passwordlưu dạng mã hóa có thể giải mã (dùngencrypt()/decrypt()của Laravel — AES-256-CBC) vì BBS không hiển thị mật khẩu sau khi tạo tài khoản- Màn hình chi tiết tài khoản hiển thị mật khẩu dạng
••••••••mặc định, có nút "Hiện" để xem - Khi tạo tài khoản mới: gọi
POST /v1/create-accounts→ gọi tiếpPOST /v1/loginlấy token → lưu vào cộttoken
Bảng mới mappy_bbs_location_mappings — mapping giữa Mappy location và BBS location, tách biệt hoàn toàn với hệ thống hiện tại:
| Cột | Kiểu | Ghi chú |
|---|---|---|
id | BIGINT UNSIGNED PK | |
gbp_location_id | BIGINT UNSIGNED | ID location bên Mappy |
bbs_location_id | BIGINT UNSIGNED | ID location bên BBS |
memo | VARCHAR(255) NULL | Ghi chú vận hành |
created_at / updated_at | TIMESTAMP NULL |
- UNIQUE
(gbp_location_id)— 1 Mappy location chỉ map với 1 BBS location - Không FK cứng sang BBS vì BBS là hệ thống ngoài
- Không sửa bảng
gbp_locationshiện tại
Xác thực (Authentication)
| Loại thao tác | Token cần dùng | Lưu ở đâu |
|---|---|---|
| Quản lý tài khoản / location (ROOT) | ROOT token | ENV (BBS_ROOT_TOKEN) |
| Gọi API theo từng tài khoản | User token | mappy_bbs_accounts.token |
- API key dùng chung toàn hệ thống → ENV (
BBS_API_KEY) - ROOT token lấy một lần từ
POST /v1/inside/login→ lưu ENV, không hết hạn - User token được tạo tự động khi tạo tài khoản mới (
POST /v1/login) → lưu vào bảngmappy_bbs_accounts
API theo từng màn hình
[1] Quản lý tài khoản BBS
| Thao tác | API | Token |
|---|---|---|
| Load danh sách | GET /v1/pub-accounts | ROOT |
| Xem chi tiết tài khoản | GET /v1/pub-accounts/{account_id} | ROOT |
| Tạo mới tài khoản | POST /v1/create-accounts → POST /v1/login (lấy & lưu token) | ROOT |
| Cập nhật tài khoản | PUT /v1/update-accounts/{account_id} | ROOT |
Khi tạo tài khoản: sau khi
POST /v1/create-accountsthành công, tự động gọi tiếpPOST /v1/loginrồi lưu token vàomappy_bbs_accounts.
[2] Danh sách location
| Thao tác | API | Token |
|---|---|---|
| Load danh sách location theo tài khoản | GET /v1/pub-locations (filter account_id) | ROOT |
| Xem chi tiết location | GET /v1/pub-locations/{location_id} | ROOT |
| Tạo mới location | POST /v1/create-locations | ROOT |
| Cập nhật location | PUT /v1/update-locations/{location_id} | ROOT |
| Lưu mapping BBS ↔ Mappy | INSERT/UPDATE mappy_bbs_location_mappings | — (Mappy DB, không gọi BBS) |
[3] Danh sách citation
| Thao tác | API | Token |
|---|---|---|
| Load trạng thái citation theo location | GET /v1/pub_citation_pages/by-location/{location_id} | User token (mappy_bbs_accounts.token) |
Citation dùng user token của tài khoản sở hữu location đó, không dùng ROOT token.
Bảng API tương ứng
Endpoint base: https://pub-api.optimize-business.com Xác thực: Thao tác ROOT dùng token từ POST /v1/inside/login, thao tác người dùng dùng token từ POST /v1/login.
Quản lý tài khoản BBS
| Thao tác | Phương thức | URI | Xác thực |
|---|---|---|---|
| Lấy danh sách tài khoản | GET | /v1/pub-accounts | ROOT token |
| Lấy thông tin tài khoản | GET | /v1/pub-accounts/{account_id} | ROOT token |
| Tạo tài khoản | POST | /v1/create-accounts | ROOT token |
| Cập nhật tài khoản | PUT | /v1/update-accounts/{account_id} | ROOT token |
Tham số request chính (tạo・cập nhật): name, email, password, address_line_1〜3, telephone, account_representative, is_additional_line_notification_allowed, memo
Danh sách・Chi tiết・Chỉnh sửa location
| Thao tác | Phương thức | URI | Xác thực |
|---|---|---|---|
| Lấy danh sách location | GET | /v1/pub-locations | ROOT token |
| Lấy thông tin location | GET | /v1/pub-locations/{location_id} | ROOT token |
| Tạo location | POST | /v1/create-locations | ROOT token |
| Cập nhật location | PUT | /v1/update-locations/{location_id} | ROOT token |
Tham số request chính (tạo・cập nhật):
| Tham số | Kiểu | Ghi chú |
|---|---|---|
name | String | Tên location |
address_line_1〜3 | String | Mã bưu điện・tỉnh thành・địa chỉ chi tiết |
telephone | int | 10〜13 ký tự, phân cách bằng dấu gạch ngang |
location_person | String | Người phụ trách location |
place_id | String | Google Place ID |
status | int | 1:Hợp đồng / 2:Sắp hủy / 3:Đã hủy / 4:Chuẩn bị / 5:Tạm dừng |
service_id | int | 1:Liên kết Insta / 2:Quản lý Google / 3:Insta×Google / 4:CMS / 5:IG / 6:IM / 7:Recruit / 8:Synup |
contract_start | timestamp | YYYY-MM-DD HH:MM:SS |
contract_update_interval | int | Thời hạn hợp đồng (tháng). Bắt buộc khi status=1,2 |
contract_end | timestamp | Mặc định là ngày cuối tháng hiện tại |
initial_cost / monthly_cost | int | Phí ban đầu・hàng tháng |
initial_transfer_amount / monthly_transfer_amount | int | Giá nhập (ban đầu・hàng tháng) |
initial_back_amount / monthly_back_amount | int | Hoa hồng (ban đầu・hàng tháng) |
agency_id | int | Đại lý (mặc định: 1=không có) |
payment_method | int | 0:Chưa chọn / 1:Thẻ / 2:Chuyển khoản / 3:Hóa đơn / 4:Đại lý hóa đơn |
billing_destination | String | Địa chỉ thanh toán |
is_initial_configuration | int | Citation: 0:không / 1:có / 2:gói cao cấp |
is_splan / is_owlet / is_onerank / is_win / is_hitosara | int | Tùy chọn CMS (0:không / 1:có) |
is_synup | int | 0:không / 1:có / 2:có (nhà hàng/lưu trú) |
synup_serial_number | String | Số serial Synup |
is_pc_block | int | Chặn PC trang đệm đánh giá (0:không / 1:có) |
target_keywords | JSON | Từ khóa mục tiêu (tối đa 10) |
memo | String | Ghi chú |
Danh sách citation
| Thao tác | Phương thức | URI | Xác thực |
|---|---|---|---|
| Lấy thông tin trang citation | GET | /v1/pub_citation_pages/by-location/{location_id} | token |
Response bao gồm trạng thái đăng tải (đã đồng bộ/đang chuẩn bị/cần liên kết tài khoản) và URL link theo từng AI listing・voice assistant・platform.
Mockup màn hình
Quản lý tài khoản BBS
BBSアカウント管理
| ID | アカウント名 | adminユーザー | 住所 | 電話番号 | インスタ連携 | GBP管理 | インスタ × GBP | 合計契約数 | 月額料金合計 | メモ | 操作 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 51420 | tanaka@gmail.com | 東京都港区赤坂3丁目21−15 | 03-4500-7451 | 3 | 5 | 2 | 10 | ¥48,000 | |||
| 51383 | h.sato@company.co.jp | 東京都新宿区西新宿2-8-1 | 080-2345-6789 | 1 | 2 | 1 | 4 | ¥16,000 | |||
| 51441 | suzuki@gmail.com | 東京都豊島区東池袋1-1-1 | 090-3456-7890 | 5 | 8 | 4 | 17 | ¥85,000 | |||
| 51298 | misaki.t@outlook.com | 神奈川県横浜市西区みなとみらい2-2 | 045-567-8901 | 0 | 1 | 0 | 1 | ¥4,800 | 退会検討中 | ||
| 51247 | kenta.n@company.jp | 東京都品川区大崎1-2-2 | 03-2345-6789 | 2 | 3 | 2 | 7 | ¥34,000 | |||
| 51203 | akane.k@mappy-admin.jp | 東京都千代田区秋葉原1-1 | 03-3456-7890 | 8 | 12 | 6 | 26 | ¥130,000 | VIP顧客 | ||
| 51187 | yuji.ito@ymail.co.jp | 東京都台東区上野4-1-1 | 070-4567-8901 | 2 | 4 | 1 | 7 | ¥33,600 | |||
| 51152 | sachiko.y@hotmail.com | 東京都武蔵野市吉祥寺本町1-1 | 0422-12-3456 | 1 | 1 | 0 | 2 | ¥9,600 | 長期未ログイン |
Chi tiết / Chỉnh sửa tài khoản
Danh sách location (theo tài khoản)
ロケーション一覧
| 基本情報 | 料金 | 代理店・支払い | FB連携 | GBP連携 | LINE公式連携 | IG API連携 | — | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ID | ロケーション | 住所 | 契約期間 | 電話番号 | ステータス | 契約サービス | 初期費用 | 月額費用 | 仕切り (初期) | 仕切り (月額) | バック (初期) | バック (月額) | サイテーション | 自動更新 システム | 自動更新 (月額) | 代理店 | 支払い方法 | 請求先 | ステータス | インスタID | ステータス | 接続メール | ステータス | アクセストークン | ステータス | ロギングID | メモ |
| 33944 | 株式会社H2Technology | 107-0052, 東京都港区赤坂3丁目21−15 東都赤坂ビル 2階A号室 | 2026/04/01 〜 2027/03/31 | 03-4500-7451 | 契約 | インスタ連携 × GBP管理 | なし | なし | なし | 未選択 | なし | なし | なし | なし | なし | H2 | — | — | 連携済み | h2technologytest | 連携済み | h2tec12131234@gmail.com | 連携済み | h2technologytest | H2 | — | |
| 33945 | 渋谷サンプル店 | 150-0041, 東京都渋谷区神南1丁目2−3 | 2026/01/01 〜 2026/12/31 | 03-1234-0001 | 契約 | GBP管理 | ¥50,000 | ¥9,800 | ¥30,000 | ¥5,000 | なし | なし | あり | あり | ¥2,000 | Agency A | クレジット | 本社 | 未連携 | — | 連携済み | shibuya@sample.jp | 未連携 | — | 未連携 | — | テスト中 |
| 33946 | 新宿テスト法人 | 160-0023, 東京都新宿区西新宿2丁目8−1 | 2025/07/01 〜 2026/06/30 | 03-5678-9012 | 解約 | インスタ連携 | ¥30,000 | ¥4,800 | 未選択 | 未選択 | なし | なし | なし | なし | なし | — | 銀行振込 | 担当者 | 連携済み | shinjuku_test | 未連携 | — | 未連携 | — | 未連携 | — | 解約済み |
Chi tiết / Chỉnh sửa location
Danh sách citation
サイテーション一覧
AIリスティング
| AI |
|---|
⬡openai.com |
✦gemini.google.com |
◈perplexity.ai |
⬡copilot.microsoft.com |
◈intellychat.com |
◈myndmeld.com |
ボイスアシスタントリスティング
| アシスタント | 連携ステータス |
|---|---|
CCortana | ⏳ 進行中 |
AAlexa | ⏳ 進行中 |
SSiri | ⏳ 進行中 |
プラットフォームリスティング
| プラットフォーム | 連携ステータス | インデックス | リンク |
|---|---|---|---|
HHotfrog | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
BBeLocalFocussed | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
Aarrivebusiness | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
GGoLocalPages | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
BBrownBook | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
iiGlobal | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
OOpenDi.us | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
PPassPages | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
SSpeedy Local | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
LLocalizedListings | ✔ 同期済み | 🌐 Yes | 🔗 アクティブ |
NNAVITIME | ✔ 同期済み | — | |
MMapion | ✔ 同期済み | — | |
TTabelog | ✔ 同期済み | — | |
PPayPay | ✔ 同期済み | — | |
AAmazon | ✔ 同期済み | — | |
YYouTube | ✔ 同期済み | — | |
RRakuten Market | ✔ 同期済み | — | |
DDiDi | ✔ 同期済み | — | |
WWaze | ✔ 同期済み | — | |
UUber | ✔ 同期済み | — | |
LLife360 | ✔ 同期済み | — | |
MMapFan | ✔ 同期済み | — | |
LLUUP | ✔ 同期済み | — | |
◉Pokemon GO | ✔ 同期済み | — | |
TToyota | ✔ 同期済み | — | |
HHonda | ✔ 同期済み | — | |
BBMW | ✔ 同期済み | — | |
MMercedes Benz | ✔ 同期済み | — | |
BBaidu | ✔ 同期済み | — | |
TTomTom | プラットフォーム側準備中 | 🌐 No | |
HHere | プラットフォーム側準備中 | 🌐 No | |
BBing | プラットフォーム側準備中 | 🌐 No | |
MMG | プラットフォーム側準備中 | 🌐 No | |
◆Apple Maps | プラットフォーム側準備中 | 🌐 No | 🔗 アクティブ |
◉TripAdvisor | アカウント連携が必要 | 🌐 No |
Ước lượng công sức (AI-assisted)
Cấu trúc 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ỉ thị AI tạo tài liệu → Review → Chỉ thị phát triển |
| Người phát triển | 1 | Dựa vào ISSUE chỉ thị AI → Review code → Test → Deploy |
Chi tiết công sức
| # | Hạng mục công việc | Số lần AI retry | Thời gian review | Công sức (ngày-người) | Phụ trách |
|---|---|---|---|---|---|
| 1 | Xác nhận yêu cầu・Tạo tài liệu thiết kế | — | — | 1.0 | Người thiết kế |
| 2 | Xác thực ROOT・Xây dựng API client | 2 lần | 0.5 ngày/lần | 1.0 | Người phát triển |
| 3 | Quản lý tài khoản BBS (danh sách・tìm kiếm・phân trang) | 4 lần | 0.5 ngày/lần | 2.0 | Người phát triển |
| 4 | Form chi tiết・chỉnh sửa tài khoản | 3 lần | 0.5 ngày/lần | 1.5 | Người phát triển |
| 5 | Danh sách location (bảng có header nhóm) | 4 lần | 0.5 ngày/lần | 2.0 | Người phát triển |
| 6 | Form tạo・chỉnh sửa location (35 trường・validation) | 5 lần | 0.5 ngày/lần | 2.5 | Người phát triển |
| 7 | Danh sách citation (3 section) | 2 lần | 0.5 ngày/lần | 1.0 | Người phát triển |
| 8 | Test tích hợp・Deploy | 3 lần | 0.5 ngày/lần | 1.5 | Người phát triển |
| 9 | Review thiết kế・Chỉ thị phát triển | — | — | 1.0 | Người thiết kế |
| Tổng cộng | 13.5 | Thiết kế 2.0 ngày / Phát triển 11.5 ngày |
Lịch trình
| タスク | 担当 | 日数 | 6/23 | 6/24 | 6/25 | 6/26 | 6/27 | 6/28 | 6/29 | 6/30 | 7/1 | 7/2 | 7/3 | 7/4 | 7/5 | 7/6 | 7/7 | 7/8 | 7/9 | 7/10 | 7/11 | 7/12 | 7/13 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 火 | 水 | 木 | 金 | 土 | 日 | 月 | 火 | 水 | 木 | 金 | 土 | 日 | 月 | 火 | 水 | 木 | 金 | 土 | 日 | 月 | |||
| Xác nhận yêu cầu・Tạo tài liệu thiết kế | Người thiết kế | 1d | |||||||||||||||||||||
| Xác thực ROOT・Xây dựng API client | Người phát triển | 1d | |||||||||||||||||||||
| Review thiết kế・Chỉ thị phát triển | Người thiết kế | 1d | |||||||||||||||||||||
| Quản lý tài khoản BBS (danh sách・tìm kiếm) | Người phát triển | 2d | |||||||||||||||||||||
| Form chi tiết・chỉnh sửa tài khoản | Người phát triển | 2d | |||||||||||||||||||||
| Danh sách location | Người phát triển | 2d | |||||||||||||||||||||
| Form tạo・chỉnh sửa location | Người phát triển | 3d | |||||||||||||||||||||
| Danh sách citation | Người phát triển | 1d | |||||||||||||||||||||
| Test tích hợp・Deploy | Người phát triển | 2d |
PHẦN 2 — Chi tiết task để thực hiện code
Phần dành cho đội phát triển.
Tổng quan kỹ thuật
| Hạng mục | Nội dung |
|---|---|
| Repo | mappy-laravel-docker/mappy/laravel (GitLab h2t/mappy, Laravel 5.7 / PHP 7.1) |
| Chiến lược data | Gọi BBS API on-demand, không lưu cache |
| Bảng mới | mappy_bbs_accounts, mappy_bbs_location_mappings |
| ENV cần thêm | BBS_API_KEY, BBS_ROOT_TOKEN, BBS_API_BASE_URL |
| Dự kiến công | ~13.5 người-ngày (2 người: 1 thiết kế + 1 sản xuất) |
ENV variables
Thêm vào .env và .env.example:
BBS_API_BASE_URL=https://pub-api.optimize-business.com
BBS_API_KEY= # x-api-key dùng chung toàn hệ thống
BBS_ROOT_TOKEN= # Bearer token từ POST /v1/inside/login (không hết hạn)Checklist triển khai
Thứ tự: A → (B, C, D song song) → E → F.
A. Nền tảng (làm trước tiên — mọi phần khác phụ thuộc)
- [ ] Migration tạo bảng
mappy_bbs_accounts— các cột:id,bbs_account_id(UNIQUE),email,password(encrypted),token(TEXT),created_at,updated_at,deleted_at - [ ] Migration tạo bảng
mappy_bbs_location_mappings— các cột:id,gbp_location_id(UNIQUE),bbs_location_id,memo,created_at,updated_at - [ ] Model
app/Models/Mappy/BbsAccount.php—fillable, castpasswordquaencrypt()/decrypt(), SoftDeletes - [ ] Model
app/Models/Mappy/BbsLocationMapping.php—fillable, quan hệbelongsTo(GbpLocation::class) - [ ] Service
app/Services/Mappy/BbsApiService.php— HTTP client wrapper gọi BBS API:- Header mặc định:
x-api-key: env('BBS_API_KEY'),Content-Type: application/json - Method
rootToken()— trảenv('BBS_ROOT_TOKEN') - Method
userToken($accountId)— lấytokentừBbsAccounttheobbs_account_id - Method
get($uri, $token),post($uri, $data, $token),put($uri, $data, $token) - Throw
BbsApiExceptionkhi response status >= 400
- Header mặc định:
B. Backend — Quản lý tài khoản (song song với C, D)
- [ ]
app/Http/Controllers/Mappy/BbsAccountController.php:index()—GET /v1/pub-accounts(ROOT token) → trả danh sáchshow($bbsAccountId)—GET /v1/pub-accounts/{id}+ lấypassworddecrypt từmappy_bbs_accounts→ trả thêm fieldstoredEmail,storedPassword(masked)store(Request $request)— validate →POST /v1/create-accounts→POST /v1/loginlấy token → INSERTmappy_bbs_accountsupdate(Request $request, $bbsAccountId)— validate →PUT /v1/update-accounts/{id}revealPassword($bbsAccountId)— trảpassworddạng plain text (decrypt), chỉ gọi khi user bấm nút "Hiện"
- [ ] Validation
store/update:namerequired|max:255,emailrequired|email,passwordrequired|min:8,telephonenullable|regex:/^\d{2,4}-\d{2,4}-\d{4}$/ - [ ] Route:php
Route::prefix('bbs/accounts')->group(function () { Route::get('/', 'BbsAccountController@index'); Route::post('/', 'BbsAccountController@store'); Route::get('/{id}', 'BbsAccountController@show'); Route::put('/{id}', 'BbsAccountController@update'); Route::get('/{id}/password', 'BbsAccountController@revealPassword'); });
C. Backend — Danh sách / chi tiết location (song song với B, D)
- [ ]
app/Http/Controllers/Mappy/BbsLocationController.php:index($bbsAccountId)—GET /v1/pub-locationsfilter theoaccount_id+ joinmappy_bbs_location_mappingsđể biết location nào đã mappingshow($bbsLocationId)—GET /v1/pub-locations/{id}+ lấy mapping nếu cóstore(Request $request)— validate →POST /v1/create-locationsupdate(Request $request, $bbsLocationId)— validate →PUT /v1/update-locations/{id}mapping(Request $request, $bbsLocationId)— validategbp_location_id→ upsertmappy_bbs_location_mappings
- [ ] Validation
store/update:namerequired,address_line_1required,location_personrequired,statusrequired|in:1,2,3,4,5,service_idrequired|in:1,2,3,4,5,6,7,8,contract_update_intervalrequired_if:status,1,2 - [ ] Route:php
Route::prefix('bbs/accounts/{accountId}/locations')->group(function () { Route::get('/', 'BbsLocationController@index'); Route::post('/', 'BbsLocationController@store'); Route::get('/{id}', 'BbsLocationController@show'); Route::put('/{id}', 'BbsLocationController@update'); Route::post('/{id}/mapping', 'BbsLocationController@mapping'); });
D. Backend — Danh sách citation (song song với B, C)
- [ ]
app/Http/Controllers/Mappy/BbsCitationController.php:index($bbsLocationId)— lấybbs_account_idtừ location → lấy user token từmappy_bbs_accounts→GET /v1/pub_citation_pages/by-location/{id}
- [ ] Route:php
Route::get('bbs/locations/{locationId}/citations', 'BbsCitationController@index');
E. Frontend (sau khi A xong)
- [ ]
resources/js/mappy/views/bbs/AccountList.vue— danh sách tài khoản, tìm kiếm, phân trang; nút "Tạo mới", "Chỉnh sửa", link sang LocationList - [ ]
resources/js/mappy/views/bbs/AccountForm.vue— form tạo/chỉnh sửa tài khoản; field password hiện••••••••, nút "Hiện" gọiGET /{id}/password - [ ]
resources/js/mappy/views/bbs/LocationList.vue— bảng nhiều cột header nhóm, breadcrumb về AccountList, nút "Tạo mới", link sang CitationList - [ ]
resources/js/mappy/views/bbs/LocationForm.vue— form 35 trường + section mapping Mappy location (dropdowngbp_location_id) - [ ]
resources/js/mappy/views/bbs/CitationList.vue— 3 section (AI listing, Voice assistant, Platform), hiện trạng thái + link URL theo từng dòng
F. QA & vận hành (làm cuối)
- [ ] Unit
BbsApiService: U1 (ROOT token header đúng), U2 (response 4xx → throw BbsApiException), U3 (userToken lấy đúng theo bbs_account_id) - [ ] Unit
BbsAccount: U4 (password được encrypt khi lưu), U5 (revealPassword trả plain text đúng) - [ ] Integration: I1 (tạo account → token được lưu vào mappy_bbs_accounts), I2 (mapping location → upsert đúng), I3 (citation dùng user token không phải ROOT), I4 (BBS API lỗi → trả lỗi rõ ràng cho FE)
- [ ] Regression: R1 (màn hình hiện tại không bị ảnh hưởng), R2 (bảng gbp_locations không thay đổi)
- [ ] Thêm
BBS_API_KEY,BBS_ROOT_TOKEN,BBS_API_BASE_URLvào.env.examplevà CI/CD secrets