Asia Business Builders — Merchant Banking CRM ABBMB — kỹ thuật & hướng dẫn sử dụng Hướng dẫn

Tài liệu kỹ thuật · người dùng & người phân tích

CRM ABBMB: dùng hằng ngày và đọc dữ liệu từ kho BigQuery

Một trang cho người ghi biên bản, một trang cho người phân tích, một trang cho người vận hành

Phần đầu hướng dẫn người dùng làm việc trong CRM: đăng nhập, ghi biên bản, giao việc, tìm lịch sử. Phần giữa là trợ lý Claude đọc CRM. Phần lớn nhất mô tả kho dữ liệu (DWH): mỗi đêm hệ thống chụp toàn bộ CRM vào Google BigQuery ra sao, bảng nào chứa gì, truy vấn thế nào cho đúng, và các lớp bảo vệ quanh dữ liệu cá nhân.

abbmb_dwh._snapshot_check18/10
BảngSố dòngok
res_partner5.277✓
abb_meeting_note3.374✓
abb_meeting_attendee1.033✓
abb_legacy_deal128✓
abb_company_group4✓

Mỗi đêm 03:30: 5/5 bảng phải khớp số dòng = số id khác nhau = số bản ghi Odoo đếm được, nếu không thì cả lượt báo lỗi.

01 · Kiến trúc

Các thành phần và vì sao chọn

Mọi thứ chạy trên một máy chủ ảo Google Cloud ở Singapore (asia-southeast1). Không có thành phần nào lưu dữ liệu ngoài vùng này, trừ trợ lý AI đọc theo yêu cầu (pháp chế đã cho phép).


LớpChọnGhi chú
Ứng dụngOdoo Community 20 + module abb_dealMã nguồn mở; module riêng kế thừa, không sửa lõi Odoo; 121–123 bài test tự động
Cơ sở dữ liệuPostgreSQL 16Image ghim theo digest, không dùng tag trôi
Cửa vàonginx + chứng chỉ Let's EncryptChỉ mở giao diện web; API JSON-2 và trang tài liệu API bị chặn từ internet
Bí mậtGoogle Secret ManagerNạp vào bộ nhớ tạm (tmpfs) khi khởi động, không nằm trên đĩa
Sao lưuBackup 02:00 mỗi đêm ra Cloud Storage + snapshot đĩaKhôi phục thử trên DB tên khác; cảnh báo email khi backup lỗi hoặc quá hạn
Giám sátCloud Logging + MonitoringUptime web, RAM, backup, DWH — mỗi loại một chính sách cảnh báo email
Kho dữ liệuGoogle BigQuery, dataset abbmb_dwhẢnh chụp đầy đủ mỗi đêm 03:30 — phần 05–08
Trợ lý AIClaude qua MCP, chỉ đọcMỗi người một tài khoản chỉ xem + khoá API riêng, hạn 90 ngày — phần 04

Hạ tầng dựng từ bộ khung dùng chung odoo-gcp-base (v2.1.0). Mọi giá trị riêng của ABBMB nằm trong một file cấu hình tenant; bộ khung không chứa tên tenant nào — đó là điều kiện để portco khác dùng lại được.

02 · Người dùng

Dùng CRM hằng ngày

Giao diện bằng tiếng Anh; tên nút và menu dưới đây giữ nguyên như trên màn hình. Ứng dụng nằm ở menu trên cùng bên trái: ABB CRM.


Đăng nhập lần đầu

  • Tài khoản là của riêng bạn — không dùng chung. Chủ CRM gửi riêng cho bạn tên đăng nhập và mật khẩu tạm; đăng nhập rồi đổi mật khẩu ngay.
  • Bật xác thực hai lớp: avatar → My Preferences → Account Security.
  • Thông báo hiện trong Odoo (chuông, Discuss), không gửi qua email.

Vai trò

