Wave 1 · Chat-driven actions · 2026-05-03

Thử các tình huống chat thực tế.

Mỗi tình huống dưới đây ứng với 1 luồng tính năng đã ship. Mở widget chat ở trang chủ timviecviva.vn hoặc /tro-ly-ai, gõ thử các câu mẫu, đối chiếu kết quả với cột "Mong đợi". Thiếu gì báo cho ops.

⚠️
Lưu ý: Chat ở floating widget chạy ở chế độ guest (anonymous) — chỉ thấy được job_search, parse_search_intent, should_capture_lead. Để thử application_status, save_job, create_saved_search phải đăng nhập worker (qua OTP) trước.
TC-01

Auto-apply khi verify OTP — funnel rút gọn

WRITE Không cần đăng nhập trước phase 01
Câu mẫu (gõ trong chat)
  • Tìm việc Goertek Bắc Ninh lương 12 triệu
  • (sau khi AI show JobCard) Mình muốn ứng tuyển việc này
  • (chip "Để lại SĐT" hiện) → click chip
  • (modal OTP mở) → nhập SĐT thật + OTP
Mong đợi
  • Sau intent ứng tuyển, AI emit lead_signalprefill.job_id
  • Chip "Để lại SĐT" hiện trong ≤500ms
  • OTP verify thành công → 1 dòng job_applications mới với utm_source='ai_chat_lead', status='pending'
  • Response body có application_id ≠ null
  • Slack #lead channel nhận message (nếu có cấu hình SLACK_LEAD_WEBHOOK_URL)
  • Không tạo Worker thứ 2 nếu SĐT đã tồn tại (idempotent)
  • Đơn thứ 16/ngày → 422 "Bạn đã ứng tuyển tối đa 15 việc hôm nay"
TC-02

Hỏi trạng thái đơn ứng tuyển — ApplicationStatusCard

READ Cần worker JWT phase 02
Câu mẫu
  • Đơn của tôi sao rồi?
  • Tôi nộp gì rồi?
  • Trạng thái ứng tuyển
  • Đã apply những gì?
Mong đợi
  • AI tự gọi tool application_status (không phụ thuộc câu chính xác)
  • Card hiện list 10 đơn gần nhất, mỗi row: tên việc, công ty, status badge tiếng Việt (Chờ xét duyệt / Đang xem hồ sơ / Vào danh sách / …)
  • Click row → navigate /ung-tuyen/{id}
  • 0 đơn → AI nói "Bạn chưa có đơn nào, mình giúp tìm việc nhé?" thay vì hiện card rỗng
  • Không leak đơn của worker khác (filter by worker_id từ JWT)
TC-03

Lưu / xem việc đã lưu — SaveJobConfirmCard

WRITE READ Cần worker JWT phase 03
Câu mẫu
  • (sau khi AI show JobCard) Lưu việc này
  • Bookmark Goertek đi
  • Xem việc đã lưu
  • Wishlist của tôi
Mong đợi
  • "Lưu việc này" → AI tham chiếu job_id của JobCard render gần nhất
  • ConfirmCard "Lưu việc {tên}?" với 2 nút Lưu / Hủy hiện trong ≤500ms
  • Click Lưu → API POST /v1/worker/saved-jobs (Sanctum) → state success "✓ Đã lưu" trong ≤2s
  • "Xem việc đã lưu" → JobPickerCard hiển thị danh sách
  • Lưu 1 việc 2 lần → idempotent, không tạo dòng trùng
  • Anonymous user → tool reply error "Bạn cần đăng nhập để lưu việc"
TC-04

Đặt thông báo việc làm tự động — SavedSearchConfirmCard

WRITE Cần worker JWT phase 04
Câu mẫu
  • Báo cho tôi khi Samsung tuyển ở Bắc Ninh
  • Alert tôi việc CNC lương trên 15 triệu
  • Thông báo khi Goertek mở đơn
  • Xem các thông báo đã đặt
  • (trên ListCard) bấm "Tắt" để xóa 1 thông báo
Mong đợi
  • AI gọi parse_search_intent trước → extract {keyword, location, salary_min, industry}
  • ConfirmCard hiện filter rõ ràng tiếng Việt + nút "Tạo thông báo" / "Bỏ qua"
  • Click Tạo → DB saved_searches có 1 dòng mới · cron hourly tự alert khi job mới khớp
  • Cap 3 alert/ngày/saved search (Setting saved_search_alerts_per_day_cap)
  • Max 5 saved search active/worker — vượt quá → 422 friendly
  • "Xem các thông báo đã đặt" → SavedSearchListCard hiển thị label + filter summary + last_alerted_at
  • Bấm "Tắt" trên row → DELETE saved search → row fade out
TC-05

Regression: tính năng cũ vẫn hoạt động

READ Anonymous OK smoke
Câu mẫu
  • Tìm việc CNC ở Bắc Ninh lương 12tr
  • Lương công nhân Goertek bao nhiêu?
  • KCN Quế Võ có việc gì?
  • So sánh việc Samsung và Goertek
Mong đợi
  • job_search trả carousel 2-8 việc / picker list ≥9 việc / single card 1 việc
  • Wiki RAG citation hiện [#W…] khi câu hỏi trùng KB
  • Chat đa lượt: hỏi "Goertek" rồi hỏi "Bắc Ninh" → AI hiểu = Goertek BN
  • F5 / refresh page → chat history còn (localStorage 24h)
  • Anonymous chip "Để lại SĐT" hiện khi conversation thể hiện ý apply

Test xong, ghi nhận gì?

Bug → ghi commit hash + screenshot vào #qa-channel. Pass → tick xanh trong sprint board.