@jmruthers/pace-core 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/cursor-rules/00-pace-core-compliance.mdc +34 -2
  3. package/dist/{AuthService-BPvc3Ka0.d.ts → AuthService-Cb34EQs3.d.ts} +9 -1
  4. package/dist/{DataTable-TPTKCX4D.js → DataTable-E7YQZD7D.js} +9 -8
  5. package/dist/{PublicPageProvider-DC6kCaqf.d.ts → PublicPageProvider-DEMpysFR.d.ts} +45 -67
  6. package/dist/{UnifiedAuthProvider-CVcTjx-d.d.ts → UnifiedAuthProvider-CKvHP1MK.d.ts} +1 -8
  7. package/dist/{UnifiedAuthProvider-CH6Z342H.js → UnifiedAuthProvider-QPXO24B4.js} +5 -4
  8. package/dist/{api-MVVQZLJI.js → api-6LVZTHDS.js} +10 -10
  9. package/dist/{audit-B5P6FFIR.js → audit-V53FV5AG.js} +2 -2
  10. package/dist/chunk-36LVWXB2.js +227 -0
  11. package/dist/chunk-36LVWXB2.js.map +1 -0
  12. package/dist/{chunk-24UVZUZG.js → chunk-3LPHPB62.js} +129 -387
  13. package/dist/chunk-3LPHPB62.js.map +1 -0
  14. package/dist/{chunk-2UOI2FG5.js → chunk-5EC5MEWX.js} +4 -4
  15. package/dist/{chunk-3XC4CPTD.js → chunk-7JPAB3T5.js} +244 -5727
  16. package/dist/chunk-7JPAB3T5.js.map +1 -0
  17. package/dist/{chunk-6J4GEEJR.js → chunk-ATKZM7RX.js} +53 -27
  18. package/dist/chunk-ATKZM7RX.js.map +1 -0
  19. package/dist/{chunk-EHMR7VYL.js → chunk-AVMLPIM7.js} +443 -189
  20. package/dist/chunk-AVMLPIM7.js.map +1 -0
  21. package/dist/chunk-DGUM43GV.js +11 -0
  22. package/dist/{chunk-NECFR5MM.js → chunk-I6DAQMWX.js} +575 -647
  23. package/dist/chunk-I6DAQMWX.js.map +1 -0
  24. package/dist/{chunk-F2IMUDXZ.js → chunk-M7MPQISP.js} +2 -2
  25. package/dist/{chunk-XWQCNGTQ.js → chunk-NN6WWZ5U.js} +173 -79
  26. package/dist/chunk-NN6WWZ5U.js.map +1 -0
  27. package/dist/{chunk-MMZ7JXPU.js → chunk-OEWDTMG7.js} +13 -21
  28. package/dist/{chunk-MMZ7JXPU.js.map → chunk-OEWDTMG7.js.map} +1 -1
  29. package/dist/{chunk-SFZUDBL5.js → chunk-YKRAFF5K.js} +70 -56
  30. package/dist/chunk-YKRAFF5K.js.map +1 -0
  31. package/dist/components.d.ts +2 -2
  32. package/dist/components.js +12 -13
  33. package/dist/contextValidator-OOPCLPZW.js +9 -0
  34. package/dist/contextValidator-OOPCLPZW.js.map +1 -0
  35. package/dist/eslint-rules/pace-core-compliance.cjs +106 -0
  36. package/dist/hooks.d.ts +2 -2
  37. package/dist/hooks.js +7 -6
  38. package/dist/hooks.js.map +1 -1
  39. package/dist/index.d.ts +7 -7
  40. package/dist/index.js +21 -16
  41. package/dist/index.js.map +1 -1
  42. package/dist/providers.d.ts +3 -3
  43. package/dist/providers.js +4 -3
  44. package/dist/rbac/index.d.ts +67 -27
  45. package/dist/rbac/index.js +15 -8
  46. package/dist/styles/index.js +1 -1
  47. package/dist/theming/runtime.js +1 -1
  48. package/dist/types.js +1 -1
  49. package/dist/{usePublicRouteParams-1oMokgLF.d.ts → usePublicRouteParams-i3qtoBgg.d.ts} +7 -16
  50. package/dist/utils.js +5 -7
  51. package/dist/utils.js.map +1 -1
  52. package/docs/api/README.md +14 -16
  53. package/docs/api/modules.md +3796 -2513
  54. package/docs/components/context-selector.md +126 -0
  55. package/docs/migration/RBAC_SCOPE_MIGRATION.md +385 -0
  56. package/docs/pace-mint-fix-auto-selection.md +218 -0
  57. package/docs/pace-mint-rbac-setup.md +391 -0
  58. package/docs/rbac/secure-client-protection.md +330 -0
  59. package/package.json +10 -5
  60. package/scripts/audit/core/checks/compliance.cjs +72 -0
  61. package/scripts/audit/core/checks/dependencies.cjs +568 -28
  62. package/scripts/audit/core/checks/documentation.cjs +68 -3
  63. package/scripts/audit/core/checks/environment.cjs +2 -14
  64. package/scripts/audit/core/checks/error-handling.cjs +47 -6
  65. package/src/components/ContextSelector/ContextSelector.tsx +384 -0
  66. package/src/components/ContextSelector/index.ts +3 -0
  67. package/src/components/DataTable/components/RowComponent.tsx +19 -19
  68. package/src/components/DataTable/components/UnifiedTableBody.tsx +2 -2
  69. package/src/components/DataTable/hooks/useDataTablePermissions.ts +8 -6
  70. package/src/components/Dialog/Dialog.tsx +29 -1
  71. package/src/components/FileDisplay/FileDisplay.tsx +42 -10
  72. package/src/components/Header/Header.test.tsx +43 -73
  73. package/src/components/Header/Header.tsx +44 -45
  74. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +10 -19
  75. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +2 -2
  76. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +5 -5
  77. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +9 -9
  78. package/src/components/PaceAppLayout/PaceAppLayout.tsx +157 -36
  79. package/src/components/PaceAppLayout/README.md +14 -17
  80. package/src/components/PaceAppLayout/test-setup.tsx +2 -2
  81. package/src/components/index.ts +5 -5
  82. package/src/eslint-rules/pace-core-compliance.cjs +106 -0
  83. package/src/hooks/__tests__/useAppConfig.unit.test.ts +4 -98
  84. package/src/hooks/useAppConfig.ts +15 -30
  85. package/src/hooks/useFileDisplay.ts +77 -50
  86. package/src/index.ts +4 -5
  87. package/src/providers/services/AuthServiceProvider.tsx +17 -7
  88. package/src/providers/services/EventServiceProvider.tsx +33 -5
  89. package/src/providers/services/UnifiedAuthProvider.tsx +90 -134
  90. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +1 -1
  91. package/src/rbac/adapters.tsx +2 -2
  92. package/src/rbac/api.test.ts +59 -51
  93. package/src/rbac/api.ts +178 -132
  94. package/src/rbac/components/PagePermissionGuard.tsx +38 -10
  95. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +32 -21
  96. package/src/rbac/hooks/permissions/useAccessLevel.ts +1 -1
  97. package/src/rbac/hooks/permissions/useCan.ts +41 -11
  98. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +1 -1
  99. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +1 -1
  100. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +1 -1
  101. package/src/rbac/hooks/useCan.test.ts +0 -9
  102. package/src/rbac/hooks/useRBAC.test.ts +1 -5
  103. package/src/rbac/hooks/useRBAC.ts +36 -37
  104. package/src/rbac/hooks/useResolvedScope.test.ts +120 -35
  105. package/src/rbac/hooks/useResolvedScope.ts +35 -40
  106. package/src/rbac/hooks/useSecureSupabase.ts +7 -7
  107. package/src/rbac/index.ts +7 -0
  108. package/src/rbac/secureClient.test.ts +22 -18
  109. package/src/rbac/secureClient.ts +103 -16
  110. package/src/rbac/security.ts +0 -17
  111. package/src/rbac/types.ts +1 -0
  112. package/src/rbac/utils/__tests__/contextValidator.test.ts +64 -86
  113. package/src/rbac/utils/clientSecurity.ts +93 -0
  114. package/src/rbac/utils/contextValidator.ts +77 -168
  115. package/src/services/AuthService.ts +39 -7
  116. package/src/services/EventService.ts +285 -56
  117. package/src/services/OrganisationService.ts +81 -14
  118. package/src/services/__tests__/EventService.test.ts +1 -2
  119. package/src/services/base/BaseService.ts +3 -0
  120. package/src/utils/dynamic/dynamicUtils.ts +7 -4
  121. package/dist/chunk-24UVZUZG.js.map +0 -1
  122. package/dist/chunk-3XC4CPTD.js.map +0 -1
  123. package/dist/chunk-6J4GEEJR.js.map +0 -1
  124. package/dist/chunk-7D4SUZUM.js +0 -38
  125. package/dist/chunk-EHMR7VYL.js.map +0 -1
  126. package/dist/chunk-NECFR5MM.js.map +0 -1
  127. package/dist/chunk-SFZUDBL5.js.map +0 -1
  128. package/dist/chunk-XWQCNGTQ.js.map +0 -1
  129. package/docs/api/classes/ColumnFactory.md +0 -243
  130. package/docs/api/classes/InvalidScopeError.md +0 -73
  131. package/docs/api/classes/Logger.md +0 -178
  132. package/docs/api/classes/MissingUserContextError.md +0 -66
  133. package/docs/api/classes/OrganisationContextRequiredError.md +0 -66
  134. package/docs/api/classes/PermissionDeniedError.md +0 -73
  135. package/docs/api/classes/RBACAuditManager.md +0 -297
  136. package/docs/api/classes/RBACCache.md +0 -322
  137. package/docs/api/classes/RBACEngine.md +0 -171
  138. package/docs/api/classes/RBACError.md +0 -76
  139. package/docs/api/classes/RBACNotInitializedError.md +0 -66
  140. package/docs/api/classes/SecureSupabaseClient.md +0 -163
  141. package/docs/api/classes/StorageUtils.md +0 -328
  142. package/docs/api/enums/FileCategory.md +0 -184
  143. package/docs/api/enums/LogLevel.md +0 -54
  144. package/docs/api/enums/RBACErrorCode.md +0 -228
  145. package/docs/api/enums/RPCFunction.md +0 -118
  146. package/docs/api/interfaces/AddressFieldProps.md +0 -241
  147. package/docs/api/interfaces/AddressFieldRef.md +0 -94
  148. package/docs/api/interfaces/AggregateConfig.md +0 -43
  149. package/docs/api/interfaces/AutocompleteOptions.md +0 -75
  150. package/docs/api/interfaces/AvatarProps.md +0 -128
  151. package/docs/api/interfaces/BadgeProps.md +0 -34
  152. package/docs/api/interfaces/ButtonProps.md +0 -56
  153. package/docs/api/interfaces/CalendarProps.md +0 -73
  154. package/docs/api/interfaces/CardProps.md +0 -69
  155. package/docs/api/interfaces/ColorPalette.md +0 -7
  156. package/docs/api/interfaces/ColorShade.md +0 -66
  157. package/docs/api/interfaces/ComplianceResult.md +0 -30
  158. package/docs/api/interfaces/DataAccessRecord.md +0 -96
  159. package/docs/api/interfaces/DataRecord.md +0 -11
  160. package/docs/api/interfaces/DataTableAction.md +0 -252
  161. package/docs/api/interfaces/DataTableColumn.md +0 -504
  162. package/docs/api/interfaces/DataTableProps.md +0 -625
  163. package/docs/api/interfaces/DataTableToolbarButton.md +0 -96
  164. package/docs/api/interfaces/DatabaseComplianceResult.md +0 -85
  165. package/docs/api/interfaces/DatabaseIssue.md +0 -41
  166. package/docs/api/interfaces/EmptyStateConfig.md +0 -61
  167. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +0 -235
  168. package/docs/api/interfaces/ErrorBoundaryProps.md +0 -147
  169. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +0 -36
  170. package/docs/api/interfaces/ErrorBoundaryState.md +0 -75
  171. package/docs/api/interfaces/EventAppRoleData.md +0 -71
  172. package/docs/api/interfaces/ExportColumn.md +0 -90
  173. package/docs/api/interfaces/ExportOptions.md +0 -126
  174. package/docs/api/interfaces/FileDisplayProps.md +0 -249
  175. package/docs/api/interfaces/FileMetadata.md +0 -129
  176. package/docs/api/interfaces/FileReference.md +0 -118
  177. package/docs/api/interfaces/FileSizeLimits.md +0 -7
  178. package/docs/api/interfaces/FileUploadOptions.md +0 -139
  179. package/docs/api/interfaces/FileUploadProps.md +0 -296
  180. package/docs/api/interfaces/FooterProps.md +0 -107
  181. package/docs/api/interfaces/FormFieldProps.md +0 -166
  182. package/docs/api/interfaces/FormProps.md +0 -113
  183. package/docs/api/interfaces/GrantEventAppRoleParams.md +0 -122
  184. package/docs/api/interfaces/InactivityWarningModalProps.md +0 -115
  185. package/docs/api/interfaces/InputProps.md +0 -56
  186. package/docs/api/interfaces/LabelProps.md +0 -107
  187. package/docs/api/interfaces/LoggerConfig.md +0 -62
  188. package/docs/api/interfaces/LoginFormProps.md +0 -187
  189. package/docs/api/interfaces/NavigationAccessRecord.md +0 -107
  190. package/docs/api/interfaces/NavigationContextType.md +0 -164
  191. package/docs/api/interfaces/NavigationGuardProps.md +0 -139
  192. package/docs/api/interfaces/NavigationItem.md +0 -120
  193. package/docs/api/interfaces/NavigationMenuProps.md +0 -221
  194. package/docs/api/interfaces/NavigationProviderProps.md +0 -117
  195. package/docs/api/interfaces/Organisation.md +0 -140
  196. package/docs/api/interfaces/OrganisationContextType.md +0 -388
  197. package/docs/api/interfaces/OrganisationMembership.md +0 -140
  198. package/docs/api/interfaces/OrganisationProviderProps.md +0 -76
  199. package/docs/api/interfaces/OrganisationSecurityError.md +0 -62
  200. package/docs/api/interfaces/PaceAppLayoutProps.md +0 -409
  201. package/docs/api/interfaces/PaceLoginPageProps.md +0 -49
  202. package/docs/api/interfaces/PageAccessRecord.md +0 -85
  203. package/docs/api/interfaces/PagePermissionContextType.md +0 -140
  204. package/docs/api/interfaces/PagePermissionGuardProps.md +0 -153
  205. package/docs/api/interfaces/PagePermissionProviderProps.md +0 -119
  206. package/docs/api/interfaces/PaletteData.md +0 -41
  207. package/docs/api/interfaces/ParsedAddress.md +0 -120
  208. package/docs/api/interfaces/PermissionEnforcerProps.md +0 -153
  209. package/docs/api/interfaces/ProgressProps.md +0 -42
  210. package/docs/api/interfaces/ProtectedRouteProps.md +0 -78
  211. package/docs/api/interfaces/PublicPageFooterProps.md +0 -112
  212. package/docs/api/interfaces/PublicPageHeaderProps.md +0 -125
  213. package/docs/api/interfaces/PublicPageLayoutProps.md +0 -185
  214. package/docs/api/interfaces/QuickFix.md +0 -52
  215. package/docs/api/interfaces/RBACAccessValidateParams.md +0 -52
  216. package/docs/api/interfaces/RBACAccessValidateResult.md +0 -41
  217. package/docs/api/interfaces/RBACAuditLogParams.md +0 -85
  218. package/docs/api/interfaces/RBACAuditLogResult.md +0 -52
  219. package/docs/api/interfaces/RBACConfig.md +0 -133
  220. package/docs/api/interfaces/RBACContext.md +0 -52
  221. package/docs/api/interfaces/RBACLogger.md +0 -112
  222. package/docs/api/interfaces/RBACPageAccessCheckParams.md +0 -74
  223. package/docs/api/interfaces/RBACPerformanceMetrics.md +0 -138
  224. package/docs/api/interfaces/RBACPermissionCheckParams.md +0 -74
  225. package/docs/api/interfaces/RBACPermissionCheckResult.md +0 -52
  226. package/docs/api/interfaces/RBACPermissionsGetParams.md +0 -63
  227. package/docs/api/interfaces/RBACPermissionsGetResult.md +0 -63
  228. package/docs/api/interfaces/RBACResult.md +0 -58
  229. package/docs/api/interfaces/RBACRoleGrantParams.md +0 -63
  230. package/docs/api/interfaces/RBACRoleGrantResult.md +0 -52
  231. package/docs/api/interfaces/RBACRoleRevokeParams.md +0 -63
  232. package/docs/api/interfaces/RBACRoleRevokeResult.md +0 -52
  233. package/docs/api/interfaces/RBACRoleValidateParams.md +0 -52
  234. package/docs/api/interfaces/RBACRoleValidateResult.md +0 -63
  235. package/docs/api/interfaces/RBACRolesListParams.md +0 -52
  236. package/docs/api/interfaces/RBACRolesListResult.md +0 -74
  237. package/docs/api/interfaces/RBACSessionTrackParams.md +0 -74
  238. package/docs/api/interfaces/RBACSessionTrackResult.md +0 -52
  239. package/docs/api/interfaces/ResourcePermissions.md +0 -155
  240. package/docs/api/interfaces/RevokeEventAppRoleParams.md +0 -100
  241. package/docs/api/interfaces/RoleBasedRouterContextType.md +0 -151
  242. package/docs/api/interfaces/RoleBasedRouterProps.md +0 -156
  243. package/docs/api/interfaces/RoleManagementResult.md +0 -52
  244. package/docs/api/interfaces/RouteAccessRecord.md +0 -107
  245. package/docs/api/interfaces/RouteConfig.md +0 -134
  246. package/docs/api/interfaces/RuntimeComplianceResult.md +0 -55
  247. package/docs/api/interfaces/SecureDataContextType.md +0 -168
  248. package/docs/api/interfaces/SecureDataProviderProps.md +0 -132
  249. package/docs/api/interfaces/SessionRestorationLoaderProps.md +0 -34
  250. package/docs/api/interfaces/SetupIssue.md +0 -41
  251. package/docs/api/interfaces/StorageConfig.md +0 -41
  252. package/docs/api/interfaces/StorageFileInfo.md +0 -74
  253. package/docs/api/interfaces/StorageFileMetadata.md +0 -151
  254. package/docs/api/interfaces/StorageListOptions.md +0 -99
  255. package/docs/api/interfaces/StorageListResult.md +0 -41
  256. package/docs/api/interfaces/StorageUploadOptions.md +0 -101
  257. package/docs/api/interfaces/StorageUploadResult.md +0 -63
  258. package/docs/api/interfaces/StorageUrlOptions.md +0 -60
  259. package/docs/api/interfaces/StyleImport.md +0 -19
  260. package/docs/api/interfaces/SwitchProps.md +0 -34
  261. package/docs/api/interfaces/TabsContentProps.md +0 -9
  262. package/docs/api/interfaces/TabsListProps.md +0 -9
  263. package/docs/api/interfaces/TabsProps.md +0 -9
  264. package/docs/api/interfaces/TabsTriggerProps.md +0 -50
  265. package/docs/api/interfaces/TextareaProps.md +0 -53
  266. package/docs/api/interfaces/ToastActionElement.md +0 -12
  267. package/docs/api/interfaces/ToastProps.md +0 -9
  268. package/docs/api/interfaces/UnifiedAuthContextType.md +0 -823
  269. package/docs/api/interfaces/UnifiedAuthProviderProps.md +0 -173
  270. package/docs/api/interfaces/UseFormDialogOptions.md +0 -62
  271. package/docs/api/interfaces/UseFormDialogReturn.md +0 -117
  272. package/docs/api/interfaces/UseInactivityTrackerOptions.md +0 -138
  273. package/docs/api/interfaces/UseInactivityTrackerReturn.md +0 -123
  274. package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
  275. package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -84
  276. package/docs/api/interfaces/UsePublicEventOptions.md +0 -34
  277. package/docs/api/interfaces/UsePublicEventReturn.md +0 -71
  278. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +0 -47
  279. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +0 -123
  280. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +0 -97
  281. package/docs/api/interfaces/UseResolvedScopeOptions.md +0 -47
  282. package/docs/api/interfaces/UseResolvedScopeReturn.md +0 -47
  283. package/docs/api/interfaces/UseResourcePermissionsOptions.md +0 -34
  284. package/docs/api/interfaces/UserEventAccess.md +0 -121
  285. package/docs/api/interfaces/UserMenuProps.md +0 -88
  286. package/docs/api/interfaces/UserProfile.md +0 -63
  287. package/src/components/EventSelector/EventSelector.test.tsx +0 -720
  288. package/src/components/EventSelector/EventSelector.tsx +0 -423
  289. package/src/components/EventSelector/index.ts +0 -3
  290. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +0 -784
  291. package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -327
  292. package/src/components/OrganisationSelector/index.ts +0 -9
  293. /package/dist/{DataTable-TPTKCX4D.js.map → DataTable-E7YQZD7D.js.map} +0 -0
  294. /package/dist/{UnifiedAuthProvider-CH6Z342H.js.map → UnifiedAuthProvider-QPXO24B4.js.map} +0 -0
  295. /package/dist/{api-MVVQZLJI.js.map → api-6LVZTHDS.js.map} +0 -0
  296. /package/dist/{audit-B5P6FFIR.js.map → audit-V53FV5AG.js.map} +0 -0
  297. /package/dist/{chunk-2UOI2FG5.js.map → chunk-5EC5MEWX.js.map} +0 -0
  298. /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
  299. /package/dist/{chunk-F2IMUDXZ.js.map → chunk-M7MPQISP.js.map} +0 -0