Vai tròLàm được
Manager (Quản lý)Mọi việc của Nhân viên, thêm: đổi Company Group của công ty, gộp bản ghi trùng, xử lý hàng Pending Review, xuất dữ liệu
Staff (Nhân viên)Đọc toàn bộ; tạo và sửa biên bản, công ty, liên hệ; giao việc theo dõi. Không xuất được dữ liệu.
Read-only (Chỉ xem)Đọc toàn bộ; chỉ sửa hồ sơ của chính mình

Ghi một cuộc gặp

ABB CRM → Meeting Notes → New. Điền 7 phần theo mẫu ABB — phần in đậm là bắt buộc:

DateNgày gặp (bắt buộc)
Person(s) met withChọn liên hệ có sẵn (bắt buộc); người mới → New person
CompanyChọn từ danh sách (bắt buộc); chưa có thì gõ tên, Quản lý gắn sau
Brief descriptionTóm tắt cuộc gặp (bắt buộc)
Follow-up · Key dataViệc tiếp theo, dữ liệu chính thu được
  • ABB Attendees (mặc định là bạn) cũng bắt buộc. Phần Contact details ghi thông tin liên hệ mới nhận.
  • Người mới (New person) hoặc liên hệ đổi thông tin (Contact update) đều vào Pending Review cho Quản lý duyệt — không có liên hệ nào tự sinh sau lưng bạn.

Việc theo dõi

Trên biên bản bấm Schedule follow-up, chọn người, việc, hạn. Việc hiện ở My Activities (biểu tượng đồng hồ) của người được giao; đánh dấu xong ở đó.

Tìm lại

  • Meeting Notes: bộ lọc My notes, This week, nhóm theo Year; tìm theo công ty, người hoặc chữ.
  • Companies / Contacts: nút Meeting Notes trên một công ty liệt kê mọi cuộc gặp với công ty đó. Salesperson trên công ty = người phụ trách phía ABB.
  • Legacy Deals: deal từ CRM cũ, chỉ đọc.

Thói quen tốt: mỗi cuộc gặp một biên bản, viết trong ngày; dùng đúng các phần của mẫu, không dán nguyên chuỗi email. Odoo không gửi thư nào tới liên hệ — không có gì bạn gõ tự đi tới khách hàng.

03 · Dữ liệu cũ

Lịch sử PipelineDeals

Dữ liệu cũ được nạp ngày 12/10/2026 sau 22 cổng kiểm chất lượng và một vòng duyệt 100 bản ghi mẫu (0 lỗi nghiêm trọng).


Ghi chú gắn nhãn Legacy (PD)

Các trường gốc chỉ đọc. Legacy Author là người viết trong PipelineDeals; Logged by chỉ đặt cho nhân sự hiện tại, ghi chú của người đã nghỉ và của tài khoản chung "ABB Team" giữ tên. Original Text (PD) giữ nguyên văn bản cũ; 7 ghi chú rất dài đã bị bản xuất cũ cắt (Truncated in Export).

Số điện thoại cần xem lại

Số không đọc được mang thẻ Phone to fix và số gốc ở Original Phone (PD). Số được thêm dấu "+" theo suy luận mang thẻ Phone: + added (inferred). Sửa dần trong lúc dùng.

04 · Trợ lý AI

Claude đọc CRM — không ghi được gì

Claude (ứng dụng Desktop hoặc Claude Code trên máy tính) kết nối CRM qua một máy chủ MCP nhỏ chạy trên chính máy của bạn, đi qua đường hầm bảo mật của Google tới máy chủ CRM. Giao diện web của CRM không mở thêm cổng nào cho việc này.


Quyền

Mỗi người một tài khoản Odoo nhóm Chỉ xem và một khoá API riêng hạn 90 ngày — thu hồi được từng người, nhật ký truy cập theo từng người. Chủ CRM tạo và cài một lần cho bạn.

8 công cụ chỉ đọc

