Functional Specification · PCCCTrace Web DN

DN-001 — Đăng ký tài khoản doanh nghiệp (Signup & KYC Submission)

Đặc tả chức năng cho developer — mô tả đầy đủ UI, validation, business rules, API contract và edge cases của màn hình đăng ký DN.

Screen IDDN-001
ModuleAuth & Onboarding
ActorDN Owner (chưa có tài khoản)
RequirementsFR-1a MVP, FR-7, FR-18, FR-75
Trạng tháiReady for dev — OQ đã chốt 03/07/2026
Version / Ngàyv1.2 · 03/07/2026
Màn hình liên quanDN-002 · DN-003

1.Tổng quan & phạm vi

Mục đích: Cho phép DN Owner (doanh nghiệp PCCC nhập khẩu / sản xuất tier 1) tự đăng ký tài khoản tenant trên app.pccctrace.vn. Người dùng khai thông tin doanh nghiệp, tạo mật khẩu, upload Giấy đăng ký kinh doanh (ĐKKD), xác thực quyền sở hữu email qua OTP, sau đó hồ sơ chuyển sang trạng thái pending_kyc chờ Platform Admin duyệt thủ công (SLA 24h — FR-18).

Trong phạm vi (In scope)

Ngoài phạm vi (Out of scope)

Bối cảnh hệ thống Đây là bước đầu của hành trình onboarding J1 (DN-001 → DN-019, mục tiêu time-to-first-print < 7 ngày). Hệ thống multi-tenant, dữ liệu cô lập bằng Postgres RLS theo tenant_id (FR-58a). Quy mô mục tiêu nhỏ (~30 DN) — ưu tiên giải pháp đơn giản, không over-engineer.

2.User story & Acceptance Criteria

chủ doanh nghiệp PCCC (DN Owner),
tôi muốn đăng ký tài khoản doanh nghiệp bằng MST + email và nộp hồ sơ ĐKKD ngay trên web,
để doanh nghiệp của tôi được duyệt KYC và bắt đầu sử dụng PCCCTrace trong vòng 24 giờ.

Acceptance Criteria

IDKịch bản (Given / When / Then)
AC-01Given người dùng chưa có tài khoản, When nhập đầy đủ thông tin hợp lệ + upload ≥1 file ĐKKD và bấm "Gửi hồ sơ đăng ký", Then hệ thống gửi OTP 6 số tới email đã khai và hiển thị modal nhập OTP.
AC-02Given modal OTP đang mở, When nhập đúng mã OTP còn hiệu lực và bấm "Xác nhận & gửi hồ sơ", Then hệ thống tạo tenant (status pending_kyc) + user DN Owner, lưu hồ sơ ĐKKD, và chuyển hướng sang DN-002.
AC-03Given MST đã tồn tại trong hệ thống, When submit form, Then hiển thị lỗi "Tài khoản đã tồn tại, vui lòng đăng nhập" kèm link sang DN-003, không gửi OTP.
AC-04Given modal OTP đang mở, When nhập sai OTP 5 lần liên tiếp, Then khoá xác thực tạm thời (FR-7), hiển thị thông báo khoá và thời gian thử lại.
AC-05Given bất kỳ field nào không hợp lệ (xem mục 5), When submit, Then hiển thị lỗi inline dưới từng field, focus vào field lỗi đầu tiên, không gọi API.
AC-06Given người dùng chưa xác nhận OTP, Then không có tenant/user nào được tạo chính thức (chỉ tồn tại bản ghi đăng ký tạm — xem BR-06).
AC-07Given countdown OTP đã hết, When bấm "Gửi lại mã", Then OTP cũ bị vô hiệu, OTP mới được gửi, countdown reset (tối đa 5 OTP/giờ/email — FR-7).

3.Luồng nghiệp vụ

Điều kiện vào / ra

MụcChi tiết
Entry pointsLink "Đăng ký" từ landing page; link "Đăng ký" trên DN-003 (Login); URL trực tiếp /signup.
PreconditionNgười dùng chưa đăng nhập. Nếu đã có session hợp lệ → redirect về dashboard.
Exit — thành côngRedirect sang DN-002 KYC Pending.
Exit — thoát giữa chừngLink "Đăng nhập" → DN-003. Đóng modal OTP → quay lại form, dữ liệu giữ nguyên.

Luồng chính (Main flow)

