📌 Quyết định scope (PM — 03/07/2026)
DN-004 chỉ còn một flow duy nhất: Quên mật khẩu (self-service). Flow "Mất quyền truy cập email" (admin-assisted) đã bỏ; màn DN-005 Đổi Email đã loại bỏ hoàn toàn (ID retired). Email đăng nhập cố định sau đăng ký. Thành viên không tự phục hồi được (mất email) → liên hệ trực tiếp DN Admin của công ty để được đặt lại mật khẩu (row action 🔑 trong DN-008 — chốt 03/07/2026); riêng DN Owner → support@pccctrace.vn.
1.Tổng quan & phạm vi
Mục đích: Cho phép user quên mật khẩu tự phục hồi mà không cần hỗ trợ: nhập email đăng nhập → hệ thống gửi link đặt lại mật khẩu (token một lần, hiệu lực 15 phút) → user mở link, đặt mật khẩu mới → mọi phiên cũ bị đăng xuất → đăng nhập lại tại DN-003.
Trong phạm vi (In scope)
Form yêu cầu link đặt lại mật khẩu (1 field email duy nhất).
Response generic — không tiết lộ email có tồn tại trong hệ thống hay không.
Trang đặt mật khẩu mới từ link email (route /reset-password?token=... — xem OQ-01 về việc tách ID màn).
Khôi phục khi mất quyền truy cập email — không có UI tự phục hồi: thành viên liên hệ trực tiếp DN Admin công ty, Admin đặt lại mật khẩu qua DN-008 (đăng nhập không cần hộp thư email).
Đổi email đăng nhập (DN-005) — đã loại bỏ hoàn toàn.
Đổi mật khẩu khi đang đăng nhập (thuộc màn cài đặt tài khoản, không phải DN-004).
2.User story & Acceptance criteria
Là nhân sự doanh nghiệp PCCC quên mật khẩu đăng nhập, tôi muốn tự nhận link đặt lại mật khẩu qua email trong vài phút, để quay lại làm việc ngay mà không phải chờ ai hỗ trợ.
ID
Acceptance criteria (Gherkin)
AC-01
Given email đã đăng ký, When submit form, Then hệ thống gửi email chứa link đặt lại mật khẩu (token một lần, hiệu lực 15 phút) và hiển thị màn "Kiểm tra hộp thư".
AC-02
Given email chưa đăng ký, When submit form, Then hiển thị cùng một màn "Kiểm tra hộp thư" (generic — không tiết lộ email tồn tại) và không gửi gì.
AC-03
Given user mở link hợp lệ trong email, When đặt mật khẩu mới đạt yêu cầu (tối thiểu 8 ký tự) và xác nhận khớp, Then mật khẩu cập nhật, mọi phiên và refresh token cũ bị thu hồi, chuyển về DN-003 kèm thông báo thành công.
AC-04
Given link đã dùng hoặc quá 15 phút, When mở link, Then hiển thị "Link đã hết hạn hoặc đã sử dụng" + nút yêu cầu link mới (về DN-004).
AC-05
Given đã yêu cầu link, When bấm gửi lại trong vòng 60 giây, Then bị chặn bởi cooldown; quá 5 yêu cầu/giờ/email → trả lỗi rate limit.
3.Luồng nghiệp vụ
DN-003 "Quên mật khẩu?" ──► DN-004 nhập email ──► POST /auth/forgot-password
│ (luôn trả 202 — generic)
▼
Màn "Kiểm tra hộp thư" (Success state)
│ user mở link trong email (TTL 15 phút, 1 lần)
▼
Trang "Đặt mật khẩu mới" (/reset-password?token=...)
│ mật khẩu mới ×2 + chỉ báo độ mạnh (tái dùng SU-05 DN-001)
▼
POST /auth/reset-password ──► thu hồi mọi phiên cũ ──► DN-003 + toast thành công
4.UI elements
Layout: card căn giữa, max-width 440px (đồng bộ DN-003), nền --neutral. Tham chiếu trực tiếp prototype DN-004 — dùng đúng design tokens trong tokens.css.
4.1 · Form yêu cầu (mặc định)
ID
Thành phần
Loại
Bắt buộc
Hành vi / Ghi chú
FP-00
Icon 🔑 + header
Static
—
Icon tròn nền --primary-soft · H1 "Đặt lại mật khẩu" · lead "Nhập email đăng nhập của bạn — chúng tôi sẽ gửi link đặt lại mật khẩu qua email."
FP-01
Email đăng nhập
Email input
Có
type=email · autocomplete="username" · trim + lowercase trước khi gửi · Enter = submit.
FP-02
Nút "Gửi link đặt lại mật khẩu"
Button primary, full-width
—
Submit → disable + spinner "Đang gửi..." · luôn chuyển sang Success state bất kể email có tồn tại (BR-02).
FP-03
Ghi chú gửi email
Callout nhỏ
—
"Link gửi từ noreply@pccctrace.vn, có hiệu lực 15 phút. Không thấy email? Kiểm tra hộp thư Spam."
Password + toggle 👁 + chỉ báo độ mạnh 3 mức — tái dùng đúng component và rule của DN-001 SU-05 (mục 5.1 spec DN-001).
RP-02
Xác nhận mật khẩu
Phải khớp RP-01, validate on blur + on submit.
RP-03
Nút "Đặt lại mật khẩu"
Submit → thành công: redirect DN-003 + toast "Mật khẩu đã được đặt lại — vui lòng đăng nhập". Token sai/hết hạn → AC-04.
5.Validation & thông báo lỗi
Field
Rule
Thông báo lỗi
FP-01
Rỗng / sai định dạng email (client)
Vui lòng nhập email hợp lệ — banner đỏ + viền đỏ field
FP-01
Server: quá 5 yêu cầu/giờ (429)
Bạn đã yêu cầu quá nhiều lần. Vui lòng thử lại sau {phút} phút
RP-01
<8 ký tự
Mật khẩu tối thiểu 8 ký tự
RP-02
Không khớp RP-01
Mật khẩu xác nhận không khớp
Token
Server: hết hạn / đã dùng / không hợp lệ
Link đã hết hạn hoặc đã được sử dụng. Vui lòng yêu cầu link mới. (+ nút → DN-004)
Form
Server: lỗi 5xx
Toast "Có lỗi xảy ra, vui lòng thử lại" — giữ nguyên dữ liệu đã nhập
Không có lỗi "email không tồn tại"
Submit email chưa đăng ký vẫn hiển thị Success state bình thường (AC-02). Đây là hành vi cố ý — chống dò email (user enumeration), đồng bộ BR-04 của DN-003.
6.Business rules
ID
Quy tắc
Nguồn
BR-01
Token đặt lại mật khẩu: ngẫu nhiên ≥128 bit, dùng một lần, hiệu lực 15 phút, lưu dạng hash (không lưu plaintext). Tạo token mới → vô hiệu token cũ chưa dùng của cùng user.
FR-6a
BR-02
API luôn trả 202 generic bất kể email có tồn tại hay không; thời gian phản hồi đồng đều (chống timing attack).
FR-7
BR-03
Rate limit: cooldown gửi lại 60 giây · tối đa 5 yêu cầu/giờ/email (đồng bộ pattern OTP DN-001 BR-05).
FR-7
BR-04
Đặt lại mật khẩu thành công → thu hồi toàn bộ phiên + refresh token hiện có của user (chống kẻ chiếm phiên giữ quyền truy cập).
BA đề xuất
BR-05
Mật khẩu mới hash bcrypt cost 12 — đồng bộ DN-001 BR-07 / DN-003 BR-01. Mật khẩu mới được phép trùng mật khẩu cũ (không giữ lịch sử mật khẩu ở MVP — đơn giản hoá 30 DN).
FR-4
BR-08
Admin-assisted reset (chốt 03/07/2026): DN Admin/Owner đặt lại mật khẩu cho thành viên role thấp hơn qua DN-008 (🔑): hệ thống tạo mật khẩu tạm ngẫu nhiên hiển thị 1 lần cho Admin chuyển ngoài hệ thống; thành viên buộc đổi mật khẩu ở lần đăng nhập kế; thu hồi mọi phiên cũ như BR-04; ghi audit log (actor_user_id + target_user_id). Owner không tự reset chính mình qua kênh này.
PM 03/07/2026
BR-06
Ghi audit log: yêu cầu reset (email + IP + timestamp, kể cả email không tồn tại — đánh dấu riêng) và reset thành công (user_id, IP).
FR-71
BR-07
Email đăng nhập cố định sau đăng ký — không có UI đổi/khôi phục email (quyết định PM 03/07/2026). Thành viên mất quyền truy cập email → liên hệ trực tiếp DN Admin công ty, Admin đặt lại mật khẩu tạm qua DN-008 (xác minh nội bộ doanh nghiệp); DN Owner → support@pccctrace.vn.
PM 03/07/2026
7.API contract (đề xuất)
7.1 · Yêu cầu link đặt lại mật khẩu
POST /api/v1/auth/forgot-password
{ "email": "anhtuan@hathanhpccc.vn" } // lowercase, trim// 202 Accepted — LUÔN trả giống nhau, có hay không có tài khoản (BR-02)
{ "message": "OK", "resend_cooldown": 60 }
// Lỗi
429 RATE_LIMITED → { "retry_after_seconds": 1800 } // >5 lần/giờ/email
422 VALIDATION_ERROR → email sai định dạng
7.2 · Đặt mật khẩu mới
POST /api/v1/auth/reset-password
{ "token": "rp_9f3k...", "new_password": "********" }
// 200 OK — mật khẩu đã đổi, mọi phiên cũ bị thu hồi (BR-04)
{ "message": "PASSWORD_RESET_OK" }
// Lỗi
400 TOKEN_INVALID | TOKEN_EXPIRED | TOKEN_USED → "Link đã hết hạn hoặc đã được sử dụng"
422 VALIDATION_ERROR → { "errors": { "new_password": "..." } }
8.Trạng thái màn hình (UI states)
State
Mô tả hiển thị
Empty / Default
Form 1 field email trống (placeholder), nút enable, không lỗi.
Loading (skeleton)
Toàn bộ card thay bằng skeleton shimmer khớp layout (icon tròn, title, lead, field, nút, ghi chú, footer) — dùng khi trang đang tải.
Error
Banner đỏ "Không thể gửi yêu cầu. Vui lòng kiểm tra lại email bên dưới." + viền đỏ field + lỗi inline "Vui lòng nhập email hợp lệ"; giữ nguyên giá trị đã nhập, focus field.
Icon 📬 "Kiểm tra hộp thư của bạn" + thông điệp generic + dòng "Gửi lại sau {n}s" + nút quay lại đăng nhập.
Khối demo "State & Spec" trong prototypedn-004-recovery-request-mockup.html có khối "State & Spec" ở góc phải dưới: preview Loading / Empty / Error / Đã gửi link (bấm lại nút đang active để về default) + link mở file spec này. Khối này chỉ phục vụ review prototype — không build vào production.
9.Yêu cầu phi chức năng
Bảo mật: HTTPS bắt buộc; token hash trong DB; response đồng đều (BR-02); không log token/mật khẩu; link email dạng HTTPS tuyệt đối tới app.pccctrace.vn.
Email delivery: gửi trong ≤60 giây; sender noreply@pccctrace.vn có SPF/DKIM/DMARC để tránh rơi Spam.
Accessibility: label gắn for/id; lỗi có aria-describedby + aria-invalid; focus ring rõ.
Ngôn ngữ: 100% tiếng Việt, kể cả nội dung email.
Đơn giản hoá: quy mô 30 DN — không captcha; rate limit theo email + IP là đủ.
10.Edge cases
ID
Tình huống
Xử lý
EC-01
User yêu cầu nhiều link liên tiếp
Token mới nhất vô hiệu mọi token cũ chưa dùng (BR-01); email cũ mở ra sẽ báo hết hạn.
EC-02
User đang khoá đăng nhập tạm (sai 5 lần ở DN-003) yêu cầu reset
Vẫn cho reset bình thường — reset thành công thì gỡ khoá (mật khẩu mới chứng minh sở hữu email).
EC-03
Tài khoản thuộc tenant pending_kyc / rejected
Vẫn reset được mật khẩu; sau đăng nhập điều hướng theo kyc_status như DN-003 BR-05.
EC-04
User mở link trên thiết bị/trình duyệt khác với nơi yêu cầu
Hoạt động bình thường — token không gắn thiết bị (đơn giản hoá MVP).
EC-05
Email scanner của doanh nghiệp tự mở link (pre-fetch) làm token bị "dùng"
Token chỉ tính "đã dùng" khi submit mật khẩu mới thành công, không phải khi mở trang (GET không đốt token).
EC-06
User quên mật khẩu nhưng cũng mất quyền truy cập email
Không tự phục hồi được — liên hệ trực tiếp DN Admin công ty để được đặt lại mật khẩu tạm (BR-08; đăng nhập không cần hộp thư). DN Owner rơi vào tình huống này → support@pccctrace.vn.
11.Câu hỏi mở — cần chốt trước khi dev
ID
Câu hỏi
Đề xuất của BA
OQ-01
Trang "Đặt mật khẩu mới" (đích của link email, mục 4.3) chưa có trong screen inventory và chưa có prototype riêng.
Thêm màn DN-004b — Đặt mật khẩu mới (route /reset-password) vào inventory + dựng prototype; layout tái dùng card 440px + component mật khẩu của DN-001.
OQ-02
DN-010 Recovery Approvals (queue DN Admin duyệt yêu cầu khôi phục) mất nguồn cấp sau khi bỏ flow "mất email" — quên mật khẩu là tự phục hồi, không cần duyệt.
✅ Chốt 03/07/2026 (PM): thành viên liên hệ trực tiếp DN Admin (ngoài hệ thống, không có form gửi yêu cầu trong app) → DN-010 loại bỏ, ID retired. Năng lực reset chuyển thành row action 🔑 trong DN-008 Members (BR-08).
OQ-03
Nội dung email đặt lại mật khẩu (subject, template) do ai chốt?
BA soạn draft cùng template email kết quả KYC (DN-002) thành bộ email transactional thống nhất — 1 file spec riêng.
12.Changelog
Version
Ngày
Người
Thay đổi
v1.1
03/07/2026
BA
Chốt OQ-02 theo quyết định PM: thành viên cần reset mật khẩu (kể cả mất email) liên hệ trực tiếp DN Admin công ty — thêm BR-08 admin-assisted reset qua DN-008 (mật khẩu tạm + buộc đổi + audit); DN-010 loại bỏ, ID retired; cập nhật BR-07, EC-06.
v1.0
03/07/2026
BA
Bản đầu tiên — viết sau quyết định PM 03/07/2026 thu hẹp DN-004 còn flow Quên mật khẩu duy nhất (bỏ flow mất email, loại bỏ DN-005). Wording + layout prototype làm lại theo chuẩn pre-auth 440px; success message generic chống dò email.