search_companies, get_company, search_contacts, get_contact, search_meeting_notes, get_meeting_note, list_legacy_deals, list_company_groups. Không có công cụ tạo, sửa hay xoá.

Hỏi thế nào

01Tổng hợp quan hệ với một công ty
“Dùng abb-crm: tóm tắt mọi cuộc gặp với công ty [tên công ty] trong 12 tháng qua — ai đã gặp, nội dung chính, việc theo dõi còn mở. Trích ngày và id biên bản cho từng ý.”
02Chuẩn bị trước buổi gặp
“Dùng abb-crm: tôi sắp gặp [tên người] ở [tên công ty]. Liệt kê các lần gặp trước, người phụ trách phía ABB, deal cũ liên quan, và 3 câu nên hỏi tiếp dựa trên ghi chú cũ.”
03Rà danh mục theo nhóm công ty
“Dùng abb-crm: với Company Group [tên nhóm], liệt kê các công ty chưa có cuộc gặp nào từ đầu năm nay, sắp theo lần gặp gần nhất.”

Claude chỉ thấy những gì tài khoản Chỉ xem của bạn thấy, và chỉ khi đường hầm đang mở trên máy bạn. Câu trả lời của AI có thể sai — luôn mở biên bản gốc theo id để kiểm trước khi dùng.

05 · Kho dữ liệu

Mỗi đêm một ảnh chụp đầy đủ của CRM

Kho dữ liệu không đồng bộ từng thay đổi. Mỗi đêm nó chụp toàn bộ 5 bảng nghiệp vụ, gắn ngày chụp (snapshot_date) cho từng dòng và giữ lại mọi ngày. Nhờ vậy bạn hỏi được cả "hôm nay có gì" lẫn "hôm qua khác hôm nay ở đâu", và một đêm lỗi không làm hỏng các đêm trước.

03:30Giờ chạy mỗi đêm (giờ Việt Nam), sau backup 02:00
~1 phútMột lượt: 9.816 dòng + 6.749 cặp quan hệ, bộ nhớ đỉnh ~222 MB
5 bảng · 73 trườngTheo hợp đồng dữ liệu có version, sinh tự động từ Odoo
asia-southeast1Dataset abbmb_dwh ở Singapore, cùng vùng với CRM

05 · Luồng chạy

Từ Odoo tới BigQuery trong năm bước

Toàn bộ chạy trên máy chủ CRM, do một bộ hẹn giờ của hệ điều hành (systemd timer) kích hoạt. Không có máy nào khác tham gia.


Lấy khoáĐọc khoá API của user bot từ Secret Manager vào bộ nhớ tạm riêng của lượt chạy
Kiểm hợp đồngSo trường của Odoo với hợp đồng: trường biến mất → dừng, báo lỗi; trường mới → chỉ ghi log
Đọc OdooContainer Python ghim digest gọi API JSON-2 ngay trên máy (không qua internet), lấy cả bản ghi đã lưu trữ
Nạp BigQueryThư viện dlt thay đúng phân vùng của ngày chụp (xoá rồi chèn), chạy lại cùng ngày không sinh trùng
Tự kiểmGhi _snapshot_check 5/5, dựng lại view; ghi DWH OK hoặc DWH FAIL vào log → email khi lỗi

Không có file khoá nào nằm lại

Khoá Odoo chỉ tồn tại trong thư mục tmpfs của lượt chạy, hệ điều hành tự xoá khi lượt kết thúc. BigQuery xác thực bằng tài khoản dịch vụ của máy chủ qua metadata server — không có file khoá Google nào.

User bot chỉ đọc

Odoo cấp cho kho một user riêng nhóm Chỉ xem, không mật khẩu, một khoá API phạm vi rpc hạn 90 ngày. Đã đo: user này không có quyền ghi, tạo hay xoá trên các model trong hợp đồng dữ liệu; khoá sai trả 401.

