Sheet 9 · System Messages, Security & API Reference

Phụ lục & Hệ thống

Tài liệu tra cứu kỹ thuật toàn diện cho CTC ERP: Từ điển thông điệp hệ thống chuẩn hoá (IEM/EM/SM/CM), danh mục 60+ API Endpoints trong sync-server, quy tắc bảo mật Whitelist relay, và cơ chế đồng bộ realtime SSE dạng Revision Blob.

1. Từ điển Thông điệp Hệ thống (System Messages)

Toàn bộ thông điệp giao diện và lỗi nghiệp vụ được định danh theo mã chuẩn: IEM (Lỗi inline tại trường dữ liệu) · EM (Lỗi thao tác nghiệp vụ) · SM (Thông báo thành công) · CM (Hộp thoại xác nhận thao tác).

1.1. IEM — Inline Error Messages (Lỗi trường nhập liệu)

Quy trìnhNội dung thông điệp tiếng ViệtTiêu chí kích hoạt
IEM1Tạo TaskTiêu đề công việc không được để trống hoặc chỉ chứa khoảng trắng.Độ dài chuỗi title.trim().length === 0
IEM2Tạo Task / Dự ánHạn hoàn thành (Due date) phải bằng hoặc sau ngày bắt đầu.dueDate < startDate
IEM3Toàn hệ thống (*)Trường này là bắt buộc, vui lòng không bỏ trống.Thiếu trường bắt buộc (Mandatory) lúc blur/submit
IEM4Hoá đơn / Đối tácMã số thuế không đúng định dạng (10 số hoặc 13 số).Regex kiểm tra MST doanh nghiệp Việt Nam
IEM5Chốt DealGiá trị hợp đồng (dealValue) phải là số dương lớn hơn 0.dealValue <= 0 khi chuyển sang won
IEM6Đổi mật khẩuMật khẩu mới phải có ít nhất 8 ký tự, bao gồm cả chữ và số.Validation mật khẩu tài khoản cá nhân

1.2. EM — Operation Error Messages (Lỗi nghiệp vụ)

Quy trìnhNội dung thông điệp tiếng ViệtTiêu chí kích hoạt
EM1Lưu dữ liệu (*)Không thể lưu — vui lòng kiểm tra lại các trường dữ liệu được đánh dấu đỏ.Client validation thất bại trước khi gửi request
EM2Đồng bộ RealtimeXung đột phiên bản dữ liệu (Optimistic Lock). Đang tự động tải lại bản mới nhất...Mã lỗi 409 Conflict khi clientRev !== serverRev
EM3Phân quyền RBACBạn không có quyền truy cập module này. Vui lòng liên hệ Admin cấp quyền.Tài khoản member không có mã module trong modules[]
EM4Duyệt chi NCCKhoản chi vượt quá 5.000.000đ yêu cầu phải có phê duyệt từ Ban Giám đốc.Tài khoản không phải Admin duyệt chi lớn
EM5Relay WebhookDomain webhook không nằm trong danh sách an toàn (Whitelist). Gửi thất bại.Domain không khớp whitelist bảo mật của server

1.3. SM — Success Messages (Thông báo thành công)

Quy trìnhNội dung thông điệp tiếng ViệtGhi chú
SM1Tạo TaskĐã tạo công việc <Mã task> thành công.Hiển thị toast và focus thẻ task mới
SM2Chốt DealChúc mừng! Đã chuyển Deal sang trạng thái THẮNG (Won) và khởi tạo Dự án.Kích hoạt workflow thông báo Telegram
SM3Xuất Hoá đơnĐã phát hành hoá đơn <Số HĐ> thành công. Đã cập nhật công nợ AR.Ghi nhận vào sổ hoá đơn GTGT
SM4Ghi nhận tiềnĐã ghi nhận thanh toán <Số tiền> vào sổ tài chính công ty.Tự động sinh Transaction income
SM5Review ThreadĐã đánh dấu hoàn tất (Resolved) phiên thảo luận review.Ẩn pin khỏi màn hình active

1.4. CM — Confirmation Messages (Hộp thoại xác nhận)

