Quy trình vận hành để Founder tự onboard đối tác Pilot đầu tiên mà không phụ thuộc đội phát triển. Mọi lệnh đã kiểm chứng thật trong Gamma-1. Source of truth = file này (Markdown). Không sửa HTML trực tiếp. Liên quan: Support Playbook · Onboarding Package · Execution Plan.
Ký hiệu
Lệnh CLI chạy tại packages/platform-infrastructure: npm run ops -- <command> [--json] (cần DATABASE_URL trỏ DB tương ứng).
partnerId == customerId. Tenant có vòng đời riêng (xem TENANT-LIFECYCLE).
1. Chuẩn bị trước Pilot
Xác nhận sandbox/staging chạy: GET https://staging-api.booking.bngagency.vn/health → {"status":"ok"}.
Nhận từ đối tác: tên tổ chức, môi trường (sandbox), IP egress (server sẽ gọi API).
Xác định unitId sandbox cho đối tác (vd u_muongthanh_deluxe).
2. Cấp Sandbox (provision partner + tenant + inventory)
npm run ops -- create-partner --name "<Tên đối tác>" --owner founder --json # → partnerId (pending)
npm run ops -- activate-partner --partner <partnerId> # → active
npm run ops -- provision-tenant --partner <partnerId> --tenant <tenantId> --name "<Tên>" --json
npm run ops -- activate-tenant --tenant <tenantId> # → active
npm run ops -- seed-inventory --tenant <tenantId> --json # inventory mẫu (Availability có dữ liệu)
PASS:npm run ops -- tenant-health --tenant <tenantId> --json → status:"active", units > 0, partnerId khớp.
3. Allowlist IP (bắt buộc cho staging)
/api/booking/* trên staging trả 403 nginx nếu IP đối tác chưa được allowlist. Đây là thao tác ops trên VPS (ssh kqxs, sửa allowlist nginx), không thuộc phạm vi thay-đổi-code.
Thêm IP egress của đối tác vào allowlist nginx staging.
Reload nginx.
PASS: từ phía đối tác (hoặc IP đã allowlist): GET /api/booking/availability?...không trả trang 403 HTML của nginx.
Nếu chưa thể allowlist (hoặc muốn tránh đụng staging), có thể chạy Pilot trên sandbox local production-like (xem Execution Plan §Ghi chú) — cùng code/migration/kit.
# Với key vừa cấp + base URL:
curl -s -H "x-bng-api-key: <KEY>" \
"<BASE>/api/booking/availability?unitId=<unitId>&start=2026-09-10&end=2026-09-12&quantity=1&adults=2&children=0"