@@ -0,0 +1,126 @@
1
+ # Context Selector - Unified Intelligent Selector
2
+
3
+ ## Overview
4
+
5
+ The `ContextSelector` (formerly `HybridContextSelector`) is the **single unified selector** for all pace-core applications. It intelligently shows all organisations and events a user can access based on their roles and permissions.
6
+
7
+ ## Why Unified Selector?
8
+
9
+ Previously, apps had to choose between:
10
+ - `OrganisationSelector` - for org-based apps
11
+ - `EventSelector` - for event-based apps
12
+ - `HybridContextSelector` - for hybrid apps
13
+
14
+ This created complexity and required apps to know their scope type upfront. With page-level scope, we can now intelligently show **everything** the user can access in one place.
15
+
16
+ ## How It Works
17
+
18
+ The `ContextSelector` automatically:
19
+
20
+ 1. **Shows all accessible organisations** - Based on user's organisation roles
21
+ 2. **Shows all accessible events** - Based on user's event-app roles and organisation membership
22
+ 3. **Groups items intelligently** - Organisations and Events in separate sections
23
+ 4. **Handles super admins** - Shows all orgs and events
24
+ 5. **Respects permissions** - Only shows what user can actually access
25
+
26
+ ## Usage
27
+
28
+ ### Basic Usage
29
+
30
+ ```tsx
31
+ import { ContextSelector } from '@jmruthers/pace-core';
32
+
33
+ function MyHeader() {
34
+ const { switchOrganisation } = useOrganisations();
35
+ const { events, setSelectedEvent } = useEvents();
36
+
37
+ return (
38
+ <ContextSelector
39
+ onOrganisationSelect={(org) => switchOrganisation(org.id)}
40
+ onEventSelect={(event) => {
41
+ const fullEvent = events.find(e => e.event_id === event.event_id);
42
+ setSelectedEvent(fullEvent || event);
43
+ }}
44
+ />
45
+ );
46
+ }
47
+ ```
48
+
49
+ ### In Header Component
50
+
51
+ The `Header` component now uses `ContextSelector` by default:
52
+
53
+ ```tsx
54
+ <Header
55
+ logoUrl="/logo.svg"
56
+ showContextSelector={true} // Default: shows unified selector
57
+ user={user}
58
+ onSignOut={handleSignOut}
59
+ />
60
+ ```
61
+
62
+ ### In PaceAppLayout
63
+
64
+ ```tsx
65
+ <PaceAppLayout
66
+ appName="MINT"
67
+ showContextSelector={true} // Default: shows unified selector
68
+ navItems={navItems}
69
+ >
70
+ {children}
71
+ </PaceAppLayout>
72
+ ```
73
+
74
+ ## Migration from Separate Selectors
75
+
76
+ ### Before (Separate Selectors)
77
+
78
+ ```tsx
79
+ <Header
80
+ showOrgSelector={true}
81
+ showEventSelector={true}
82
+ // ...
83
+ />
84
+ ```
85
+
86
+ ### After (Unified Selector)
87
+
88
+ ```tsx
89
+ <Header
90
+ showContextSelector={true} // Single prop replaces both
91
+ // ...
92
+ />
93
+ ```
94
+
95
+ ## Benefits
96
+
97
+ 1. **Simpler API** - One selector instead of three
98
+ 2. **Better UX** - Users see everything they can access in one place
99
+ 3. **Intelligent** - Automatically determines what to show based on permissions
100
+ 4. **Future-proof** - Works with any app configuration (org-based, event-based, hybrid)
101
+ 5. **No configuration needed** - Just use it, it figures out what to show
102
+
103
+ ## Migration from Separate Selectors
104
+
105
+ **⚠️ BREAKING CHANGE**: The separate selectors have been removed. You must migrate to `ContextSelector`.
106
+
107
+ ### Removed Components
108
+ - `OrganisationSelector` - Use `ContextSelector` instead
109
+ - `EventSelector` - Use `ContextSelector` instead
110
+ - `HybridContextSelector` - Use `ContextSelector` instead
111
+
112
+ ### Removed Props
113
+ - `Header.showEventSelector` - Use `showContextSelector` instead
114
+ - `Header.showOrgSelector` - Use `showContextSelector` instead
115
+ - `PaceAppLayout.showEventSelector` - Use `showContextSelector` instead
116
+ - `PaceAppLayout.showOrgSelector` - Use `showContextSelector` instead
117
+
118
+ ## Implementation Details
119
+
120
+ The selector uses:
121
+ - `useOrganisations()` - Gets accessible organisations
122
+ - `useEvents()` - Gets accessible events (already filtered by permissions)
123
+ - `useRBAC()` - Checks super admin status
124
+
125
+ Both hooks already filter based on user permissions, so the selector automatically shows the correct items.
126
+
@@ -0,0 +1,385 @@
1
+ # RBAC Scope Migration Guide
2
+
3
+ ## Overview
4
+
5
+ This migration moves RBAC scope from app-level (`rbac_apps.requires_event`) to page-level (`rbac_app_pages.scope_type`). This enables hybrid apps like `pace-mint` to have both event-based and organisation-based pages within the same app.
6
+
7
+ **⚠️ BREAKING CHANGE**: This migration removes app-level scope configuration entirely. All scope is now configured at the page level with no backward compatibility.
8
+
9
+ ## What Changed
10
+
11
+ **Removed**: App-level scope configuration (`rbac_apps.requires_event`)
12
+ **Now**: Page-level scope only (`rbac_app_pages.scope_type`)
13
+
14
+ ### Why This Change?
15
+
16
+ 1. **Single Source of Truth**: Scope is stored in one place (page-level), making it easier to understand and maintain
17
+ 2. **More Flexible**: Each page can have its own scope, enabling hybrid apps like pace-mint
18
+ 3. **Simpler Queries**: No need to join with `rbac_apps` to determine scope
19
+ 4. **More Explicit**: No inheritance logic - scope is always clear from the page itself
20
+ 5. **No Backward Compatibility Overhead**: Clean break from old patterns
21
+
22
+ ## Breaking Changes
23
+
24
+ ### Removed APIs
25
+
26
+ 1. **`UnifiedAuthProvider.appConfig` prop** - No longer needed
27
+ 2. **`useAppConfig().requiresEvent`** - Use `getPageScopeType(pageId)` instead
28
+ 3. **`useAppConfig().supportsDirectAccess`** - No longer relevant
29
+ 4. **`ContextValidator.validateScope()`** - Use `resolveScopeForPage()` instead
30
+ 5. **`ContextValidator.resolveRequiredContext()`** - Use `resolveScopeForPage()` instead
31
+ 6. **`ContextValidator.isContextReady()`** - Context readiness checked per page
32
+ 7. **`RBACSecurityValidator.validateContextRequirements()`** - No longer needed
33
+ 8. **`getAppConfig()`, `getAppConfigByName()`, `getAppConfigWithClient()`** - Use `getPageScopeType()` instead
34
+
35
+ ### Changed APIs
36
+
37
+ 1. **`useRBAC(pageId)`** - Now requires `pageId` parameter for proper scope resolution
38
+ 2. **`getPermissionMap()`, `getRoleContext()`, `getAccessLevel()`, `isPermitted()`** - No longer accept `appConfig` parameter
39
+
40
+ ### Removed Components
41
+
42
+ - `OrganisationSelector` - Use `ContextSelector` instead
43
+ - `EventSelector` - Use `ContextSelector` instead
44
+ - `HybridContextSelector` - Use `ContextSelector` instead
45
+
46
+ ### Removed Props
47
+
48
+ - `Header.showEventSelector` - Use `showContextSelector` instead
49
+ - `Header.showOrgSelector` - Use `showContextSelector` instead
50
+ - `PaceAppLayout.showEventSelector` - Use `showContextSelector` instead
51
+ - `PaceAppLayout.showOrgSelector` - Use `showContextSelector` instead
52
+
53
+ ## Migration Steps
54
+
55
+ ### Step 1: Run Database Migration
56
+
57
+ Run the migration to populate `rbac_app_pages.scope_type`:
58
+
59
+ ```bash
60
+ supabase migration up
61
+ ```
62
+
63
+ **Migration 1:** `supabase/migrations/20251231124932_add_page_scope_type_to_rbac_app_pages.sql`
64
+ - Adds `scope_type` column to `rbac_app_pages`
65
+ - Populates `scope_type` for all existing pages based on their app's `requires_event`
66
+ - Makes `scope_type` NOT NULL (required for all pages)
67
+ - Creates `get_page_scope_type()` function
68
+ - **Drops `rbac_apps.requires_event` column** (no longer needed)
69
+
70
+ **Migration 2:** `supabase/migrations/20251231131610_update_rpc_functions_remove_requires_event.sql`
71
+ - Updates `data_rbac_apps_list` to remove `requires_event` from return type
72
+ - Updates `data_user_events_get` to remove `requires_event` check (always checks event app roles if app_id provided)
73
+
74
+ ### Step 2: Verify Page Scope Types
75
+
76
+ Check that all pages have `scope_type` set:
77
+
78
+ ```sql
79
+ -- Check for any pages without scope_type (should return 0 rows after migration)
80
+ SELECT
81
+ ap.page_name,
82
+ ap.scope_type,
83
+ a.name as app_name
84
+ FROM rbac_app_pages ap
85
+ JOIN rbac_apps a ON ap.app_id = a.id
86
+ WHERE ap.scope_type IS NULL;
87
+ ```
88
+
89
+ If any pages have `NULL` scope_type after migration, update them:
90
+
91
+ ```sql
92
+ -- For event-based pages
93
+ UPDATE rbac_app_pages
94
+ SET scope_type = 'event'
95
+ WHERE page_name = 'your-page-name'
96
+ AND app_id = (SELECT id FROM rbac_apps WHERE name = 'YOUR_APP');
97
+
98
+ -- For organisation-based pages
99
+ UPDATE rbac_app_pages
100
+ SET scope_type = 'organisation'
101
+ WHERE page_name = 'your-page-name'
102
+ AND app_id = (SELECT id FROM rbac_apps WHERE name = 'YOUR_APP');
103
+ ```
104
+
105
+ ### Step 3: Update UnifiedAuthProvider
106
+
107
+ **Before:**
108
+ ```tsx
109
+ <UnifiedAuthProvider
110
+ appConfig={{ requires_event: true }}
111
+ // ... other props
112
+ >
113
+ {children}
114
+ </UnifiedAuthProvider>
115
+ ```
116
+
117
+ **After:**
118
+ ```tsx
119
+ <UnifiedAuthProvider
120
+ // appConfig prop removed - scope is now page-level
121
+ // ... other props
122
+ >
123
+ {children}
124
+ </UnifiedAuthProvider>
125
+ ```
126
+
127
+ ### Step 4: Update useRBAC Calls
128
+
129
+ **Before:**
130
+ ```tsx
131
+ const { permissionMap } = useRBAC(); // No pageId
132
+ ```
133
+
134
+ **After:**
135
+ ```tsx
136
+ const { permissionMap } = useRBAC(pageId); // Pass pageId for proper scope resolution
137
+ ```
138
+
139
+ ### Step 5: Replace useAppConfig Usage
140
+
141
+ **Before:**
142
+ ```tsx
143
+ const { requiresEvent, supportsDirectAccess } = useAppConfig();
144
+
145
+ if (requiresEvent) {
146
+ // Show event selector
147
+ }
148
+ ```
149
+
150
+ **After:**
151
+ ```tsx
152
+ import { getPageScopeType } from '@jmruthers/pace-core';
153
+
154
+ const pageScopeType = await getPageScopeType(pageId, appId, appName);
155
+
156
+ if (pageScopeType === 'event' || pageScopeType === 'both') {
157
+ // Show event selector (or use ContextSelector which handles this automatically)
158
+ }
159
+ ```
160
+
161
+ ### Step 6: Update ContextValidator Usage
162
+
163
+ **Before:**
164
+ ```tsx
165
+ import { ContextValidator } from '@jmruthers/pace-core';
166
+
167
+ const validation = await ContextValidator.resolveRequiredContext(
168
+ scope,
169
+ appConfig,
170
+ appName,
171
+ supabase
172
+ );
173
+ ```
174
+
175
+ **After:**
176
+ ```tsx
177
+ import { ContextValidator, getPageScopeType } from '@jmruthers/pace-core';
178
+
179
+ const pageScopeType = await getPageScopeType(pageId, appId, appName);
180
+ const validation = await ContextValidator.resolveScopeForPage(
181
+ scope,
182
+ pageScopeType,
183
+ appName,
184
+ supabase
185
+ );
186
+ ```
187
+
188
+ ### Step 7: Update Permission Checks
189
+
190
+ **Before:**
191
+ ```tsx
192
+ const permissionMap = await getPermissionMap(
193
+ { userId, scope },
194
+ appConfig,
195
+ appName
196
+ );
197
+ ```
198
+
199
+ **After:**
200
+ ```tsx
201
+ const permissionMap = await getPermissionMap(
202
+ { userId, scope }
203
+ // appConfig and appName no longer needed
204
+ );
205
+ ```
206
+
207
+ ### Step 8: Update Selector Components
208
+
209
+ **Before:**
210
+ ```tsx
211
+ <Header
212
+ showOrgSelector={true}
213
+ showEventSelector={true}
214
+ />
215
+ ```
216
+
217
+ **After:**
218
+ ```tsx
219
+ <Header
220
+ showContextSelector={true} // Single unified selector
221
+ />
222
+ ```
223
+
224
+ ## Page Scope Types
225
+
226
+ After migration, all pages must have one of these `scope_type` values:
227
+
228
+ ### `'event'`
229
+ Page requires event context. Organisation is derived from event.
230
+
231
+ ### `'organisation'`
232
+ Page requires organisation context. Event is optional.
233
+
234
+ ### `'both'`
235
+ Page can be accessed with either event or organisation context. Permissions are merged (union), with higher permissions taking precedence.
236
+
237
+ ## Creating New Pages
238
+
239
+ When creating new pages, always set `scope_type` explicitly:
240
+
241
+ ```sql
242
+ -- Create an event-based page
243
+ INSERT INTO rbac_app_pages (app_id, page_name, page_description, scope_type)
244
+ VALUES (
245
+ (SELECT id FROM rbac_apps WHERE name = 'MINT'),
246
+ 'budget',
247
+ 'Event Budget Management',
248
+ 'event' -- ✅ Explicit scope type
249
+ );
250
+
251
+ -- Create an organisation-based page
252
+ INSERT INTO rbac_app_pages (app_id, page_name, page_description, scope_type)
253
+ VALUES (
254
+ (SELECT id FROM rbac_apps WHERE name = 'MINT'),
255
+ 'dashboard',
256
+ 'Organisation Dashboard',
257
+ 'organisation' -- ✅ Explicit scope type
258
+ );
259
+
260
+ -- Create a 'both' page (can use either context)
261
+ INSERT INTO rbac_app_pages (app_id, page_name, page_description, scope_type)
262
+ VALUES (
263
+ (SELECT id FROM rbac_apps WHERE name = 'MINT'),
264
+ 'reports',
265
+ 'Reports (Event or Organisation)',
266
+ 'both' -- ✅ Can be accessed with either context
267
+ );
268
+ ```
269
+
270
+ ## Hybrid Apps (e.g., pace-mint)
271
+
272
+ For apps that have both event-based and organisation-based pages:
273
+
274
+ 1. Set `scope_type = 'event'` for event-based pages (e.g., budget pages)
275
+ 2. Set `scope_type = 'organisation'` for organisation-based pages (e.g., settings pages)
276
+ 3. Set `scope_type = 'both'` for pages that can use either context
277
+
278
+ Example:
279
+ ```sql
280
+ -- Event-based budget page
281
+ UPDATE rbac_app_pages
282
+ SET scope_type = 'event'
283
+ WHERE page_name = 'budget' AND app_id = (SELECT id FROM rbac_apps WHERE name = 'MINT');
284
+
285
+ -- Organisation-based settings page
286
+ UPDATE rbac_app_pages
287
+ SET scope_type = 'organisation'
288
+ WHERE page_name = 'settings' AND app_id = (SELECT id FROM rbac_apps WHERE name = 'MINT');
289
+ ```
290
+
291
+ ## API Changes Summary
292
+
293
+ ### `getPageScopeType()`
294
+
295
+ **Before**: Could return `null` (inherit from app)
296
+
297
+ **After**: Always returns a value (`'event'`, `'organisation'`, or `'both'`)
298
+
299
+ ```typescript
300
+ // After migration, this always returns a value
301
+ const scopeType = await getPageScopeType(pageId, appId, appName);
302
+ // scopeType is now: 'event' | 'organisation' | 'both' (never null)
303
+ ```
304
+
305
+ ### `resolveScopeForPage()`
306
+
307
+ **Before**: Accepted `appConfig` parameter and could inherit from app
308
+
309
+ **After**: `pageScopeType` is required (never null), `appConfig` removed
310
+
311
+ ```typescript
312
+ // After migration
313
+ const validation = await ContextValidator.resolveScopeForPage(
314
+ scope,
315
+ pageScopeType, // Required, never null
316
+ appName,
317
+ supabase
318
+ );
319
+ ```
320
+
321
+ ## Benefits
322
+
323
+ 1. **Clearer Intent**: Each page explicitly declares its scope requirements
324
+ 2. **Easier Debugging**: No need to trace through app-level config to understand page scope
325
+ 3. **Better Performance**: Direct lookup from page table, no join needed
326
+ 4. **More Flexible**: Hybrid apps can have mixed scopes without special handling
327
+ 5. **No Backward Compatibility Overhead**: Clean, maintainable codebase
328
+
329
+ ## Testing Checklist
330
+
331
+ - [ ] Database migration completed successfully
332
+ - [ ] All pages have `scope_type` set (no NULL values)
333
+ - [ ] `UnifiedAuthProvider` no longer uses `appConfig` prop
334
+ - [ ] All `useRBAC()` calls pass `pageId` parameter
335
+ - [ ] All `useAppConfig().requiresEvent` replaced with `getPageScopeType()`
336
+ - [ ] All deprecated `ContextValidator` methods replaced
337
+ - [ ] All selector components updated to use `ContextSelector`
338
+ - [ ] Permission checks work correctly for all page types
339
+ - [ ] Event-based pages work correctly
340
+ - [ ] Organisation-based pages work correctly
341
+ - [ ] Hybrid pages (scope_type = 'both') work correctly
342
+
343
+ ## Troubleshooting
344
+
345
+ ### Pages Not Showing in Navigation
346
+
347
+ If pages aren't showing after migration:
348
+
349
+ 1. **Check scope_type is set**:
350
+ ```sql
351
+ SELECT page_name, scope_type FROM rbac_app_pages WHERE app_id = 'your-app-id';
352
+ ```
353
+
354
+ 2. **Verify scope matches context**:
355
+ - Event-based pages require `eventId` to be selected
356
+ - Organisation-based pages require `organisationId` to be selected
357
+ - 'both' pages work with either context
358
+
359
+ 3. **Check permissions**: Ensure user has permissions for the page in the correct scope
360
+
361
+ ### Permission Denied Errors
362
+
363
+ If you get permission denied errors:
364
+
365
+ 1. **Verify scope_type matches selected context**:
366
+ - If page is `'event'`, ensure an event is selected
367
+ - If page is `'organisation'`, ensure an organisation is selected
368
+
369
+ 2. **Check page permissions are configured** for the correct scope type
370
+
371
+ 3. **Verify user's roles are active** (valid_from/valid_to dates)
372
+
373
+ ### ContextSelector Not Showing Items
374
+
375
+ 1. Check user has organisation memberships or event-app roles
376
+ 2. Verify organisations/events are active
377
+ 3. Check RLS policies allow user to see the items
378
+ 4. Ensure super admin status if testing as super admin
379
+
380
+ ## Related Documentation
381
+
382
+ - [pace-mint RBAC Setup Guide](../pace-mint-rbac-setup.md) - Specific guide for hybrid apps
383
+ - [Context Selector Component](../components/context-selector.md) - Unified selector documentation
384
+ - [RBAC System Overview](../rbac/README.md) - General RBAC documentation
385
+ - [Event-Based Apps](../rbac/event-based-apps.md) - Event-based app patterns