Customer Portal & My Home — Architecture & data
Bootstrap by app mode
- The staff-context store (
currentUserTopi,currentUserLinkedSites) only populates in Admin Mode. - The
_aselector onConsumerAccount: an admin selecting a customer account → still callable in Admin Mode; only the caller's own account is excluded from bootstrap.
Layout & width
- All standard pages share the shell → moving between the Booking UI and the portal does not change the max-width.
- A local max-width conflicting with the canonical one → drop/replace the rule, unless it is a documented exception.
- Opt-out exceptions do not change the default behavior.
Timezone resolution
- The backend returns the source datetime; the frontend branches the display (INV-ENTTZMODE-002).
- Saving the timezone: staff prompt →
POST /api/User/UpdateUserTimezoneIdentifier; sidebar →updateUserTimezone(newWindowsId); both save a Windows TZ ID. - Rehydrates after reload from
ConsumerManage/CurrentUser, no extra request.
Prompt & popup gating
- Staff My Home prompt: flag
my-home-tz-prompted, save is mandatory (not dismissible). - Portal session popup: flag
tz-popup-dismissed, set on save or dismiss. - Mismatch detection only runs for an authenticated MultiZone user who has not dismissed.
My Subscriptions — read boundary
- My Bookings shares the row model: sections by Pending/Confirmed/Cancelled tab; the Waiting/Cart tab renders nothing.
- Switching tabs filters the already-fetched data, no re-fetch.
Share link composition
- INV-CP-SHARELINK-001: compose from the Customer Portal base URL, not from the browser origin when that origin could be the Admin Portal.
Key APIs
| Purpose | API | Mode |
|---|---|---|
| Staff context | GET /api/Manage/CurrentUser, GET /api/Employee/LinkOrg | Admin Mode |
| Caller account | GET /api/ConsumerAccount (no _a) | outside Admin Mode |
| Consumer identity + timezone | GET /api/ConsumerManage/CurrentUser | every mode |
| Update timezone | POST /api/User/UpdateUserTimezoneIdentifier (Windows TZ ID) | staff prompt / updateUserTimezone |
| My Subscriptions | route /{curl}/enrollments (backend account-scoped) | authenticated |
Ownership boundary
| Block | Who may mutate |
|---|---|
| Timezone display, layout, prompt/session flags | Frontend (no backend mutation) |
User.TimezoneIdentifier | Only via the update-timezone API |
| Enrollment / booking / billing / invoice / payment / credit note | Only the existing backend services; portal is read-only |
| Share URL | Frontend composes from the Customer Portal origin, unchanged by browser origin |