Master Data — Common cases
Account holder avatar does not show
Check Contact.ProfileImage, upload endpoint/entity type, and URL construction. Do not look for Account.ProfileImage; the account does not own the avatar.
Real-world example: Parent avatar does not show. → Find where the image is stored. → The avatar lives on
Contact.ProfileImage, notAccount.
Customer/attendee filtered by the wrong BU/site
Cross-check the BusinessUnitAccount, BusinessUnitAttendee, Org_Account, Org_Attendee relationships and the request context. Wrong BU scope → security issues or "lost" data.
Real-world example: Staff at site B sees a child of site B missing. → Keep the BU scope correct, neither leak nor hide data. → The
BusinessUnitAttendeelink for the selected BU is missing → add the relationship, do not broaden the query scope.
Session does not appear in booking
Check term, TPS, term product, site-program link, category rule, and capacity. Booking only reads availability from setup; missing setup → booking does not create sessions on its own.
Real-world example: Admin opens booking for Term 3, sees no sessions. → Booking only reads setup; it does not generate sessions. → TPS not linked to a site/program or term products not generated → once setup is complete the session appears.
Image upload forced to crop
First-class UI images must be cropped per policy; generic file uploads are exempt. Avatar/profile images are usually 1:1; wide course/activity images are usually 16:9.
Real-world example: Uploading a course image forces a 16:9 crop; attaching a document does not. → Keeps display consistent without blocking ordinary files. → First-class images crop per policy; generic uploads are exempt.
Custom URL conflict
Enterprise.CustomUrl must be unique among active enterprises. The site initiator must detect conflicts and log an error instead of overwriting the custom URL.
Real-world example: A new enterprise sets a custom URL matching an active enterprise. → Avoid two organizations sharing one URL. → Site initiator detects the duplicate, logs an error instead of overwriting the other enterprise's URL.
Subscription Config tab does not show on Attendee Profile
Check the gate: the user must be a sys-admin and the current BU must have TypeId = 99 (SuperAdmin). The gate uses already-loaded context, no new BU query; direct navigation to the product-config route without the gate goes through the invalid-tab deny flow.
Real-world example: Sys-admin opens the profile but does not see the
Subscription Configtab. → Check whether the selected BU is SuperAdmin. → Current BU isTypeId = 30(not 99) → switch to a SuperAdmin BU for the tab to show.
ProductSet list empty or missing ProductSet
Candidate ProductSets come only from the assigned Subscription's active SubscriptionExtra (ProductSetId distinct, ProductSet.IsActive = true, same BU). An attach without an assigned Subscription → empty list. A ProductSet not referenced by the subscription → does not show even with an Attendee_ProductSet row.
Real-world example: Reassigning
Subscription→ a previously enabledProductSetgoes missing. → Avoid configuring outside the subscription scope. → The ProductSet is no longer in activeSubscriptionExtra→ not listed; the old row can still be Disabled.
Requirement field hidden but attendee still "stuck required"
_Required only blocks when _Enabled = true. When _Enabled is off, the field is hidden on every surface, _Required is ignored, and BasicProfileCompleted/booking is not blocked — but saved values are not deleted.
Real-world example: BU disables
AttendeeLevel_EnabledbutAttendeeLevel_Requiredstaystrue; an attendee without a Level still submits enrollment. → Avoid blocking the form for a field no longer used. → Form submits successfully,Attendee.Levelkeeps its old value (or null).
Legacy Swimming Competency not in options
The field is a dropdown built from AttendeeSwimmingCompetency_Options. Previously saved values outside the options still display and stay unchanged on save. Saving a new value outside the options is rejected.
Real-world example:
Attendee "Tom"hasSwimmingCompetency = "Beginner - can float", new options only["Non Swimmer","Learner","Competent"]. → Old data is not lost. → The dropdown showsBeginner - can float; Tom can save a switch toLearner, but other text is rejected.
Consent required ignored when disabled
CustomConsent1..3 (and PhotoConsent/MedicalDeclaration/TreatmentConsent) only enforce Required when Enabled = true; a disabled field is hidden and does not block submit. Text = label, Description = helper (empty → not rendered).
Real-world example:
CustomConsent3_Required = truebutCustomConsent3_Enabled = false. → Enrollment is not blocked because the consent is unused. → The form does not render the field; the form submits successfully without an answer.
Archived staff still appear in roster/selector
GET /api/employee/LinkEmployee and the surfaces (Weekly Planner, Add Shift selector) only fetch employees with StatusId = Approved; StatusId = Archived are excluded even with IsActive = true.
Real-world example: An archived staff still shows in the shift-assignment dropdown. → Avoid assigning shifts to someone who left. → Check the
StatusId(Approved) filter instead of onlyIsActive; archived are excluded from the list.
Wrong program category tag/card on portal
Site-category selection lives on OrgProgramCategory.StatusId: Approved (500) = selected, Initialised (0) = unselected; IsActive is not used to filter tags. Site Settings renders the multi-selector Program Categories (before business hours), no longer the old Program Categories per Site list.
Real-world example: Landing page misses or mis-shows a site's category tag. → Check
StatusId, notIsActive. → Site has not selected the category →StatusId = 0→ tag hidden even withIsActive = true; select it in Site Settings →StatusId = 500→ tag appears.
Tracking code does not save/show color
The TrackingCode drawer uses a color picker to set colorCode; it saves via /api/trackingCode and the list shows a color swatch from the persisted value; a row without a color shows no default swatch. Create/edit validation, archive/restore, and tabs stay the same.
Real-world example: Admin picks
#BF4040forTrackingCode "Paid Leave"but the color is gone after reload. → The color must ride in thecolorCodepayload. → Save carriescolorCode = "#BF4040"; the list shows the swatch; a row without color stays empty, no fake default blue.
New Course drawer has no Sign In/Out Method
The Term Planner New Course drawer does not render Sign In Method/Sign Out Method; TermProduct copies SignInMethodId/SignOutMethodId from Product when creating a course. The session drawer shows requirements as a read-only summary, not min/max inputs.
Real-world example: Admin creates a new Class course but cannot find a sign method field in the drawer. → Avoid misaligned config between product and session. →
TermProduct.SignInMethodId=Product.SignInMethodId; the session drawer shows the5 - 7 years oldrequirement summary read-only.
Booking unfairly blocked by missing capacity setup
ProgramCapacity reads from TermProgramSetCapacity per session date; no record for a date → unlimited (ProgramRemainingCount = 999), booking not blocked; slot-level capacity is still enforced at TermProduct.
Real-world example: Admin sets
TermProgramSetcapacity for only a few days; on other days booking still reports full. → Do not let a missing-capacity date block incorrectly. → Check theTermProgramSetCapacitysource (no moreProgram.Capacity); a date without a record → unlimited, onlyTermProductcapacity truly blocks.