--- title: AI Platform Lead Scoring description: Hành vi dịch vụ chấm điểm lead đồng bộ và ranh giới với client. status: review_ready --- # Lead Scoring Dịch vụ AI scoring dùng chung, không giữ trạng thái nghiệp vụ. Client gửi snapshot lead cùng rules/weights, dịch vụ trả điểm, breakdown, tóm tắt, tín hiệu và gợi ý hành động; client tự quyết định phần còn lại (ngưỡng, HITL, CRM writeback). Wire shape do `contracts/lead-scoring/openapi.json` và `fixtures/` xác định; `contracts/lead-scoring/README.md` là tóm tắt cho client. ## Sở hữu - Client (hiện là DotB-Omni) sở hữu user/account, quyền EMS, snapshot, rules, weights, ngưỡng điểm, HITL và CRM writeback. Dịch vụ không biết client cụ thể; dữ liệu riêng của client đi trong `metadata`, được lưu và trả lại nguyên vẹn. - AI Platform xác thực app bằng app key, chấm điểm, lưu lần chấm để replay và để Admin Web xem. Admin Web quản lý AI profile, chạy fixtures, xem runs và thu hồi app access. ## Endpoint `POST /v1/lead-scoring/score`, đồng bộ, trả 200 khi chấm xong. - `Authorization: Bearer `: thiếu, sai hoặc bị revoke trả 401. - `Idempotency-Key`: UUID bắt buộc. Unique theo `(app_id, idempotency_key)`, kèm SHA-256 của body chuẩn hóa. Cùng key, cùng body trả kết quả đã lưu và không gọi AI lần hai. Cùng key, khác body trả 422. Hai POST đồng thời cùng key chỉ tạo một bản ghi. - `X-AI-Key` (tùy chọn): khóa AI cho profile AIHub, tối đa 4096 ký tự, không CR/LF (sai thì 422). Chỉ giữ trong RAM trong lúc gọi; không lưu, log hay trả về. - Body: `snapshot`, `scoring_config` (`rule_weight`, `ai_weight`, `rules[]`, tổng weight bằng 1), `metadata` (tối đa 10KB). Snapshot tối đa 10 conversations, 50 messages, 20.000 ký tự nội dung, 100KB. Field lạ bị 422. - Rule: `id`, `field`, `operator`, `value`, `points`, `description` tùy chọn (tối đa 99 ký tự, chỉ gửi cho AI làm ngữ cảnh, không đổi kết quả khớp). `field` là `lead_profile.`, `custom_fields.` hoặc `metrics.`. Operator: `eq ne gt gte lt lte contains exists between in`. `between` nhận `[min, max]` số, gồm cả hai đầu. `in` nhận list scalar (1 đến 100 phần tử), so khớp nguyên giá trị. Field sai kiểu thì không khớp, không lỗi. ## Kết quả `run_id`, `final_score`, `rule_score`, `ai_score`, `result_mode`, `error_code`, `breakdown[]`, `ai {summary, suggested_action, signals[]}`, `metrics`, `metadata`. - `ai_weight=0`: `rules_only`, không gọi AI. - `ai_weight>0` và AI thành công: `hybrid`, `final_score = clamp(round(rule_score*rule_weight + ai_score*ai_weight), 0, 100)`. - Thiếu AI key (AIHub), không có profile active, AI lỗi hoặc quá `timeout_seconds`: `rules_only_fallback`, `final_score = rule_score`, `error_code` là `ai_key_missing`, `ai_profile_missing`, `ai_timeout` hoặc mã lỗi provider. Không tự retry. - Lỗi code hoặc DB trả 5xx; DB không sẵn sàng trả 503 với thông báo an toàn. ## AI profile Admin Web lưu AI profile theo revision tự tăng. Lưu tạo revision mới (không active), kích hoạt là bước riêng và kích hoạt revision cũ là rollback. Profile gồm `provider` (`aihub` hoặc `openai_compatible`), `base_url`, `model`, `timeout_seconds` (1 đến 60), `reasoning_effort`, `instructions` (rubric do admin viết), `include_reference_date`, `timezone`, `suggested_action_enabled`. Khung kỹ thuật của prompt nằm trong code. Mỗi run lưu `profile_revision`. Chạy thử một profile nháp không lưu run và không đổi revision active. Đổi URL có hiệu lực ngay, không restart. Một lần gọi AI trả JSON `{signals[], score, summary, suggested_action}`. `base_url` phải qua `safe_http_url`: HTTPS, hoặc HTTP chỉ với loopback ở development, không userinfo, query hay fragment. AIHub dùng khóa trong `X-AI-Key`. OpenAI-compatible dùng `AI_PLATFORM_OPENAI_API_KEY`, chỉ gửi tới `AI_PLATFORM_OPENAI_BASE_URL`. ## Credential và runtime - Một app ID ổn định và một key cho mỗi installation. DB chỉ lưu SHA-256 verifier. Rotate giữ app ID và các run cũ; key cũ hết hiệu lực. Cấp, rotate, revoke qua CLI `create-app`, `rotate-app-key`, `revoke-app-key`; raw key chỉ xuất ở thao tác CLI. Admin session độc lập, password hash, CSRF; Web chỉ list và revoke. - App key và AI key không xuất hiện trong DB, log, response hay lỗi. - Một backend process. Startup đọc migration head, không tự migrate. Schema chưa phát hành là một migration `0001_initial`; database local mang revision cũ cần dựng lại hoặc xử lý riêng. ## Nghiệm thu và chưa xác minh Đã kiểm tra bằng test cục bộ: các chế độ kết quả, replay và xung đột idempotency, truy cập đồng thời, xác thực, hình dạng prompt và request tới provider qua transport giả, contract khớp code, migration khớp models. Chưa xác minh: hành vi AI thật (AIHub, model, `reasoning_effort`, `temperature`, độ trễ, quota), tích hợp Omni/EMS, chất lượng điểm bằng dữ liệu có nhãn, và hạ tầng production (hosting, TLS, secret, backup, alerting, retention). Không tuyên bố production-ready từ kiểm tra cục bộ.