Gói Python khoá bằng hash

Môi trường Python dựng một lần từ file lock có hash (74 gói), chỉ nhận bản đóng gói sẵn, không tự biên dịch. Đã thử sửa một hash → cài đặt phải thất bại, và nó thất bại.

Không giữ bản thừa

Dataset trung gian abbmb_dwh_staging được làm rỗng sau mỗi lượt; thư mục làm việc trên máy chủ được dọn sau mỗi lượt OK — vì cả hai đều chứa dữ liệu cá nhân.

06 · Mô hình dữ liệu

Bảng, view và cột

Mọi bảng dữ liệu đều có cột snapshot_date (DATE). Quan hệ nhiều-một (ví dụ công ty của một biên bản) được lưu bằng id số của bản ghi đích. Số dòng là của ảnh chụp 18/10/2026.


BảngModel OdooDòng / ngàyCột chính
res_partnerCông ty + liên hệ5.277id, name, is_company, parent_id, commercial_partner_id, function, email, phone, website, street, city, country_id, industry_id, user_id (người phụ trách), abb_prospect_status, comment, active
abb_meeting_noteBiên bản gặp mặt3.374id, name, date, partner_company_id, raw_company_name, description, follow_up, key_data, user_id, legacy_deal_id, review_pending, is_legacy, legacy_category, legacy_author, legacy_truncated, legacy_raw, active
abb_meeting_attendeeNgười gặp trong biên bản1.033id, note_id, sequence, partner_id, name, function, phone, email, company_name, state, abb_reviewed
abb_legacy_dealDeal cũ PipelineDeals128id, name, partner_company_id, last_stage, currency_id, amount, first_date, last_date, active
abb_company_groupCompany Group4id, name, code, sequence, description, active

Mọi bảng còn có create_date, write_date (TIMESTAMP) và hai cột kỹ thuật của dlt (_dlt_load_id, _dlt_id).

View dựng sẵn — nên dùng thay cho bảng con

ViewCộtDùng để
bridge__res_partner__abb_company_group_idsleft_id = partner, right_id = company group, snapshot_dateCông ty thuộc nhóm nào (một công ty có thể thuộc nhiều nhóm)
bridge__res_partner__category_idleft_id = partner, right_id = thẻThẻ gắn trên liên hệ (ví dụ Phone to fix)
bridge__abb_meeting_note__abb_staff_idsleft_id = biên bản, right_id = user ABBNhân sự ABB dự cuộc gặp
deleted_since_prev__<bảng>id, prev_snapshot_date, snapshot_dateId có ở ảnh chụp hợp lệ trước nhưng biến mất ở ảnh chụp hợp lệ mới nhất (đã xoá hẳn trong Odoo)

View chỉ lấy những ngày mà _snapshot_check ghi ok = true. Bảng con gốc (res_partner__category_id…) nối qua _dlt_parent_id — dùng view thì không cần biết chi tiết đó. Các bảng _dlt_loads, _dlt_pipeline_state, _dlt_version là siêu dữ liệu của dlt, không chứa dữ liệu CRM.

07 · Truy vấn

Ba quy tắc để không đếm sai

Thay PROJECT_ID bằng mã project Google Cloud của CRM (hỏi chủ CRM). Mọi ví dụ chạy được trong BigQuery Studio với vùng asia-southeast1.


Luôn lọc một ngày chụp. Bảng chứa mọi ngày; quên lọc snapshot_date là đếm một công ty nhiều lần.
Chỉ dùng ngày đã tự kiểm ĐẠT — ngày có đủ 5 dòng ok = true trong _snapshot_check.
Lọc active khi cần "hiện tại". Ảnh chụp lấy cả bản ghi đã lưu trữ (archive) để không mất lịch sử.

Ngày chụp hợp lệ mới nhất