┌────────────────────┐ │ 1. Người dùng điền │ Tên DN, MST, Email, SĐT, Mật khẩu ×2, │ form + upload │ upload ĐKKD (1–5 file) └─────────┬──────────┘ │ bấm "Gửi hồ sơ đăng ký" ▼ ┌────────────────────┐ lỗi validation ──► hiển thị lỗi inline, dừng │ 2. Client validate │ └─────────┬──────────┘ │ hợp lệ ▼ ┌────────────────────┐ MST/email đã tồn tại ──► lỗi + link Đăng nhập │ 3. Server: tạo bản │ │ ghi đăng ký tạm + │ │ gửi OTP qua email │ └─────────┬──────────┘ ▼ ┌────────────────────┐ sai 5 lần ──► khoá tạm (FR-7) │ 4. Modal OTP: nhập │ hết hạn ──► "Gửi lại mã" │ mã 6 số │ bấm Huỷ ──► đóng modal, giữ form └─────────┬──────────┘ │ OTP đúng, bấm "Xác nhận & gửi hồ sơ" ▼ ┌────────────────────┐ │ 5. Server: tạo │ tenant (pending_kyc) + user DN Owner │ tenant + user, lưu │ + lưu file ĐKKD + audit log │ hồ sơ KYC │ └─────────┬──────────┘ ▼ Redirect ──► DN-002 KYC Pending (SLA duyệt 24h)

Luồng thay thế (Alternate flows)

IDTình huốngXử lý
ALT-01MST hoặc email đã tồn tạiBước 3 trả lỗi 409. Hiển thị lỗi + link "Đăng nhập". Không gửi OTP.
ALT-02OTP hết hạnCountdown về 0 → disable nút xác nhận, enable "Gửi lại mã".
ALT-03Sai OTP 5 lầnKhoá xác thực 30 phút. Thông báo rõ thời gian được thử lại.
ALT-04Quá 5 lần gửi OTP/giờTrả 429. Disable "Gửi lại mã", hiển thị thời gian chờ.
ALT-05Người dùng đóng modal (Huỷ)Quay lại form, dữ liệu đã nhập giữ nguyên. Bản ghi đăng ký tạm vẫn hợp lệ trong TTL (BR-06).
ALT-06Lỗi mạng / server 5xxToast lỗi chung "Có lỗi xảy ra, vui lòng thử lại" + giữ nguyên dữ liệu form.

4.Đặc tả thành phần UI

Layout: card căn giữa, max-width 680px, nền --neutral. Tham chiếu trực tiếp prototype DN-001 — dùng đúng design tokens trong tokens.css.

IDThành phầnLoạiBắt buộcThuộc tính / hành vi
SU-00Header card (H1 + lead + badge SLA)StaticH1 "Đăng ký tài khoản doanh nghiệp" · lead: "Đăng ký một lần, quản lý truy xuất nguồn gốc tem PCCC cho toàn doanh nghiệp." · badge xanh lá "⏱ Duyệt hồ sơ trong 24 giờ làm việc" — cam kết SLA duyệt KYC (FR-18; 24h làm việc không tính T7/CN — chốt 03/07/2026, chi tiết tại spec DN-002 BR-02).
SU-01Tên doanh nghiệpText input, icon 🏢maxlength=200 · placeholder "VD: Công ty TNHH PCCC Hà Nội" · trim khoảng trắng đầu/cuối khi submit.
SU-02Mã số thuế (MST)Text input, icon #maxlength=14 · inputmode="numeric" · chỉ nhận chữ số và dấu "-" cho MST chi nhánh, chuẩn hoá bỏ gạch trước khi lưu (OQ-03 ✅) · placeholder "10 hoặc 13 chữ số".
SU-03EmailEmail input, icon ✉type="email" · autocomplete="username" · lowercase khi submit · là login identifier duy nhất (FR-1a).
SU-04Số điện thoạiTel input, icon 📞type="tel" · nhận số VN 10 số (di động 0xx / cố định 02x) · bỏ khoảng trắng khi validate.
SU-05Mật khẩuPassword input, icon 🔒 + toggle 👁 + thanh độ mạnhautocomplete="new-password" · tối thiểu 8 ký tự · toggle mắt chuyển type=password ⇄ text · thanh độ mạnh 3 mức hiện khi bắt đầu nhập, ẩn khi trống (rule tại mục 5.1).
SU-06Xác nhận mật khẩuPassword input, icon 🔒 + toggle 👁Phải khớp SU-05 · validate on blur + on submit.
SU-07Upload Giấy ĐKKDFile drop-zone (kéo thả / click)Định dạng PDF, JPG, PNG · ≤10 MB/file · tối đa 5 file, tối thiểu 1 file · counter "n/5" · sau khi chọn hiển thị danh sách file kèm nút xoá từng file.
SU-08Checkbox consentCheckbox + linksCheckbox bắt buộc tick trước khi submit: "Tôi đồng ý với Điều khoản sử dụngChính sách bảo mật của PCCCTrace" · link mở tab mới (/terms, /privacy) · server lưu consent_at timestamp làm bằng chứng đồng ý (FR-75 — OQ-05 ✅).
SU-09Nút "Gửi hồ sơ đăng ký ›"Button primary, full-width, h=48pxClick → client validate → gọi API gửi OTP → mở modal OTP · disable + spinner khi đang gọi API (chống double-submit).
SU-10Link "Đăng nhập"Link (topbar + footer card)DN-003.
SU-11Badge "🔒 SSL/TLS bảo mật"Static textTrấn an người dùng — không có hành vi.

