🇬🇧 English: README.en.md

zca-bridge là sidecar tự host để đồng bộ hội thoại Zalo hai chiều với
Chatwoot. Bridge biến Zalo thành một inbox trong Chatwoot để nhân viên
có thể nhận, gửi, ghi chú và theo dõi lịch sử hội thoại ngay trong helpdesk.
Mặc định tài liệu chính dùng tiếng Việt. Bản tiếng Anh nằm ở README.en.md.
zca-js và đăng nhập QR.
Đây là API không chính thức, có rủi ro khóa hoặc cấm tài khoản./media có token.Node 24+ · TypeScript ESM · Fastify · PostgreSQL · Vitest · Docker
Dự án này độc lập, không thuộc sở hữu, không được tài trợ và không được xác nhận chính thức bởi Zalo, VNG, Chatwoot hoặc nhóm phát triển
zca-js.
Tài khoản Zalo cá nhân được kết nối qua zca-js, một thư viện không chính thức. Dùng API không
chính thức có thể khiến tài khoản Zalo bị hạn chế, khóa hoặc cấm vĩnh viễn. Nên dùng tài khoản phụ,
không dùng tài khoản kinh doanh chính hoặc tài khoản có dữ liệu nhạy cảm.
Kênh Zalo Official Account (OA) dùng API chính thức của Zalo nên không thuộc nhóm rủi ro từ
zca-js. Xem thêm SECURITY.vi.md.
message_map./admin/ để tạo tài khoản admin, cấu hình Chatwoot/OA, thêm inbox, quản lý proxy, quét QR, xem/export log và ẩn cảnh báo đã xử lý.Admin console là UI vận hành chính sau khi bridge chạy. Bộ ảnh dưới đây được chụp từ bản build local
trên http://localhost:4100/admin/ với dữ liệu preview và không chứa secret thật.
| Setup lần đầu | Dashboard |
|---|---|
![]() |
![]() |
| Proxy | Cấu hình | Logs | Mobile |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
zca-js) hoặc Zalo OA webhook/backfill → phân loại message → PostgreSQL
job queue → worker → Chatwoot Application/Platform API./media/:token.CREDENTIALS_KEY.src/zalo — adapter Zalo cá nhân, phân loại message, session, đăng nhập QR, supervisor tự kết nối lại và định tuyến proxy.src/zalo-oa — OA OAuth, webhook, sender, backfill, verify chữ ký, nén ảnh.src/chatwoot — client, Application API, webhook server, tạo inbox.src/handlers — orchestration inbound/outbound, note lỗi, đồng bộ contact info.src/worker và src/store — queue bền, repository (gồm proxy), migration.src/admin — admin API, đăng nhập, settings, webhook info, proxy CRUD, log dashboard.src/media — archive và link media token hóa.PUBLIC_BASE_URL phải là URL bridge có thể truy cập từ bên ngoài khi dùng webhook/OA/iframe.Copy .env.example thành .env rồi điền giá trị thật:
cp .env.example .env
Các biến tối thiểu:
DATABASE_URL — PostgreSQL riêng của bridge.CHATWOOT_BASE_URL — URL Chatwoot mà bridge truy cập được.CREDENTIALS_KEY — khóa hex 32 byte để mã hóa secret, tạo bằng openssl rand -hex 32.PUBLIC_BASE_URL — URL public của bridge, ví dụ https://bridge.example.com.Biến nên cấu hình thêm:
CHATWOOT_API_ACCESS_TOKEN và CHATWOOT_ACCOUNT_ID — cần cho tạo inbox tự động, import tin tự gửi
từ app Zalo và ghi private note khi outbound fail vĩnh viễn.WEBHOOK_SECRET — thêm secret vào URL webhook Chatwoot.MEDIA_ARCHIVE_ROOT, MEDIA_TOKEN_TTL_DAYS, CHATWOOT_MAX_ATTACHMENT_MB — kiểm soát lưu trữ media.ZALO_OA_APP_ID, ZALO_OA_APP_SECRET, ZALO_OA_SECRET_KEY, ZALO_OA_OAUTH_REDIRECT — chỉ cần khi dùng OA.Không commit .env, token thật, app secret, session Zalo hoặc database dump.
Tải docker-compose.full.yml, chuẩn bị .env, rồi chạy:
cp .env.example .env
docker compose -f docker-compose.full.yml up -d
Bridge chạy ở http://localhost:4000. File compose này chạy kèm PostgreSQL riêng cho bridge và pull
image ghcr.io/diendh/zca-bridge:latest.
cp .env.example .env
docker compose -f docker-compose.example.yml up -d --build
File compose mẫu chỉ chạy bridge và PostgreSQL của bridge. Bạn vẫn cần Chatwoot riêng và trỏ
CHATWOOT_BASE_URL tới Chatwoot đó.
docker run --env-file .env -p 4000:4000 ghcr.io/diendh/zca-bridge:latest
Khi chạy container đơn, DATABASE_URL và CHATWOOT_BASE_URL phải trỏ tới dịch vụ truy cập được từ
container.
npm ci
npm run build
mkdir -p dist/store/migrations dist/admin/public
cp src/store/migrations/*.sql dist/store/migrations/
cp -r src/admin/public/. dist/admin/public/
npm start
npm run build chỉ biên dịch TypeScript; các lệnh cp đưa SQL migration và admin UI tĩnh vào
dist giống Dockerfile. Migration tự chạy khi khởi động. Bridge lắng nghe trên $PORT, mặc định là
4000.
Chạy dev mode:
npm run dev
PUBLIC_BASE_URL/admin/ hoặc http://localhost:4000/admin/.CHATWOOT_BASE_URL, Chatwoot account id/token và cấu hình OA nếu dùng.Hai tính năng này chỉ áp dụng cho tài khoản Zalo cá nhân (zca-js); kênh OA không bị ảnh hưởng.
Proxy theo từng tài khoản. Trong tab Proxy của admin, bạn khai báo danh sách proxy (giao thức
http, https hoặc socks5, kèm host, port và tùy chọn user/mật khẩu). Mật khẩu proxy được mã hóa
khi lưu và API không trả mật khẩu thô. Mỗi tài khoản cá nhân có thể gắn một proxy để toàn bộ lưu lượng
websocket và HTTP của tài khoản đó đi qua IP riêng — hữu ích khi muốn tách IP cho mỗi tài khoản. Khi
bạn đổi proxy của một tài khoản đang chạy, tài khoản hiển thị nhãn "Cần áp dụng proxy"; bấm "Áp
dụng proxy" để bridge kết nối lại qua proxy mới. Xóa một proxy đang được dùng sẽ yêu cầu xác nhận và
tự gỡ proxy khỏi các tài khoản liên quan.
Tự động kết nối lại. Khi phiên zca-js của một tài khoản cá nhân bị rớt, supervisor sẽ tự tạo lại
phiên với backoff lũy thừa (5s, 15s, 45s, 2 phút, tối đa 5 phút). Trong lúc này tài khoản ở trạng thái
"Đang kết nối lại…". Lỗi mạng hoặc lỗi proxy được coi là tạm thời và sẽ retry. Chỉ khi lỗi cho thấy
phiên/đăng nhập hết hạn thật, tài khoản mới chuyển sang trạng thái cần quét QR lại thủ công.
Log vận hành. Dashboard hiển thị cảnh báo/lỗi gần đây; operator có thể đánh dấu cảnh báo là đã xử lý để ẩn khỏi summary. Tab Logs vẫn cho phép lọc, copy hoặc export JSON để debug.
npm test
Bộ test dùng Vitest. Nếu test liên quan sharp báo không load được module, chạy lại npm ci để cài
dependency native/optional đúng nền tảng rồi chạy test lại.
Một số test repository cần TEST_DATABASE_URL; khi biến này không có, các test đó được skip có chủ ý.
Kiểm tra local gần nhất trên code hiện tại: 71 test file pass, 7 test file skip có chủ ý; 440 test
pass, 29 test skip. Xem ROADMAP.vi.md để biết lộ trình hiện tại.
Codex được dùng như một trợ lý maintainer cho các việc có thể kiểm chứng bằng code và test:
CREDENTIALS_KEY phải là 64 ký tự hex và được giữ riêng theo môi trường.CREDENTIALS_KEY.PUBLIC_BASE_URL, đặc biệt khi expose /admin/, /webhooks/* và /media/*.WEBHOOK_SECRET cho Chatwoot webhook và ZALO_OA_SECRET_KEY để xác thực webhook OA.rg hoặc secret scanner để đảm bảo chỉ có placeholder/tên biến.Dự án tích hợp với Chatwoot, Zalo và
zca-js. Tất cả tên thương hiệu, logo, nhãn hiệu và tên sản
phẩm thuộc về chủ sở hữu tương ứng; việc nhắc đến chỉ để mô tả tích hợp kỹ thuật.
Copyright 2026 Tom.
Phát hành theo Apache License 2.0.
$ claude mcp add zca-bridge \
-- python -m otcore.mcp_server <graph>