Skip to content

Tích hợp BBS

Tổng quan

MụcNội dung
Trạng thái🔵 Đề xuất
Ngày bắt đầu2026/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ìnhMô tả
Quản lý tài khoản BBSDanh sách・tìm kiếm・tạo mới・chỉnh sửa tài khoản trên BBS
Danh sách locationDanh 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 locationForm tạo mới・chỉnh sửa location (35 trường) + setting mapping với Mappy location
Danh sách citationXem 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ệuLưu ở đâuLý do
Danh sách / chi tiết tài khoản BBSGọi API on-demandBBS là nguồn gốc
Danh sách / chi tiết location BBSGọi API on-demandBBS là nguồn gốc
Trạng thái citationGọi API on-demandBBS là nguồn gốc
Mapping BBS location ↔ Mappy locationLưu trong Mappy DBThô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ộtKiểuGhi chú
idBIGINT UNSIGNED PK
bbs_account_idBIGINT UNSIGNEDID tài khoản bên BBS
emailVARCHAR(255)Email đăng nhập BBS
passwordVARCHAR(255)Mật khẩu đã mã hóa (encrypted)
tokenTEXTToken lấy từ BBS sau khi tạo tài khoản
created_at / updated_at / deleted_atTIMESTAMP 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
  • password lưu dạng mã hóa có thể giải mã (dùng encrypt()/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ếp POST /v1/login lấy token → lưu vào cột token

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ộtKiểuGhi chú
idBIGINT UNSIGNED PK
gbp_location_idBIGINT UNSIGNEDID location bên Mappy
bbs_location_idBIGINT UNSIGNEDID location bên BBS
memoVARCHAR(255) NULLGhi chú vận hành
created_at / updated_atTIMESTAMP 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_locations hiện tại

Xác thực (Authentication)

Loại thao tácToken cần dùngLưu ở đâu
Quản lý tài khoản / location (ROOT)ROOT tokenENV (BBS_ROOT_TOKEN)
Gọi API theo từng tài khoảnUser tokenmappy_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ảng mappy_bbs_accounts

API theo từng màn hình

[1] Quản lý tài khoản BBS

Thao tácAPIToken
Load danh sáchGET /v1/pub-accountsROOT
Xem chi tiết tài khoảnGET /v1/pub-accounts/{account_id}ROOT
Tạo mới tài khoảnPOST /v1/create-accountsPOST /v1/login (lấy & lưu token)ROOT
Cập nhật tài khoảnPUT /v1/update-accounts/{account_id}ROOT

Khi tạo tài khoản: sau khi POST /v1/create-accounts thành công, tự động gọi tiếp POST /v1/login rồi lưu token vào mappy_bbs_accounts.

[2] Danh sách location

Thao tácAPIToken
Load danh sách location theo tài khoảnGET /v1/pub-locations (filter account_id)ROOT
Xem chi tiết locationGET /v1/pub-locations/{location_id}ROOT
Tạo mới locationPOST /v1/create-locationsROOT
Cập nhật locationPUT /v1/update-locations/{location_id}ROOT
Lưu mapping BBS ↔ MappyINSERT/UPDATE mappy_bbs_location_mappings— (Mappy DB, không gọi BBS)

[3] Danh sách citation

Thao tácAPIToken
Load trạng thái citation theo locationGET /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ácPhương thứcURIXác thực
Lấy danh sách tài khoảnGET/v1/pub-accountsROOT token
Lấy thông tin tài khoảnGET/v1/pub-accounts/{account_id}ROOT token
Tạo tài khoảnPOST/v1/create-accountsROOT token
Cập nhật tài khoảnPUT/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ácPhương thứcURIXác thực
Lấy danh sách locationGET/v1/pub-locationsROOT token
Lấy thông tin locationGET/v1/pub-locations/{location_id}ROOT token
Tạo locationPOST/v1/create-locationsROOT token
Cập nhật locationPUT/v1/update-locations/{location_id}ROOT token

Tham số request chính (tạo・cập nhật):

Tham sốKiểuGhi chú
nameStringTên location
address_line_1〜3StringMã bưu điện・tỉnh thành・địa chỉ chi tiết
telephoneint10〜13 ký tự, phân cách bằng dấu gạch ngang
location_personStringNgười phụ trách location
place_idStringGoogle Place ID
statusint1:Hợp đồng / 2:Sắp hủy / 3:Đã hủy / 4:Chuẩn bị / 5:Tạm dừng
service_idint1:Liên kết Insta / 2:Quản lý Google / 3:Insta×Google / 4:CMS / 5:IG / 6:IM / 7:Recruit / 8:Synup
contract_starttimestampYYYY-MM-DD HH:MM:SS
contract_update_intervalintThời hạn hợp đồng (tháng). Bắt buộc khi status=1,2
contract_endtimestampMặc định là ngày cuối tháng hiện tại
initial_cost / monthly_costintPhí ban đầu・hàng tháng
initial_transfer_amount / monthly_transfer_amountintGiá nhập (ban đầu・hàng tháng)
initial_back_amount / monthly_back_amountintHoa hồng (ban đầu・hàng tháng)
agency_idintĐại lý (mặc định: 1=không có)
payment_methodint0:Chưa chọn / 1:Thẻ / 2:Chuyển khoản / 3:Hóa đơn / 4:Đại lý hóa đơn
billing_destinationStringĐịa chỉ thanh toán
is_initial_configurationintCitation: 0:không / 1:có / 2:gói cao cấp
is_splan / is_owlet / is_onerank / is_win / is_hitosaraintTùy chọn CMS (0:không / 1:có)
is_synupint0:không / 1:có / 2:có (nhà hàng/lưu trú)
synup_serial_numberStringSố serial Synup
is_pc_blockintChặn PC trang đệm đánh giá (0:không / 1:có)
target_keywordsJSONTừ khóa mục tiêu (tối đa 10)
memoStringGhi chú

Danh sách citation

Thao tácPhương thứcURIXác thực
Lấy thông tin trang citationGET/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

8件 表示中
IDアカウント名adminユーザー住所電話番号インスタ連携GBP管理インスタ × GBP合計契約数月額料金合計メモ操作
51420tanaka@gmail.com東京都港区赤坂3丁目21−1503-4500-745135210¥48,000
51383h.sato@company.co.jp東京都新宿区西新宿2-8-1080-2345-67891214¥16,000
51441suzuki@gmail.com東京都豊島区東池袋1-1-1090-3456-789058417¥85,000
51298misaki.t@outlook.com神奈川県横浜市西区みなとみらい2-2045-567-89010101¥4,800
退会検討中
51247kenta.n@company.jp東京都品川区大崎1-2-203-2345-67892327¥34,000
51203akane.k@mappy-admin.jp東京都千代田区秋葉原1-103-3456-7890812626¥130,000
VIP顧客
51187yuji.ito@ymail.co.jp東京都台東区上野4-1-1070-4567-89012417¥33,600
51152sachiko.y@hotmail.com東京都武蔵野市吉祥寺本町1-10422-12-34561102¥9,600
長期未ログイン

Chi tiết / Chỉnh sửa tài khoản

Danh sách location (theo tài khoản)

3件
基本情報料金代理店・支払いFB連携GBP連携LINE公式連携IG API連携
IDロケーション住所契約期間電話番号ステータス契約サービス初期費用月額費用仕切り
(初期)
仕切り
(月額)
バック
(初期)
バック
(月額)
サイテーション自動更新
システム
自動更新
(月額)
代理店支払い方法請求先ステータスインスタIDステータス接続メールステータスアクセストークンステータスロギングIDメモ
33944株式会社H2Technology107-0052, 東京都港区赤坂3丁目21−15 東都赤坂ビル 2階A号室2026/04/01 〜 2027/03/3103-4500-7451契約インスタ連携 × GBP管理なしなしなし未選択なしなしなしなしなしH2連携済み連携済み連携済みH2
33945渋谷サンプル店150-0041, 東京都渋谷区神南1丁目2−32026/01/01 〜 2026/12/3103-1234-0001契約GBP管理¥50,000¥9,800¥30,000¥5,000なしなしありあり¥2,000Agency Aクレジット本社未連携連携済み未連携未連携
テスト中
33946新宿テスト法人160-0023, 東京都新宿区西新宿2丁目8−12025/07/01 〜 2026/06/3003-5678-9012解約インスタ連携¥30,000¥4,800未選択未選択なしなしなしなしなし銀行振込担当者連携済み未連携未連携未連携
解約済み

Chi tiết / Chỉnh sửa location

Danh sách citation

サイテーション数99
株式会社H2Technology

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ườiNội dung phụ trách
Người thiết kế1Xá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ển1Dự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ệcSố lần AI retryThời gian reviewCông sức (ngày-người)Phụ trách
1Xác nhận yêu cầu・Tạo tài liệu thiết kế1.0Người thiết kế
2Xác thực ROOT・Xây dựng API client2 lần0.5 ngày/lần1.0Người phát triển
3Quản lý tài khoản BBS (danh sách・tìm kiếm・phân trang)4 lần0.5 ngày/lần2.0Người phát triển
4Form chi tiết・chỉnh sửa tài khoản3 lần0.5 ngày/lần1.5Người phát triển
5Danh sách location (bảng có header nhóm)4 lần0.5 ngày/lần2.0Người phát triển
6Form tạo・chỉnh sửa location (35 trường・validation)5 lần0.5 ngày/lần2.5Người phát triển
7Danh sách citation (3 section)2 lần0.5 ngày/lần1.0Người phát triển
8Test tích hợp・Deploy3 lần0.5 ngày/lần1.5Người phát triển
9Review thiết kế・Chỉ thị phát triển1.0Người thiết kế
Tổng cộng13.5Thiết kế 2.0 ngày / Phát triển 11.5 ngày

Lịch trình

タスク担当日数6/236/246/256/266/276/286/296/307/17/27/37/47/57/67/77/87/97/107/117/127/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 clientNgười phát triển1d
Review thiết kế・Chỉ thị phát triểnNgườ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ển2d
Form chi tiết・chỉnh sửa tài khoảnNgười phát triển2d
Danh sách locationNgười phát triển2d
Form tạo・chỉnh sửa locationNgười phát triển3d
Danh sách citationNgười phát triển1d
Test tích hợp・DeployNgười phát triển2d

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ụcNội dung
Repomappy-laravel-docker/mappy/laravel (GitLab h2t/mappy, Laravel 5.7 / PHP 7.1)
Chiến lược dataGọi BBS API on-demand, không lưu cache
Bảng mớimappy_bbs_accounts, mappy_bbs_location_mappings
ENV cần thêmBBS_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.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.phpfillable, cast password qua encrypt()/decrypt(), SoftDeletes
  • [ ] Model app/Models/Mappy/BbsLocationMapping.phpfillable, 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ấy token từ BbsAccount theo bbs_account_id
    • Method get($uri, $token), post($uri, $data, $token), put($uri, $data, $token)
    • Throw BbsApiException khi response status >= 400

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ách
    • show($bbsAccountId)GET /v1/pub-accounts/{id} + lấy password decrypt từ mappy_bbs_accounts → trả thêm field storedEmail, storedPassword (masked)
    • store(Request $request) — validate → POST /v1/create-accountsPOST /v1/login lấy token → INSERT mappy_bbs_accounts
    • update(Request $request, $bbsAccountId) — validate → PUT /v1/update-accounts/{id}
    • revealPassword($bbsAccountId) — trả password dạng plain text (decrypt), chỉ gọi khi user bấm nút "Hiện"
  • [ ] Validation store/update: name required|max:255, email required|email, password required|min:8, telephone nullable|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-locations filter theo account_id + join mappy_bbs_location_mappings để biết location nào đã mapping
    • show($bbsLocationId)GET /v1/pub-locations/{id} + lấy mapping nếu có
    • store(Request $request) — validate → POST /v1/create-locations
    • update(Request $request, $bbsLocationId) — validate → PUT /v1/update-locations/{id}
    • mapping(Request $request, $bbsLocationId) — validate gbp_location_id → upsert mappy_bbs_location_mappings
  • [ ] Validation store/update: name required, address_line_1 required, location_person required, status required|in:1,2,3,4,5, service_id required|in:1,2,3,4,5,6,7,8, contract_update_interval required_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ấy bbs_account_id từ location → lấy user token từ mappy_bbs_accountsGET /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ọi GET /{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 (dropdown gbp_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_URL vào .env.example và CI/CD secrets