PHASE 1 FIX SUMMARY
March 6, 2026 | Production-Ready Access Architecture
β PHASE 1 COMPLETE AND FIXED
All access loops resolved. Role model is deterministic. Login routes normalized.
Issues Fixed
β Access Loop (Company Invitee)
Problem: Company invitee logged in with role "user", got blocked by old permission logic requiring "staff".
Fix: Removed all legacy role checks (user/staff/admin). Now uses explicit scope + role model only.
β Login Route 404
Problem: "Back to Login" button redirected to /admin-login, but route didn't exist or was inconsistent.
Fix: Normalized all login references to use createPageUrl('AdminLogin'). Canonical route: /admin-login
β Legacy Role Logic
Problem: Code mixing old access checks (user/staff/admin) with new scope-based model.
Fix: Removed deprecated minRole param from AdminGuard. All access checks now use getUserScope() + explicit role checks.
Files Changed
components/admin/AdminGuard.jsx
- β Removed deprecated
minRoleparameter - β
Added
createPageUrlimport - β
Changed login redirect from hardcoded
/admin-logintocreatePageUrl('AdminLogin') - β
Added
navigateto dependency array
pages/AcceptInvite.jsx
- β
Added
createPageUrlimport - β
Changed redirect in success handler from hardcoded
/admin-logintocreatePageUrl('AdminLogin') - β
Changed "Go to Login" button href from hardcoded to
createPageUrl('AdminLogin') - β
Changed "Log in here" link from hardcoded to
createPageUrl('AdminLogin')
entities/User.json
- β
platform_role(explicit platform roles only) - β
company_role(explicit company roles only) - β
company_id(required if company_role set) - β
status(active/inactive/pending_activation) - β No legacy "role" field with user/staff/admin
entities/UserInvitation.json
- β
scope(platform | company) - β
platform_role(if scope=platform) - β
company_role(if scope=company) - β
company_id(if scope=company) - β
token+token_expires_at - β No legacy "role" field
Final Role Model
Platform Scope
platform_ownerβ Highest platform privilegeplatform_adminβ Standard platform adminplatform_supportβ Platform support staff
Company Scope
company_ownerβ Highest company privilegecompany_adminβ Standard company adminfleet_managerβ Vehicle operationsreservations_managerβ Booking managementfinance_managerβ Financial operationssupport_agentβ Customer support
Canonical Login Route
Canonical Route:
/admin-login via createPageUrl('AdminLogin')
All buttons/redirects now use:
// Instead of:
href="/admin-login"
navigate("/admin-login")
// Use:
href={createPageUrl('AdminLogin')}
navigate(createPageUrl('AdminLogin'))Login Redirect Rules
Legacy Logic Removed
β Removed All Occurrences:
role === "user"for admin access checksrole === "staff"for permission logicminRoleparameter in guards- Generic "admin" fallback checks
- Undefined role helper variables
- Hardcoded
/admin-loginstrings (use createPageUrl)
Access Control Summary
π AdminGuard (Base Auth)
Checks: User authenticated + has valid scope
Behavior: Loading UI β scope check β allow/deny with visible UI
π PlatformAdminGuard
Checks: isPlatformAdmin(user)
Behavior: Allow platform scope users only, deny company users with visible error
π’ CompanyAdminGuard
Checks: isCompanyAdmin(user) OR isPlatformAdmin(user) && impersonatingCompanyId
Behavior: Allow company scope users, allow platform users impersonating company
Validation Checklist
β PHASE 1 STATUS
Production-ready access architecture fully implemented and fixed.
- β Deterministic scope + role model
- β Normalized login routes
- β All legacy role logic removed
- β Access denied UI visible and helpful
- β No access loops
- β Company invitee role properly mapped
- β Ready for user validation testing