Quy trìnhNội dung câu hỏi xác nhậnMục đích
CM1Xoá bản ghiBạn có chắc chắn muốn xoá bản ghi này? Thao tác này sẽ được ghi vào nhật ký hệ thống.Chống bấm nhầm mất dữ liệu
CM2Đóng Dự ánXác nhận nghiệm thu và đóng dự án <Tên DA>? Hồ sơ sẽ chuyển sang chế độ Chỉ-đọc.Khoá chỉnh sửa sau nghiệm thu
CM3Duyệt chi > 5trXác nhận phê duyệt thanh toán <Số tiền> cho NCC <Tên Vendor>?Kiểm soát dòng tiền của BOD
CM4Duyệt Dev RequestPhê duyệt yêu cầu phát triển <Mã YC> và chuyển sang trạng thái triển khai?Admin phê duyệt tính năng

1.5. Thông điệp MÁY CHỦ trả về — bảng tra khi gặp lỗi

Khác các bảng 1.1–1.4 ở trên: những bảng đó là đặc tả thông điệp giao diện (mã IEM/EM/SM/CM, dùng khi thiết kế và kiểm thử). Bảng này là chuỗi thật trích nguyên văn từ sync-server/*.js ngày 03/09/2026 — thứ người dùng thấy khi có lỗi, và thứ tra được khi cần biết vì sao. Cột "Xử lý" là việc cần làm, không phải mô tả lỗi.

Phân quyền & quyền chủ sở hữu

Thông điệpMã HTTPNguyên nhân & xử lý
Chỉ chủ sở hữu hệ thống (Owner) mới được thay đổi phân quyền người dùng.403Tài khoản là admin nhưng không nằm trong ERP_OWNERS. Quản trị và chủ hệ thống là hai tầng khác nhau — xem trang Vai trò.
Không đổi được tên đăng nhập của tài khoản chủ sở hữu — quyền tối cao gắn với tên này.400Quyền owner suy từ username khớp ERP_OWNERS, nên đổi tên là mất quyền. Muốn đổi thì sửa env trước.
Không hạ quyền hoặc khoá tài khoản chủ sở hữu.400Chốt chống tự khoá mình ra ngoài hệ thống.
Không xoá được tài khoản chủ sở hữu hệ thống.400Như trên.
phải còn ít nhất 1 admin · phải còn ít nhất 1 admin đang hoạt động400Không thể hạ hoặc khoá người quản trị cuối cùng.
thiếu quyền module <tên>403Tài khoản chưa được cấp phân hệ đó. Cấp ở Cài đặt → Người dùng & phân quyền.
bạn chỉ được xem kỹ năng này403Được chia sẻ ở mức Xem, không phải mức Sửa. Nhờ chủ sở hữu nâng mức, hoặc nhân bản thành của mình.
chỉ người tạo được sửa · chỉ người tạo được xoá403Quy trình và kỹ năng đi theo chủ sở hữu, kể cả quản trị cũng không sửa hộ.

Đường trợ lý ngoài (/api/agent/*)

Thông điệpMã HTTPNguyên nhân & xử lý
khoá dịch vụ không hợp lệ401Thông điệp hay gây hiểu sai nhất. Gần như luôn là $ERP_API_KEY rỗng, không phải khoá hỏng — mỗi lệnh shell là một tiến trình riêng, nạp khoá ở lệnh này rồi dùng biến ở lệnh sau là mất. Kiểm bằng echo ${#ERP_API_KEY}: ra 71 là khoá có, ra 0 là workspace chưa có khoá.
ERP chưa cấu hình ERP_AGENT_KEY503Khoá dịch vụ chung không đặt trên production (có chủ đích). Dùng khoá theo người dùng, cấp ở Cài đặt → Khoá API.
Hành động "<tên>" không có. Dùng: viec, tim, help, them, xong, trangthai, han, tao_ky_nang, tao_quy_trinh.400Bảng hành động là allowlist. Thông điệp tự liệt kê tên hợp lệ nên trợ lý sửa được ngay mà không cần tra tài liệu.
Tài khoản <tên> chưa được cấp phân hệ "<phân hệ>" nên không dùng được lệnh "<lệnh>".403Kèm trường missingModule để trợ lý báo lại đúng việc cần xin — thay vì im lặng trả danh sách rỗng khiến người dùng tưởng mình không có việc nào.
Đã tạo quá 40 bản nháp trong 24 giờ. Thử lại ngày mai.429Hạn tính theo người, không theo khoá — một người nhiều khoá vẫn là một người.
rate_limited429Quá 120 lượt/phút trên một khoá, hoặc 300 lượt/phút từ một IP. Đợi rồi thử lại, đừng lặp ngay.
Bản nháp không phải JSON hợp lệ · Bản nháp phải là một object JSON · Bản nháp quá lớn (giới hạn 32KB)200 (ok:false)Tham số arg của tao_ky_nang/tao_quy_trinh phải là chuỗi JSON, không phải object.
Bản nháp thiếu trường "name".200 (ok:false)Trường bắt buộc duy nhất. Thiếu trường khác thì bỏ qua — bản ghi là nháp, người dùng sửa tiếp.
Mã không đúng hoặc đã dùng · Mã đã hết hạn (sống 10 phút) · Thử quá nhiều lần, đợi 10 phút.200 / 429Liên kết Telegram bằng mã 6 số: sống 10 phút, 5 lần thử mỗi 10 phút theo cặp (khoá, tgUserId).
Telegram này chưa liên kết tài khoản ERP200 (needLink)Chỉ xảy ra ở đường khoá dịch vụ chung. Khoá theo người dùng đã mang sẵn danh tính nên không cần liên kết.

Giới hạn kích thước & hạn mức

Thông điệpMã HTTPNgưỡng thật
ảnh quá lớn (giới hạn 8MB)413Hình nền (/api/wallpaper) — ảnh điện thoại thường 3–6MB nên nắp thấp hơn là chặn oan.
ảnh quá lớn (>3MB sau khi nén)413Ảnh đính vào Yêu cầu phát triển.
ảnh đại diện quá lớn (>64KB)413Ảnh hồ sơ, lưu thẳng trong bản ghi nên phải nhỏ.
File vượt quá giới hạn 25MB413Tệp Thư viện.
Đã vượt hạn mức lưu trữ 2GB của tài khoản. Hãy xoá bớt file cũ.413Tổng dung lượng Thư viện mỗi người.
nội dung quá lớn (>200KB) · quy trình quá lớn · nội dung quá lớn413Lần lượt: nội dung chung, def quy trình (64KB), def kỹ năng (128KB).
Quá 60 lượt tải lên trong 1 giờ · Bạn đã tải quá nhiều ảnh trong 1 giờ · Quá 10 lần tạo mã trong 1 giờ429Hạn theo người theo giờ, giữ trong bộ nhớ tiến trình.
Mỗi tài khoản tối đa 10 bot · Mỗi yêu cầu tối đa 10 ảnh400Trần số lượng.

Đăng nhập & phiên

Thông điệpMã HTTPNguyên nhân & xử lý
Sai tài khoản hoặc mật khẩu.401Một câu cho cả hai trường hợp — không tiết lộ username nào tồn tại.
Quá nhiều lần thử, đợi vài phút.429Chống dò mật khẩu.
Mật khẩu hiện tại không đúng · Mật khẩu mới tối thiểu 8 ký tự400Đổi mật khẩu: 5 lần / 10 phút.
tài khoản ERP không hợp lệ hoặc đang bị khoá200 (ok:false)Tài khoản có active=0. Cũng là lý do quy trình tự tắt nếu chủ sở hữu bị khoá.
Hai thông điệp còn trong mã nhưng người dùng không còn đường tới: "Chỉ quản trị viên (Admin) mới có quyền truy cập cài đặt AI Gateway""Chỉ chủ sở hữu hệ thống (Owner) mới được đổi cài đặt AI Gateway". Endpoint /api/ai-gateway vẫn tồn tại vì aiProvider(t) đọc cấu hình khoá HTTP từ đó cho các endpoint nội dung bất động sản, nhưng tab "Cài đặt AI" đã gỡ khỏi giao diện 03/09/2026 — nên hai câu này chỉ xuất hiện nếu ai đó gọi API trực tiếp.

2. Danh mục API Endpoints (sync-server)

Tất cả API chạy trên Node.js backend port 4114, xác thực qua Cookie phiên ode_sess (HMAC SHA-256, khoá ký dẫn xuất theo tenant nên cookie tenant A không dùng được ở tenant B) và cách ly theo Tenant Slug. Riêng nhóm /api/agent/* xác thực bằng header X-Agent-Key, không dùng cookie.

Về con số: server.js103 chỗ kiểm req.method === '…', nhưng một path thường được kiểm nhiều lần cho nhiều method nên đó KHÔNG phải số endpoint riêng biệt. Bản tài liệu trước ghi "60+" theo một cách đếm khác — nay nêu rõ cách đếm thay vì đưa một con số dễ hiểu sai.

MethodEndpoint PathQuyền hạnMô tả chức năng
POST/api/loginPublicĐăng nhập hệ thống, cấp cookie ode_sess có chữ ký HMAC SHA-256.
POST/api/logoutPublicĐăng xuất, xoá cookie phiên làm việc.
GET/api/mePublic / AuthLấy thông tin tài khoản hiện tại, vai trò và danh sách modules[] được cấp.
GET/api/auth/verifyPublicEndpoint cho Caddy forward_auth kiểm tra hợp lệ của phiên đăng nhập.
POST/api/me/passwordUserNgười dùng tự đổi mật khẩu tài khoản cá nhân.
GET/api/stateUserLấy toàn bộ JSON snapshot state mới nhất của tenant (theo rev hiện tại).
PUT/api/stateUserGhi đè snapshot state mới, tăng rev, tự động diff changelog và broadcast SSE.
GET/api/eventsUserKênh Server-Sent Events (SSE) đẩy sự kiện realtime (state_update, mention...).
GET/api/changesUserTruy vấn lịch sử các thay đổi dữ liệu giữa các revision (phục vụ System Log).
GET/api/me/dataUserLấy dữ liệu per-user từ bảng user_data (10 key whitelist: theme, quotes, mail...).
PUT/api/me/dataUserLưu dữ liệu per-user (giới hạn dung lượng ≤ 256KB/key).
GET/api/workflowsUserLấy danh sách các workflow tự động hoá thuộc quyền sở hữu hoặc được chia sẻ.
POST/api/workflowsUserTạo mới quy trình tự động hoá (React Flow JSON canvas).
PUT/api/workflows/:idOwner/AdminCập nhật cấu hình trigger, condition và action của workflow.
DELETE/api/workflows/:idOwner/AdminXoá quy trình tự động hoá.
GET/api/workflow-runsUserXem lịch sử các lần chạy tự động hoá và log thực thi.
GET/api/skillsUserLấy danh sách sổ tay kỹ năng và SOP chuẩn hoá.
POST/api/skillsUserTạo kỹ năng mới hoặc import từ file Markdown có sẵn.
PUT/api/skills/:idOwner/AdminCập nhật nội dung kỹ năng, checklist và nâng version.
DELETE/api/skills/:idOwner/AdminXoá kỹ năng.
GET/api/requestsUserXem danh sách đề xuất phát triển kỹ năng/quy trình mới.
POST/api/requestsUserGửi yêu cầu phát triển mới.
POST/api/requests/reviewAdminAdmin duyệt/từ chối yêu cầu qua 5 trạng thái new→reviewing→approved→released.
POST/api/lead-ingestPublic / TokenTiếp nhận Lead từ bên ngoài (HubSpot, Form, Landing Page).
POST/api/me/relay/telegramUserGửi tin nhắn thông báo ra bot Telegram (kiểm tra token an toàn).
POST/api/me/relay/gwsUserGửi webhook sang Google Workspace / Zapier (kiểm tra Whitelist).
POST/api/viber/webhookPublicTiếp nhận webhook tin nhắn từ kênh Viber/Zalo.
GET/api/library/itemsUserLấy danh sách tài liệu, liên kết và tệp trong Thư viện chung.
POST/api/library/itemsUserTạo liên kết mới (tự bóc metadata link) hoặc upload tệp đính kèm (≤ 25MB).
GET/api/library/boardsUserLấy danh sách các Board phân loại tài liệu.
POST/api/library/boardsAdminTạo Board chia sẻ tài nguyên mới.

Nhóm mới / thay đổi trong tháng 9/2026

MethodEndpointQuyềnMô tả
POST/api/agent/whoamiX-Agent-KeyKhoá này đại diện cho ai, còn hiệu lực không
POST/api/agent/contextX-Agent-KeyTrả system + context (đã lọc hai tầng) + actions + keySkills
POST/api/agent/actionX-Agent-KeyThực thi 1 trong 9 hành động allowlist; tên ngoài danh sách → 400
POST/api/agent/linkX-Agent-KeyLiên kết Telegram với tài khoản ERP bằng mã 6 số (sống 10 phút, 5 lần thử/10 phút)
GET / POST/api/api-keysĐăng nhập; cấp cho người khác cần ownerDanh sách và cấp khoá API. Bản rõ trả về một lần duy nhất
POST/api/api-keys/revokeChủ khoá hoặc ownerThu hồi khoá, hiệu lực tức thì
GET / POST/api/api-keys/by-skillChủ sở hữu kỹ năngPhát hành / gỡ kỹ năng khỏi skill_ids của từng khoá
POST/api/me/sessions/revoke-allOwnerTăng session_ver toàn tenant → mọi phiên đang có mất hiệu lực
POST/api/wallpaperĐăng nhậpTải ảnh nền từ máy (multipart, ≤8MB, jpg/png/webp/gif/avif)
GET/api/wallpaper/<tệp>Chỉ chính chủ ảnhXem ảnh nền; tên tệp mang id người tải, admin cũng không xem được ảnh người khác
POST/api/skillsChủ sở hữu, hoặc người được chia sẻ mức SửaNgười mức Sửa ghi được nội dung; sharedWith/sharedEdit/published họ gửi lên bị bỏ qua
POST/api/workflowsChủ sở hữuVá 03/09: active chỉ đổi khi người gọi thực sự gửi trường đó
Đã gỡ 03/09/2026: POST /api/ai-draft (sinh bản nháp bằng CLI mô hình), khối /api/bots/ai-models, POST /api/bots/inbound. Xem trang Quy trình mục 5b để biết lý do.

3. Quy tắc Bảo mật Whitelist Relay & An toàn Dữ liệu

Bảo mật Tích hợp Ngoài (Relay Whitelist):
Để ngăn ngừa tấn công SSRF (Server-Side Request Forgery), endpoint /api/me/relay/gws chỉ chấp nhận chuyển tiếp request tới các domain trong danh sách Whitelist cứng:
  • script.google.com & *.googleusercontent.com (Google Apps Script Web Apps)
  • chat.googleapis.com (Google Chat Webhooks)
  • hooks.zapier.com (Zapier Integration)
  • api.telegram.org (Telegram Bot API)
Mọi URL trỏ tới dải IP private (127.0.0.1, 10.x, 192.168.x) hoặc domain lạ đều bị từ chối ngay lập tức với mã lỗi HTTP 403 Forbidden.

4. Cơ chế Đồng bộ Realtime SSE & Revision Blob

Hệ thống áp dụng kiến trúc Optimistic State Sync kết hợp Server-Sent Events (SSE):

  1. Single Source of Truth: Toàn bộ state nghiệp vụ của 1 tenant được gói trong 1 JSON document lưu trong bảng revisions (rev, state_json, author_id, created_at).
  2. Optimistic Locking: Khi client gửi PUT /api/state kèm expectedRev:
    • Nếu expectedRev === currentRev: Server ghi snapshot mới với rev = currentRev + 1, diff ra danh sách bản ghi thay đổi và broadcast SSE sự kiện state_update tới tất cả các client khác.
    • Nếu expectedRev < currentRev: Server trả về mã lỗi 409 Conflict. Client nhận lỗi sẽ tự động kéo state mới về, thực hiện 3-way merge và thông báo cho người dùng nếu có xung đột trường.
  3. Materialized Views: Để phục vụ truy vấn báo cáo và REST API nhanh, server tự động giải nén JSON blob thành các dòng trong 9 bảng SQLite (tasks, contacts, activities, projects, events, invoices, transactions, notifications, users). Nguồn sự thật tuyệt đối vẫn là blob trong bảng revisions.
  4. Giới hạn Lịch sử: Bảng revisions lưu tối đa 1.000 phiên bản gần nhất để tối ưu dung lượng ổ đĩa; định kỳ hàng tuần server chạy lệnh VACUUM INTO để nén file SQLite dự phòng an toàn.

5. Hạ tầng, triển khai & kiểm thử (cập nhật 03/09/2026)

Toàn bộ mục này là mới — hệ thống đã chuyển sang VPS riêng trong ngày 03/09/2026 và cách triển khai không còn giống bản tài liệu trước.

5.1 Máy chủ và đường dẫn thật

Hạng mụcGiá trị
SSH hostctc-erp (unix user erp). Ngoài ra ctc = root, ctc-smarttech, ctc-kazuki cho các user khác trên cùng máy.
Mã nguồn/home/erp/erp-platform (production) · /home/erp/erp-staging (thử nghiệm)
Cơ sở dữ liệu/home/erp/erp-platform/sync-server/data/tenants/<slug>/crm.db — 4 tenant: ctc, ode, lhbd, journalist, cách ly theo file
PM2erp-next (web) · erp-crm-sync (API :4114) · erp-staging-web · erp-staging-api
Nhật ký/home/erp/erp-platform/logs/erp-crm-sync-out.log. Lọc nhanh: grep '[agent]' cho đường trợ lý, grep '[workflows]' cho việc tạo/sửa quy trình.
Tên miềnProduction ctc.erp.smarttechctc.io · Thử nghiệm staging-erp.smarttechctc.io · Tài liệu erp-docs.smarttechctc.io

5.2 Triển khai — rsync, không phải git

Dự án KHÔNG có remote git. Repo chỉ tồn tại local; mọi đường triển khai đi bằng rsync qua SSH. Không có git clone, không có git pull trên máy đích.
# 1. Đẩy mã nguồn (loại node_modules, dữ liệu và bí mật — xem deploy/rsync-exclude.txt)
./deploy/sync-to-vps.sh ctc-erp erp-platform      # production
./deploy/sync-to-vps.sh ctc-erp erp-staging       # thử nghiệm
DRY=1 ./deploy/sync-to-vps.sh ctc-erp             # xem trước, không ghi gì

# 2. Trên máy đích: build web (tự hoán đổi thư mục build và kiểm BUILD_ID)
cd erp-platform/frontend-next && ./deploy.sh
ERP_WEB_APP=erp-staging-web ./deploy.sh           # bản thử nghiệm

# 3. Sau khi sửa backend
pm2 restart erp-crm-sync

pm2 restart --update-env KHÔNG nạp env mới từ ecosystem — phải pm2 delete rồi pm2 start. Rollback web: rm -rf .next && mv .next-prev .next && pm2 restart erp-next.

5.3 Bộ công cụ trong deploy/

TệpViệc
bootstrap.sh <base-domain>Dựng từ một VPS trắng
sync-to-vps.sh + rsync-exclude.txtĐẩy mã nguồn. Danh sách loại trừ có bẫy: nó từng loại *.png nên nuốt luôn logo trang đăng nhập — nay giữ lại tường minh frontend-next/public/**frontend-next/src/assets/**.
sanitize-tenant.jsLàm sạch một DB trước khi chuyển máy. Chế độ --minimal giữ mật khẩu và khoá API, chỉ xoá bí mật cấu hình và token chia sẻ.
scan-secrets.jsQuét 10 mẫu khoá trên mọi bảng và cả trong blob state; chỉ in vị trí và vân tay, không in giá trị.
caddy-*.exampleMẫu cấu hình Caddy cho từng tenant và cho site tài liệu

5.4 Kiểm thử

20 tệp trong sync-server/test/, 84 test case, chạy bằng node --test sync-server/test/*.test.js — không cần framework ngoài. Nhóm khoá chặt các lỗ hổng đã vá: rbac-escalation, rbac-settings, rbac-endpoints, rbac-data, session-ver, session-salt, tenant-isolation, invoice-number, skill-share (chia sẻ ba mức), agent-draft (trợ lý dựng nháp — gồm một ca ép hai lớp kiểm phân hệ phải khớp nhau), codes (ép hai bản quy tắc mã khớp nhau).

5.5 Ràng buộc phải giữ

Ràng buộcVì sao
CLIENT_SCHEMA = 14không bumpToàn bộ state client nằm trong một chuỗi JSON lồng {version:14, state:{…}}. Bump là mọi client cũ mất dữ liệu.
shadcn trên Base UI, không RadixComponent viết theo API Base UI (vd ToggleGroup luôn nhận mảng giá trị kể cả khi chọn một). Lẫn sang Radix là vỡ kiểu.
Hai bản quy tắc mã phải khớpfrontend-next/src/erp/lib/codes.ts và bản chép cho script sync-server/migrate-codes.js. Sửa một bên phải sửa bên kia — test/codes.test.js ép điều đó.
Hai tầng lọc ở mọi đường đọcscopeStateForUser(filterStateForUser(inner, actor), actor). Thiếu tầng hai là rò dữ liệu cả công ty.
ERP không chạy CLI mô hìnhXem trang Quy trình mục 5b.