Super Admin Device Creation Flow Design
Date: 2026-05-02
Status: Approved (conversation-level), pending file review gate
1) Goal
Tối ưu luồng Thêm thiết bị mới để Super Admin tạo thiết bị nhanh hơn bằng cách:
- Đưa
Loại thiết bịlên đầu form - Tự sinh sẵn
Tên thiết bịvàMã serialngay sau khi chọn loại - Vẫn cho phép người dùng sửa tay hai field tự sinh trước khi lưu
- Biến
Mô hìnhthành optional ở frontend
Thiết kế phải giữ backend là nguồn sự thật cho rule đánh số và uniqueness của serialNumber, nhưng không làm nặng quy trình bằng reservation hoặc locking.
2) Current State
- Form
Thêm thiết bị mớihiện nằm trongfrontend/src/pages/devices/DeviceList.tsx. - Thứ tự field hiện tại là:
Tên thiết bịMã serialLoại thiết bịMô hình
- Frontend đang coi
modellà required trongfrontend/src/schemas/device.schema.ts. - Backend
CreateDeviceDtođang coimodellà optional. - Backend hiện chỉ tạo thiết bị từ payload gửi lên; chưa có API generate identity preview.
serialNumberđang được backend kiểm tra unique tuyệt đối.mqttTopicđang được backend sinh từserialNumberlúc tạo thiết bị.
3) Options Considered
Option A: Frontend-only suggestion
Frontend tự generate Tên thiết bị và Mã serial từ Loại thiết bị, không gọi backend trước khi submit.
Pros
- Triển khai nhanh
- UX mượt, không thêm round-trip
Cons
- Dễ đụng sequence khi nhiều người tạo cùng lúc
- Logic generate bị đẩy lên frontend, khó giữ backend làm nguồn sự thật
Option B: Backend-only generation on create
Frontend chỉ cho chọn Loại thiết bị, backend tự generate identity lúc lưu.
Pros
- Rule tập trung hoàn toàn ở backend
- Không có preview “ảo” trước submit
Cons
- Không đáp ứng yêu cầu preview sẵn để Super Admin chỉnh trước khi lưu
- UX kém hơn cho mục tiêu nhập liệu nhanh
Option C (selected): Hybrid preview with backend-generated suggestion
Frontend gọi backend để lấy cặp identity gợi ý sau khi chọn Loại thiết bị, sau đó điền sẵn vào form và cho phép sửa tay trước khi submit.
Pros
- Khớp mục tiêu Super Admin tạo nhanh
- Backend vẫn nắm rule generate
- Frontend có preview sẵn để người dùng chỉnh nếu cần
Cons
- Cần thêm endpoint/service mới
- Preview không thể được coi là “reserved”
4) Selected Design
Chọn Option C: backend cấp identity preview theo loại thiết bị, frontend dùng preview này để autofill form.
4.1 Form flow
Luồng form mới:
- Mở form tạo mới:
Loại thiết bịđứng đầu formTên thiết bị,Mã serialđể trốngMô hìnhhiển thị nhưng không bắt buộc
- Người dùng chọn
Loại thiết bị - Frontend gọi backend để lấy identity preview
- Frontend điền sẵn:
Tên thiết bịMã serial
- Người dùng có thể:
- giữ nguyên giá trị gợi ý và lưu
- sửa một hoặc cả hai field trước khi lưu
4.2 Generate rules
Mapping mặc định theo loại thiết bị:
sensor-> name prefixSensor, serial prefixSNSgateway-> name prefixGateway, serial prefixGTWinverter-> name prefixInverter, serial prefixINVfeeder-> name prefixFeeder, serial prefixFDR
Format mặc định:
Tên thiết bị:<NamePrefix> <NNN>Mã serial:<SerialPrefix>-<NNN>
Ví dụ:
Sensor 001/SNS-001Gateway 001/GTW-001
Rule đánh số:
- Sequence chạy toàn hệ thống theo từng loại thiết bị
- Sequence mặc định dùng 3 chữ số:
001,002,003 - “Số tiếp theo” được suy ra từ sequence lớn nhất hiện có của cùng loại rồi cộng 1
4.3 Manual override behavior
Frontend phải theo dõi trạng thái “đã chỉnh tay” riêng cho:
nameserialNumber
Hành vi mong muốn:
- Nếu người dùng chưa chỉnh tay field nào và đổi
Loại thiết bị, frontend được phép regenerate field đó - Nếu người dùng đã chỉnh tay một field, frontend không được silently overwrite field đó nữa
- Nếu người dùng đã sửa cả hai field, đổi loại thiết bị không được đè lại hai field đó
Thiết kế này tối ưu cho nhập liệu nhanh nhưng vẫn tôn trọng chủ đích người dùng.
4.4 Backend preview contract
Backend thêm API preview identity cho tạo thiết bị mới, ví dụ:
GET /api/v1/devices/generate-identity?type=sensor
Hoặc endpoint tương đương nếu team muốn dùng POST.
Response tối thiểu nên trả:
{
"type": "sensor",
"name": "Sensor 001",
"serialNumber": "SNS-001",
"sequence": 1
}
Endpoint này:
- Không tạo thiết bị
- Không giữ chỗ sequence
- Chỉ trả về gợi ý tốt nhất tại thời điểm gọi
4.5 Create-time validation and race conditions
Preview identity không phải reservation.
Do đó ở bước create device:
- Backend tiếp tục check
serialNumberunique tuyệt đối - Nếu serial preview đã bị chiếm trong khoảng thời gian giữa preview và submit, backend trả lỗi conflict rõ ràng
- Frontend phải hiển thị lỗi dễ hiểu và cho phép người dùng:
- sửa tay serial
- hoặc regenerate preview mới rồi lưu lại
Thiết kế này giữ tính đúng đắn dữ liệu mà không đưa thêm cơ chế lock phức tạp vào scope hiện tại.
4.6 Sequence parsing policy
Backend cần một helper thống nhất để:
- map
type -> name prefix - map
type -> serial prefix - đọc sequence từ các serial đúng pattern mặc định
Chỉ các serial khớp pattern mặc định của loại tương ứng mới được dùng để tính next sequence, ví dụ:
SNS-001GTW-014
Serial custom không theo pattern mặc định:
- vẫn hợp lệ nếu unique
- không được dùng để làm hỏng hoặc nhảy sai bộ đếm mặc định
4.7 Model field behavior
Mô hình phải được đổi thành optional ở frontend để đồng bộ với backend hiện tại.
Điều này bao gồm:
- bỏ required marker trong UI
- cập nhật validation schema tương ứng
- không chặn submit nếu field này để trống
5) File-Level Scope
Expected scope ở mức thiết kế:
frontend/src/pages/devices/DeviceList.tsx- đổi thứ tự field
- thêm autofill flow
- theo dõi manual override state
frontend/src/schemas/device.schema.ts- đổi
modelthành optional trong create schema
- đổi
frontend/src/services/device.service.ts- thêm method gọi API generate identity
frontend/src/types/device.types.ts- thêm type cho generate identity request/response nếu cần
backend/src/devices/controllers/devices.controller.ts- thêm route generate identity
backend/src/devices/devices.service.ts- thêm logic generate preview
backend/src/devices/dto/- thêm DTO/query DTO/response DTO cho generate identity nếu cần
6) Acceptance Criteria
- Trong form tạo thiết bị mới,
Loại thiết bịlà field đầu tiên. - Khi chọn
Loại thiết bị, hệ thống tự điềnTên thiết bịvàMã serialtheo rule mặc định. Tên thiết bịvàMã serialvẫn chỉnh tay được trước khi lưu.- Nếu người dùng chưa chỉnh tay một field, field đó được phép regenerate khi đổi
Loại thiết bị. - Nếu người dùng đã chỉnh tay một field, frontend không tự đè field đó âm thầm.
Mô hìnhkhông còn là field bắt buộc ở frontend.- Backend vẫn enforce uniqueness của
serialNumberở bước create. - Nếu
serialNumberbị trùng ở lúc submit, hệ thống trả lỗi rõ ràng để người dùng regenerate hoặc sửa tay. - Luồng mới giúp Super Admin tạo thiết bị với ít thao tác nhập tay hơn luồng hiện tại.
7) Out of Scope
- Reservation hoặc locking sequence
- Thay đổi rule unique tuyệt đối của
serialNumber - Migrate dữ liệu cũ sang pattern serial mới
- Mở rộng form hiện tại để thêm
pondId,installationDate,warrantyMonths,ownershipType - Thiết kế lại toàn bộ trang danh sách thiết bị
8) Risks and Mitigations
Risk: Hai người cùng lấy preview giống nhau rồi submit gần thời điểm nhau
Mitigation: Backend giữ unique validation ở bước create; frontend xử lý conflict rõ ràng.Risk: Dữ liệu cũ có serial custom khiến việc tính next sequence sai
Mitigation: Chỉ parse sequence từ serial khớp pattern mặc định theo từng loại.Risk: Frontend overwrite giá trị user đã sửa khi đổi loại thiết bị
Mitigation: Theo dõi cờ manual override riêng cho từng field.Risk:
modeloptional ở frontend nhưng code submit cũ vẫn giả định luôn có string
Mitigation: Đồng bộ type/schema/service payload để chấp nhậnundefinedhoặc empty value hợp lệ.