-- ngày có đủ 5 bảng và cả 5 đều ok
select snapshot_date
from `PROJECT_ID.abbmb_dwh._snapshot_check`
group by snapshot_date
having count(*) = 5 and logical_and(ok)
order by snapshot_date desc
limit 1;

Số cuộc gặp theo công ty và năm

declare d date default (
  select snapshot_date from `PROJECT_ID.abbmb_dwh._snapshot_check`
  group by 1 having count(*) = 5 and logical_and(ok)
  order by 1 desc limit 1);

select c.name as company,
       extract(year from n.date) as year,
       count(*) as meetings
from `PROJECT_ID.abbmb_dwh.abb_meeting_note` n
join `PROJECT_ID.abbmb_dwh.res_partner` c
  on c.id = n.partner_company_id and c.snapshot_date = d
where n.snapshot_date = d and n.active
group by company, year
order by year desc, meetings desc;

Số công ty trong từng Company Group

declare d date default (
  select snapshot_date from `PROJECT_ID.abbmb_dwh._snapshot_check`
  group by 1 having count(*) = 5 and logical_and(ok)
  order by 1 desc limit 1);

select g.name as company_group, count(distinct b.left_id) as companies
from `PROJECT_ID.abbmb_dwh.bridge__res_partner__abb_company_group_ids` b
join `PROJECT_ID.abbmb_dwh.abb_company_group` g
  on g.id = b.right_id and g.snapshot_date = b.snapshot_date
join `PROJECT_ID.abbmb_dwh.res_partner` p
  on p.id = b.left_id and p.snapshot_date = b.snapshot_date
where b.snapshot_date = d and p.is_company and p.active
group by company_group
order by companies desc;

Biên bản mới hoặc sửa giữa hai ngày chụp

select n.id, n.date, n.name, n.write_date
from `PROJECT_ID.abbmb_dwh.abb_meeting_note` n
where n.snapshot_date = '2026-10-18'
  and n.write_date >= timestamp('2026-10-17 03:30:00', 'Asia/Ho_Chi_Minh')
order by n.write_date desc;

Kết quả truy vấn có thể chứa tên, email, số điện thoại của đối tác. Không xuất ra file cá nhân, không dán vào công cụ AI ngoài, không chia sẻ màn hình kết quả thô. Báo cáo gửi đi nên chỉ chứa số đếm và tên công ty.

08 · Kiểm tra & bảo mật

Kho tự kiểm mỗi đêm và báo khi sai

Một ảnh chụp chỉ được coi là đúng khi, với từng bảng: số dòng = số id khác nhau = số bản ghi Odoo tự đếm được lúc chụp. Kết quả ghi ở _snapshot_check (cột snapshot_date, table_name, model, rows, distinct_ids, expected, ok, checked_at).


Tình huốngHệ thống làm gìBạn thấy gì
Lượt chạy lỗi (mạng, quyền, số đếm lệch)Ghi DWH FAIL, giữ nguyên các ngày cũEmail cảnh báo trong vài phút; ngày hôm đó không có trong view
Quá 26 giờ không có lượt OKKiểm hằng giờ ghi DWH OVERDUEEmail cảnh báo
Odoo mất một trường có trong hợp đồng (sau nâng cấp)Dừng trước khi nạp, mã lỗi riêngEmail; người vận hành sửa hợp đồng
Odoo có trường mới chưa có trong hợp đồngChỉ ghi log DWH NGOAI_HOP_DONG n=…, không chặnKhông có gì — trường mới chỉ vào kho khi hợp đồng được nâng version
Chạy lại cùng ngàyThay đúng phân vùng của ngày đóKhông có dòng trùng

Đã đo trước khi bật trên production

Đúng dữ liệu

Tập id trong BigQuery = tập id đọc thẳng từ PostgreSQL cho từng bảng; tập cặp quan hệ khớp 3/3; xoá 7 bản ghi thử → view báo đúng 7 id.

Ca sai phải đỏ