5.Validation & thông báo lỗi

Validate 2 lớp: client (on blur + on submit, hiển thị inline dưới field, viền đỏ --error) và server (nguồn chân lý cuối cùng). Thông báo lỗi 100% tiếng Việt.

FieldRuleThông báo lỗi
SU-01Rỗng (sau trim)Vui lòng nhập tên doanh nghiệp
SU-01>200 ký tựTên doanh nghiệp tối đa 200 ký tự
SU-02RỗngVui lòng nhập mã số thuế
SU-02Không đúng định dạng 10 số hoặc 13 số (dạng chi nhánh ##########-###)Mã số thuế phải gồm 10 hoặc 13 chữ số
SU-02Server: MST đã tồn tạiTài khoản đã tồn tại, vui lòng đăng nhập
SU-03Rỗng / sai định dạng emailVui lòng nhập email hợp lệ
SU-03Server: email đã được dùng làm login identifierEmail đã được sử dụng, vui lòng đăng nhập hoặc dùng email khác
SU-04Rỗng / không phải SĐT Việt Nam hợp lệVui lòng nhập số điện thoại hợp lệ
SU-05<8 ký tựMật khẩu tối thiểu 8 ký tự
SU-06Không khớp SU-05Mật khẩu xác nhận không khớp
SU-07Chưa có file nàoVui lòng tải lên Giấy đăng ký kinh doanh
SU-07File >10MBFile "{tên file}" vượt quá 10 MB
SU-07Sai định dạngChỉ chấp nhận PDF, JPG, PNG
SU-07Quá 5 fileTối đa 5 file
SU-08Chưa tick checkbox đồng ýVui lòng đồng ý Điều khoản sử dụng và Chính sách bảo mật để tiếp tục
OTPSai mãMã OTP không đúng, còn {n} lần thử
OTPHết hạnMã OTP đã hết hạn, vui lòng bấm "Gửi lại mã"
OTPSai 5 lần → khoáBạn đã nhập sai quá 5 lần. Vui lòng thử lại sau 30 phút
OTPQuá 5 lần gửi/giờBạn đã yêu cầu mã quá nhiều lần. Vui lòng thử lại sau {phút} phút

5.1 · Chỉ báo độ mạnh mật khẩu (cơ bản)

Thanh 3 vạch + nhãn chữ hiển thị dưới field Mật khẩu (SU-05), cập nhật realtime theo mỗi ký tự nhập; ẩn khi field trống. Chỉ mang tính gợi ý — không chặn submit (điều kiện bắt buộc vẫn là ≥8 ký tự theo mục 5).

MứcHiển thịĐiều kiện
Yếu1 vạch đỏ + nhãn đỏCó ký tự nhưng chưa đạt mức Trung bình (<8 ký tự, hoặc chỉ toàn chữ / toàn số).
Trung bình2 vạch vàng + nhãn vàng≥8 ký tự có cả chữ lẫn số.
Mạnh3 vạch xanh + nhãn xanh≥10 ký tự có chữ + số có chữ hoa hoặc ký tự đặc biệt.

6.Business rules

IDRuleNguồn
BR-01MST là định danh duy nhất của tenant — mỗi MST chỉ đăng ký được 1 tenant. Email là login identifier unique toàn hệ thống (lưu như thuộc tính, không phải primary key).FR-1a
BR-02tenant_iduser_id được tạo khi OTP verified là bất biến — không thay đổi kể cả khi FR-1b (tự động hoá KYC) triển khai sau này.FR-1a/1b
BR-03Tenant mới luôn ở trạng thái pending_kyc. Chỉ Platform Admin mới chuyển được sang active/rejected (qua platform.pccctrace.vn — FR-18). Trước khi được duyệt, user chỉ truy cập được DN-002.FR-1a, FR-18
BR-04OTP email tại màn hình này chỉ dùng để xác thực quyền sở hữu email, không phải cơ chế đăng nhập. Đăng nhập dùng email + mật khẩu (DN-003).Prototype
BR-05Giới hạn OTP: 6 chữ số · hiệu lực 5 phút · cooldown gửi lại 60 giây (OQ-06 ✅) · tối đa 5 lần gửi/giờ/email · sai 5 lần → khoá tạm 30 phút.FR-7
BR-06Trước khi OTP verified, dữ liệu form + file lưu ở bản ghi đăng ký tạm (TTL đề xuất 24h). Không tạo tenant/user chính thức; bản ghi tạm quá hạn bị dọn tự động, file mồ côi trong MinIO bị xoá theo.BA đề xuất
BR-07Mật khẩu hash bcrypt cost 12 — không bao giờ lưu/log plaintext.DN-003 spec
BR-08Tạo tenant thành công phải ghi audit log: tenant_id, actor_user_id, IP, timestamp, action tenant.signup.FR-2 pattern
BR-09Sau khi tạo tenant, gửi email xác nhận "Đã nhận hồ sơ — sẽ duyệt trong 24 giờ làm việc" tới email đăng ký.Journey J1

7.Modal OTP xác thực email

Hiện đè lên form (overlay rgba(17,24,39,0.55)) sau khi bấm SU-09 và server đã gửi OTP thành công.

IDThành phầnHành vi
OTP-016 ô input mã (56px, 1 ký tự/ô)Chỉ nhận chữ số · auto-focus ô đầu · nhập xong tự nhảy ô kế · Backspace lùi ô trước · hỗ trợ paste cả mã 6 số (tự phân bổ vào 6 ô) · inputmode="numeric", autocomplete="one-time-code".
OTP-02Countdown "Gửi lại mã sau 60 giây"60s là cooldown gửi lại, không phải hạn của mã (OQ-06 ✅). Về 0 → OTP-03 enable. Mã OTP hiệu lực 5 phút kể từ lúc gửi — hết hạn server trả OTP_EXPIRED, người dùng bấm "Gửi lại mã". OTP-04 luôn enable khi đủ 6 số.
OTP-03Link "Gửi lại mã"Disabled khi countdown còn chạy · click → vô hiệu OTP cũ, gửi mã mới, reset countdown · tôn trọng rate limit BR-05.
OTP-04Nút "Xác nhận & gửi hồ sơ"Enable khi đủ 6 số · click → verify OTP; đúng → tạo tenant + redirect DN-002; sai → lỗi inline + rung nhẹ các ô, clear mã.
OTP-05Nút "Huỷ"Đóng modal, quay lại form (dữ liệu giữ nguyên). OTP đã gửi vẫn còn hiệu lực trong thời hạn.
Lưu ý cho dev Trong prototype, nút "Xác nhận & gửi hồ sơ" là thẻ <a href> điều hướng thẳng — khi implement phải là button gọi API verify, chỉ redirect khi server trả thành công.

8.API contract (đề xuất — backend chốt cuối)

8.1 · Gửi hồ sơ & yêu cầu OTP

// Tạo bản ghi đăng ký tạm + gửi OTP. Files upload multipart cùng request (đơn giản, phù hợp scale 30 DN).
POST /api/v1/auth/signup
Content-Type: multipart/form-data

company_name : string(≤200)
tax_code     : string(10|13 digits)
email        : string(email, lowercase)
phone        : string(VN phone)
password     : string(≥8)
consent      : boolean — bắt buộc true; server lưu consent_at (FR-75)
documents[]  : file × 1–5 (pdf|jpg|jpeg|png, ≤10MB/file)

// 200 OK
{ "registration_id": "reg_8f2k...", "otp_expires_in": 300, "resend_cooldown": 60 }

// Lỗi
409 TAX_CODE_EXISTS   → "Tài khoản đã tồn tại, vui lòng đăng nhập"
409 EMAIL_EXISTS      → "Email đã được sử dụng..."
422 VALIDATION_ERROR  → { "errors": { "tax_code": "..." } }
413 FILE_TOO_LARGE / 415 FILE_TYPE_INVALID
429 RATE_LIMITED      → { "retry_after_seconds": 1800 }

8.2 · Xác thực OTP → tạo tenant

POST /api/v1/auth/signup/verify
{ "registration_id": "reg_8f2k...", "otp": "387265" }

// 200 OK — tenant + user đã tạo, trạng thái pending_kyc
{ "tenant_id": "tn_01H...", "user_id": "us_01H...", "kyc_status": "pending_kyc" }

// Lỗi
400 OTP_INVALID   → { "attempts_left": 3 }
400 OTP_EXPIRED
423 OTP_LOCKED    → { "retry_after_seconds": 1800 }
410 REGISTRATION_EXPIRED  // bản ghi tạm quá TTL — yêu cầu đăng ký lại

8.3 · Gửi lại OTP

POST /api/v1/auth/signup/resend-otp
{ "registration_id": "reg_8f2k..." }

200 { "otp_expires_in": 60 }
429 RATE_LIMITED   // >5 OTP/giờ/email (FR-7)
Ghi chú lưu trữ File ĐKKD lưu MinIO theo key kyc/{registration_id}/{filename}; khi tenant được tạo, gắn ownership theo tenant_id. OTP hash trước khi lưu (không lưu plaintext), so sánh constant-time.

9.Trạng thái màn hình (UI states)

StateMô tả hiển thị
Empty / DefaultForm pristine: mọi field trống chỉ có placeholder, counter file "0/5", thanh độ mạnh mật khẩu ẩn, không có lỗi, nút submit enable.
Loading (skeleton)Toàn bộ card thay bằng skeleton shimmer khớp layout thật (title, lead, 2 field đơn, 2 hàng grid đôi, khối upload, consent, nút submit) — dùng khi trang đang tải dữ liệu.
ErrorBanner đỏ đầu card "Không thể gửi hồ sơ đăng ký. Vui lòng kiểm tra lại các trường được đánh dấu bên dưới." + field lỗi viền đỏ kèm message inline (kịch bản mẫu AC-03: MST đã tồn tại → lỗi tại MST, Email, file ĐKKD); focus field lỗi đầu tiên.
UploadingMỗi file có progress; chưa upload xong thì disable nút submit.
SubmittingNút SU-09 disable + spinner, label "Đang gửi..." — chặn double-submit.
OTP modalOverlay + modal; focus ô OTP đầu; ESC = Huỷ.
OTP verifyingNút OTP-04 disable + spinner.
OTP lockedCác ô OTP disable, message khoá 30 phút, chỉ còn nút Huỷ.
Server error (5xx)Toast "Có lỗi xảy ra, vui lòng thử lại" — không mất dữ liệu form.
Xem demo trong prototype dn-001-signup-mockup.html có khối "State & Spec" ở góc phải dưới: preview trực tiếp 3 trạng thái Loading / Empty / Error (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.

10.Yêu cầu phi chức năng

11.Edge cases

IDTình huốngHành vi mong đợi
EC-01Đăng ký tạm đã tồn tại cho cùng email/MST (user quay lại sau khi bỏ dở)Ghi đè bản ghi tạm cũ (chưa verify) bằng bản mới; OTP cũ vô hiệu.
EC-02MST đã có tenant nhưng bị rejected KYC trước đóCho đăng ký lại — hồ sơ mới vào lại queue duyệt (OQ-07 ✅); hiển thị ghi chú "Hồ sơ trước đã bị từ chối".
EC-03Refresh trang khi modal OTP đang mởForm mất dữ liệu (chấp nhận ở MVP); bản ghi tạm vẫn hợp lệ — nếu đăng ký lại cùng email thì đi theo EC-01.
EC-042 người cùng submit MST giống nhau gần như đồng thờiRàng buộc unique ở DB; người sau nhận 409 TAX_CODE_EXISTS.
EC-05File đúng đuôi nhưng sai nội dung (đổi tên .exe → .pdf)Server validate MIME/magic bytes, từ chối với 415.
EC-06Email nhập đúng định dạng nhưng không tồn tại (không nhận được OTP)User không thể verify → bản ghi tạm hết TTL tự dọn. Hint trong modal: "Kiểm tra cả hộp thư Spam".
EC-07Kéo thả nhiều hơn 5 file cùng lúcNhận 5 file đầu, toast "Tối đa 5 file".
EC-08Unicode/emoji trong tên DNCho phép ký tự tiếng Việt có dấu; escape đầy đủ khi render (chống XSS).

12.Câu hỏi mở — đã chốt (03/07/2026)

✅ Đã chốt toàn bộ 8 câu hỏi theo đề xuất của BA — 03/07/2026 Spec lấy prototype dn-001-signup-mockup.html làm chuẩn. Cột "Quyết định" dưới đây là quyết định chính thức, đã lan truyền vào các mục 4 / 5 / 6 / 7 / 8 / 11 của spec, prototype và tài liệu liên quan (07-1 screen inventory, 07-3 UX spec).
IDCâu hỏiQuyết định (theo đề xuất BA) ✅
OQ-01Screen inventory mô tả flow 2 bước (OTP trước → form KYC sau); prototype gộp thành 1 form + OTP modal cuối. Chốt theo hướng nào?Theo prototype (1 form + OTP cuối) — ít bước hơn, phù hợp mục tiêu onboarding nhanh.
OQ-02SĐT: inventory ghi optional, prototype đánh dấu bắt buộc (*).Bắt buộc — cần kênh liên hệ khi duyệt KYC thủ công.
OQ-03Định dạng MST: inventory ghi "10/13 ký tự", prototype ghi "10 hoặc 14 chữ số". MST chi nhánh VN là 13 số, thường viết ##########-### (14 ký tự gồm gạch).Nhận 10 số hoặc 13 số; cho phép nhập kèm dấu "-", chuẩn hoá bỏ gạch trước khi lưu.
OQ-04Inventory có thêm field địa chỉ trụ sở, ngành nghề, người đại diện pháp luật — prototype không có.Bỏ khỏi DN-001 (giảm friction); thu thập sau tại DN-007 Tenant Settings sau khi được duyệt.
OQ-05Consent: inventory yêu cầu checkbox đồng ý DPA + Privacy (FR-75); prototype chỉ có dòng text implicit.Dùng checkbox bắt buộc + lưu consent_at timestamp làm bằng chứng đồng ý (đáp ứng FR-75).
OQ-06Prototype ghi OTP "hết hạn sau 60 giây" — 60s là quá ngắn cho email đến hộp thư.60s là cooldown "Gửi lại mã"; hiệu lực mã thực tế nên là 5 phút.
OQ-07DN bị reject KYC có được tự đăng ký lại không, hay phải qua support?Cho tự đăng ký lại, hồ sơ mới vào lại queue duyệt (đơn giản nhất cho MVP).
OQ-08URL "Điều khoản sử dụng" / "Chính sách bảo mật" là gì? (prototype đang để #)Cần trang tĩnh /terms/privacy trước khi launch.

13.Lịch sử thay đổi

VersionNgàyNgười viếtNội dung
v1.203/07/2026BAChốt 8 câu hỏi mở (mục 12) theo đề xuất BA: (1) giữ flow 1 form + OTP modal cuối; (2) SĐT bắt buộc; (3) MST 10/13 số, nhận dấu "-", chuẩn hoá bỏ gạch — SU-02 + mục 5; (4) không thêm field phụ, thu thập tại DN-007; (5) consent thành checkbox bắt buộc + lưu consent_at — SU-08, mục 5, API 8.1; (6) OTP hiệu lực 5 phút / cooldown 60s — OTP-02, BR-05, API 8.1; (7) reject KYC được tự đăng ký lại — EC-02; (8) cần trang tĩnh /terms + /privacy trước launch. Đồng bộ prototype + 07-1 inventory + 07-3 UX spec.
v1.103/07/2026BAĐồng bộ theo prototype cập nhật: (1) lead copy mới + badge SLA "Duyệt hồ sơ trong vòng 24 giờ" (SU-00); (2) thêm chỉ báo độ mạnh mật khẩu 3 mức — mục 5.1, cập nhật SU-05; (3) chi tiết hoá 3 UI states Loading (skeleton) / Empty / Error theo thiết kế mới + ghi chú khối demo "UI State" trong prototype.
v1.002/07/2026BABản đầu tiên — viết từ prototype dn-001-signup-mockup.html + PRD FR-1a/FR-7/FR-18/FR-75 + screen inventory 07-1.
← Quay lại mockup