Master Data — Case thường gặp
Account holder avatar không hiện
Kiểm tra Contact.ProfileImage, upload endpoint/entity type và URL construction. Không tìm Account.ProfileImage vì account không sở hữu avatar.
Ví dụ thực tế: Avatar phụ huynh không hiện. → Tìm đúng nơi lưu ảnh. → Avatar ở
Contact.ProfileImage, không phảiAccount.
Customer/attendee bị lọc sai theo BU/site
Đối chiếu relationship BusinessUnitAccount, BusinessUnitAttendee, Org_Account, Org_Attendee và request context. BU scope sai → lỗi bảo mật hoặc dữ liệu “mất”.
Ví dụ thực tế: Staff site B thấy thiếu trẻ của site B. → Giữ BU scope đúng, không lộ/giấu nhầm. → Thiếu link
BusinessUnitAttendeecho BU chọn → bổ sung quan hệ, không nới scope query.
Session không xuất hiện trong booking
Kiểm tra term, TPS, term product, site-program link, category rule và capacity. Booking chỉ đọc availability từ setup; setup thiếu thì booking không tự tạo session.
Ví dụ thực tế: Admin mở booking Term 3, không thấy buổi nào. → Booking chỉ đọc setup, không tự sinh. → TPS chưa link site/program hoặc chưa sinh term product → hoàn tất setup thì session hiện.
Image upload bị bắt crop
First-class UI images phải crop theo policy; generic file upload được exempt. Avatar/profile image thường 1:1, wide course/activity image thường 16:9.
Ví dụ thực tế: Upload ảnh khóa học bị buộc crop 16:9, đính kèm tài liệu thì không. → Giữ hiển thị đồng nhất, không cản file thường. → First-class crop theo policy; generic upload exempt.
Custom URL conflict
Enterprise.CustomUrl phải unique với enterprise active. Site initiator phải detect conflict và ghi error thay vì ghi đè custom URL.
Ví dụ thực tế: Enterprise mới đặt custom URL trùng enterprise active. → Tránh hai đơn vị cùng URL. → Site initiator detect trùng, ghi error thay vì ghi đè URL của enterprise kia.
Tab Subscription Config không hiện trên Attendee Profile
Kiểm tra gate: user phải là sys-admin và BU hiện tại có TypeId = 99 (SuperAdmin). Gate dùng context đã load, không cần query BU mới; direct navigation tới route product-config khi không đủ gate sẽ đi qua invalid-tab deny flow.
Ví dụ thực tế: Sys-admin mở profile nhưng không thấy tab
Subscription Config. → Kiểm tra BU đang chọn có phải SuperAdmin không. → BU hiện tạiTypeId = 30(không phải 99) → đổi sang BU SuperAdmin thì tab mới hiển thị.
Danh sách ProductSet trống hoặc thiếu ProductSet
Candidate ProductSet chỉ lấy từ SubscriptionExtra active của Subscription được gán (ProductSetId distinct, ProductSet.IsActive = true, cùng BU). Attach không gán Subscription → danh sách rỗng. ProductSet không được subscription tham chiếu → không hiện dù có row Attendee_ProductSet.
Ví dụ thực tế: Đổi gán
Subscription→ thiếuProductSettừng enable. → Tránh cấu hình ngoài phạm vi subscription. → ProductSet không còn trongSubscriptionExtraactive → không list; row cũ vẫn Disable được.
Requirement field bị ẩn nhưng attendee vẫn “kẹt required”
_Required chỉ chặn khi _Enabled = true. Khi tắt _Enabled, field ẩn trên mọi surface, bỏ qua _Required, và không block BasicProfileCompleted/booking — nhưng giá trị đã lưu không bị xóa.
Ví dụ thực tế: BU tắt
AttendeeLevel_EnablednhưngAttendeeLevel_Requiredvẫntrue; attendee không có Level vẫn gửi enrollment. → Tránh chặn form vì field không còn dùng. → Form submit thành công,Attendee.Levelgiữ nguyên giá trị cũ (hoặc null).
Swimming Competency cũ không nằm trong options
Field là dropdown build từ AttendeeSwimmingCompetency_Options. Giá trị cũ ngoài options vẫn hiển thị, giữ nguyên khi save. Save giá trị mới ngoài options bị reject.
Ví dụ thực tế:
Attendee "Tom"cóSwimmingCompetency = "Beginner - can float", options mới chỉ còn["Non Swimmer","Learner","Competent"]. → Không đánh mất dữ liệu cũ. → Dropdown hiệnBeginner - can float; Tom đổi sangLearnerthì lưu được, nhập text khác thì bị reject.
Consent required bị bỏ qua khi disabled
CustomConsent1..3 (và PhotoConsent/MedicalDeclaration/TreatmentConsent) chỉ enforce Required khi Enabled = true; field disabled thì ẩn và không chặn submit. Text = label, Description = helper (rỗng thì không render).
Ví dụ thực tế:
CustomConsent3_Required = truenhưngCustomConsent3_Enabled = false. → Không chặn enrollment vì consent không dùng. → Form không render field, form submit thành công không cần câu trả lời.
Archived staff vẫn xuất hiện ở roster/selector
GET /api/employee/LinkEmployee và các surface (Weekly Planner, Add Shift selector) chỉ lấy employee StatusId = Approved; StatusId = Archived bị loại dù IsActive = true.
Ví dụ thực tế: Staff đã archive vẫn hiện trong dropdown gán ca. → Tránh gán ca cho người đã nghỉ. → Kiểm tra filter
StatusId(Approved) thay vì chỉIsActive; archived bị loại khỏi list.
Program categories tag/card sai trên portal
Site-category selection nằm ở OrgProgramCategory.StatusId: Approved (500) = selected, Initialised (0) = unselected; IsActive không dùng để filter tag. Site Settings render multi-selector Program Categories (trước business hours), không còn list Program Categories per Site cũ.
Ví dụ thực tế: Landing page thiếu/hiện sai category tag của site. → Kiểm tra
StatusIdchứ không phảiIsActive. → Site chưa chọn category →StatusId = 0→ tag ẩn dùIsActive = true; chọn trong Site Settings →StatusId = 500→ tag xuất hiện.
Tracking code không lưu/không hiện màu
TrackingCode drawer dùng color picker gán colorCode; save qua /api/trackingCode và list hiển thị swatch màu từ giá trị persist; row không có màu thì không hiện default swatch. Create/edit validation, archive/restore và tabs giữ nguyên.
Ví dụ thực tế: Admin chọn
#BF4040choTrackingCode "Paid Leave"nhưng sau reload mất màu. → Màu phải đi theo payloadcolorCode. → Save cócolorCode = "#BF4040"; list hiện swatch; row không màu để trống, không giả mạo màu blue default.
New Course drawer không có Sign In/Out Method
Term Planner New Course drawer không render Sign In Method/Sign Out Method; TermProduct copy SignInMethodId/SignOutMethodId từ Product khi tạo course. Session drawer hiển thị requirement dạng read-only summary, không phải input min/max.
Ví dụ thực tế: Admin tạo course Class mới nhưng tìm không thấy field sign method trong drawer. → Tránh config lệch giữa product và session. →
TermProduct.SignInMethodId=Product.SignInMethodId; session drawer hiện requirement summary5 - 7 years oldread-only.
Booking bị chặn oan do capacity thiếu setup
ProgramCapacity đọc từ TermProgramSetCapacity theo ngày session; không có record cho ngày → unlimited (ProgramRemainingCount = 999), không block booking; slot-level capacity vẫn enforce ở TermProduct.
Ví dụ thực tế: Admin đặt capacity
TermProgramSetchỉ một vài ngày, ngày khác booking vẫn bị báo hết chỗ. → Không để ngày thiếu capacity chặn nhầm. → Kiểm tra nguồnTermProgramSetCapacity(không cònProgram.Capacity); ngày thiếu record → unlimited, chỉ capacityTermProductthật sự chặn.