Bỏ bản ghi lưu trữ, cắt phân trang, nạp chồng thay vì thay thế — cả ba cấu hình sai đều bị tự kiểm bắt và báo lỗi.

Hai đêm liên tiếp

17/10 và 18/10/2026 đều DWH OK, 5/5; diễn tập cảnh báo: log tới trong ~1 giây, email trong vòng 10 phút.

Ai đọc được

  • Hiện chỉ chủ dự án. Thêm một người hay một công cụ BI = một quyết định ghi lại, cấp quyền BigQuery Data Viewer ở mức dataset, không bao giờ ở mức project.
  • Tài khoản dịch vụ của máy chủ chỉ ghi được vào hai dataset của kho, không có vai trò rộng nào ở mức project.
  • Dữ liệu cá nhân được giữ nguyên (không băm, không cắt) theo ý kiến pháp chế; vì thế quyền đọc là lớp bảo vệ chính.

09 · Vận hành

Cho người vận hành CRM

Mọi thay đổi hạ tầng là file trong bộ khung + biến trong file cấu hình tenant, đưa lên bằng script. Không sửa tay trên máy chủ.


ViệcCách làmLịch
Đưa code module lên prodKiểm tra tự động trên máy dev → in kế hoạch → chủ dự án duyệt bằng mã commit → áp dụng; lỗi đường truyền thì dừng, không tự lùiKhi có thay đổi
Đổi code hay hợp đồng DWHKiểm tra tự động → đẩy repo lên máy chủ (cổng duyệt) → dựng lại môi trường Python nếu lock đổi → chạy một lượt → kiểmKhi có thay đổi
Kiểm sức khoẻ DWHLệnh kiểm chỉ đọc: timer, lần OK cuối, _snapshot_check ngày gần nhất 5/5, 0 file khoá ngoài tmpfs, 0 email trong logBất kỳ lúc nào
Xoay khoá API của DWHBackup → sinh khoá mới đi thẳng vào Secret Manager qua ống (không hiện màn hình) → trỏ version mới → kiểmTrước ngày 85 của khoá; lần kế 09/01/2027
Tắt DWHTắt timer, giữ dữ liệu; bật lại bằng một lệnhKhi cần
Lùi hẳn DWHTắt timer → thu hồi khoá trong Odoo → vô hiệu version secret → xoá dataset (chỉ khi chủ dự án duyệt riêng; dữ liệu nguồn vẫn ở Odoo)Khi cần
Billing Google CloudKiểm theo quý; nâng cấp gói trước khi credit dùng thử hếtTrước 15/12/2026

10 · Giới hạn

Những gì kho chưa làm

Biết trước để không hỏi kho một câu nó không trả lời được.


Không có bảng tra tên cho người phụ trách (user_id), quốc gia (country_id), ngành (industry_id), tiền tệ — chỉ có id. Cần tên thì đối chiếu trong CRM, hoặc mở rộng hợp đồng dữ liệu (một version mới).
Chưa có lớp báo cáo. Không có dbt model hay dashboard; file nguồn cho dbt đã được sinh sẵn từ hợp đồng để làm bước đó sau.
Độ trễ một ngày. Kho phản ánh CRM lúc 03:30; việc ghi trong ngày chỉ thấy ở ảnh chụp đêm sau.
Chi phí chưa đo thật. Ước lượng ≈ 0 trong năm đầu (vài GB mỗi năm, dưới mức miễn phí của BigQuery); số đo thật sẽ ghi vào sổ vận hành.
Thời hạn giữ ảnh chụp chưa chốt — sẽ xét cùng các hạn giữ dữ liệu cá nhân khác vào cuối năm 2026.

Một phép đo chỉ có giá trị khi nó cho kết quả khác nhau giữa cấu hình đúng và cấu hình sai — kho dữ liệu này được bật trên production chỉ sau khi cả ba cấu hình sai đều bị bắt.