@jmruthers/pace-core 0.5.190 → 0.5.193

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 (334) hide show
  1. package/dist/{AuthService-CbP_utw2.d.ts → AuthService-DjnJHDtC.d.ts} +1 -0
  2. package/dist/{DataTable-ON3IXISJ.js → DataTable-5FU7IESH.js} +7 -6
  3. package/dist/{DataTable-IVYljGJ6.d.ts → DataTable-Be6dH_dR.d.ts} +1 -1
  4. package/dist/{PublicPageProvider-C4uxosp6.d.ts → PublicPageProvider-C0Sm_e5k.d.ts} +4 -2
  5. package/dist/{UnifiedAuthProvider-BYA9qB-o.d.ts → UnifiedAuthProvider-185Ih4dj.d.ts} +2 -0
  6. package/dist/{UnifiedAuthProvider-X5NXANVI.js → UnifiedAuthProvider-RGJTDE2C.js} +3 -3
  7. package/dist/{api-I6UCQ5S6.js → api-N774RPUA.js} +2 -2
  8. package/dist/chunk-6C4YBBJM 5.js +628 -0
  9. package/dist/chunk-7D4SUZUM.js 2.map +1 -0
  10. package/dist/{chunk-73HSNNOQ.js → chunk-7EQTDTTJ.js} +47 -74
  11. package/dist/chunk-7EQTDTTJ.js 2.map +1 -0
  12. package/dist/chunk-7EQTDTTJ.js.map +1 -0
  13. package/dist/{chunk-J2XXC7R5.js → chunk-7FLMSG37.js} +409 -244
  14. package/dist/chunk-7FLMSG37.js 2.map +1 -0
  15. package/dist/chunk-7FLMSG37.js.map +1 -0
  16. package/dist/{chunk-NIU6J6OX.js → chunk-BC4IJKSL.js} +23 -32
  17. package/dist/chunk-BC4IJKSL.js.map +1 -0
  18. package/dist/{chunk-SDMHPX3X.js → chunk-E3SPN4VZ 5.js } +198 -53
  19. package/dist/chunk-E3SPN4VZ.js +12917 -0
  20. package/dist/{chunk-SDMHPX3X.js.map → chunk-E3SPN4VZ.js.map} +1 -1
  21. package/dist/chunk-E66EQZE6 5.js +37 -0
  22. package/dist/chunk-E66EQZE6.js 2.map +1 -0
  23. package/dist/{chunk-DZWK57KZ.js → chunk-G37KK66H.js} +1 -1
  24. package/dist/{chunk-DZWK57KZ.js.map → chunk-G37KK66H.js.map} +1 -1
  25. package/dist/{chunk-STYK4OH2.js → chunk-HWIIPPNI.js} +44 -225
  26. package/dist/chunk-HWIIPPNI.js.map +1 -0
  27. package/dist/chunk-I7PSE6JW 5.js +191 -0
  28. package/dist/chunk-I7PSE6JW.js 2.map +1 -0
  29. package/dist/{chunk-Y4BUBBHD.js → chunk-IIELH4DL.js} +211 -136
  30. package/dist/chunk-IIELH4DL.js.map +1 -0
  31. package/dist/{chunk-RUYZKXOD.js → chunk-KNC55RTG.js} +17 -5
  32. package/dist/chunk-KNC55RTG.js 5.map +1 -0
  33. package/dist/chunk-KNC55RTG.js.map +1 -0
  34. package/dist/chunk-KQCRWDSA.js 5.map +1 -0
  35. package/dist/{chunk-4QYC5L4K.js → chunk-LFNCN2SP.js} +26 -30
  36. package/dist/chunk-LFNCN2SP.js 2.map +1 -0
  37. package/dist/chunk-LFNCN2SP.js.map +1 -0
  38. package/dist/chunk-LMC26NLJ 2.js +84 -0
  39. package/dist/{chunk-VVBAW5A5.js → chunk-NOAYCWCX 5.js } +118 -110
  40. package/dist/chunk-NOAYCWCX.js +4993 -0
  41. package/dist/chunk-NOAYCWCX.js.map +1 -0
  42. package/dist/chunk-QWWZ5CAQ.js 3.map +1 -0
  43. package/dist/chunk-QXHPKYJV 3.js +113 -0
  44. package/dist/chunk-R77UEZ4E 3.js +68 -0
  45. package/dist/chunk-VBXEHIUJ.js 6.map +1 -0
  46. package/dist/{chunk-HQVPB5MZ.js → chunk-XNXXZ43G.js} +77 -33
  47. package/dist/chunk-XNXXZ43G.js.map +1 -0
  48. package/dist/chunk-ZSAAAMVR 6.js +25 -0
  49. package/dist/components.d.ts +4 -4
  50. package/dist/components.js +8 -8
  51. package/dist/components.js 5.map +1 -0
  52. package/dist/{database.generated-DI89OQeI.d.ts → database.generated-CzIvgcPu.d.ts} +165 -201
  53. package/dist/hooks.d.ts +12 -12
  54. package/dist/hooks.js +9 -9
  55. package/dist/index.d.ts +11 -11
  56. package/dist/index.js +20 -27
  57. package/dist/index.js.map +1 -1
  58. package/dist/providers.d.ts +3 -3
  59. package/dist/providers.js +2 -2
  60. package/dist/rbac/index.d.ts +2 -20
  61. package/dist/rbac/index.js +7 -9
  62. package/dist/styles/index 2.js +12 -0
  63. package/dist/styles/index.js 5.map +1 -0
  64. package/dist/theming/runtime 5.js +19 -0
  65. package/dist/theming/runtime.js 5.map +1 -0
  66. package/dist/{types-Bwgl--Xo.d.ts → types-CEpcvwwF.d.ts} +1 -1
  67. package/dist/types.d.ts +2 -2
  68. package/dist/{usePublicRouteParams-DxIDS4bC.d.ts → usePublicRouteParams-TZe0gy-4.d.ts} +1 -1
  69. package/dist/utils.d.ts +8 -8
  70. package/dist/utils.js +2 -2
  71. package/docs/api/classes/ColumnFactory.md +1 -1
  72. package/docs/api/classes/ErrorBoundary.md +1 -1
  73. package/docs/api/classes/InvalidScopeError.md +1 -1
  74. package/docs/api/classes/Logger.md +1 -1
  75. package/docs/api/classes/MissingUserContextError.md +1 -1
  76. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  77. package/docs/api/classes/PermissionDeniedError.md +2 -2
  78. package/docs/api/classes/RBACAuditManager.md +2 -2
  79. package/docs/api/classes/RBACCache.md +1 -1
  80. package/docs/api/classes/RBACEngine.md +2 -2
  81. package/docs/api/classes/RBACError.md +1 -1
  82. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  83. package/docs/api/classes/SecureSupabaseClient.md +10 -10
  84. package/docs/api/classes/StorageUtils.md +1 -1
  85. package/docs/api/enums/FileCategory.md +1 -1
  86. package/docs/api/enums/LogLevel.md +1 -1
  87. package/docs/api/enums/RBACErrorCode.md +1 -1
  88. package/docs/api/enums/RPCFunction.md +1 -1
  89. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  90. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  91. package/docs/api/interfaces/AggregateConfig.md +1 -1
  92. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  93. package/docs/api/interfaces/AvatarProps.md +1 -1
  94. package/docs/api/interfaces/BadgeProps.md +1 -1
  95. package/docs/api/interfaces/ButtonProps.md +1 -1
  96. package/docs/api/interfaces/CalendarProps.md +1 -1
  97. package/docs/api/interfaces/CardProps.md +1 -1
  98. package/docs/api/interfaces/ColorPalette.md +1 -1
  99. package/docs/api/interfaces/ColorShade.md +1 -1
  100. package/docs/api/interfaces/ComplianceResult.md +1 -1
  101. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  102. package/docs/api/interfaces/DataRecord.md +1 -1
  103. package/docs/api/interfaces/DataTableAction.md +1 -1
  104. package/docs/api/interfaces/DataTableColumn.md +1 -1
  105. package/docs/api/interfaces/DataTableProps.md +1 -1
  106. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  107. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  108. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  109. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  110. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  111. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  112. package/docs/api/interfaces/ExportColumn.md +1 -1
  113. package/docs/api/interfaces/ExportOptions.md +1 -1
  114. package/docs/api/interfaces/FileDisplayProps.md +24 -11
  115. package/docs/api/interfaces/FileMetadata.md +1 -1
  116. package/docs/api/interfaces/FileReference.md +1 -1
  117. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  118. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  119. package/docs/api/interfaces/FileUploadProps.md +1 -1
  120. package/docs/api/interfaces/FooterProps.md +1 -1
  121. package/docs/api/interfaces/FormFieldProps.md +1 -1
  122. package/docs/api/interfaces/FormProps.md +1 -1
  123. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  124. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  125. package/docs/api/interfaces/InputProps.md +1 -1
  126. package/docs/api/interfaces/LabelProps.md +1 -1
  127. package/docs/api/interfaces/LoggerConfig.md +1 -1
  128. package/docs/api/interfaces/LoginFormProps.md +1 -1
  129. package/docs/api/interfaces/NavigationAccessRecord.md +2 -2
  130. package/docs/api/interfaces/NavigationContextType.md +1 -1
  131. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  132. package/docs/api/interfaces/NavigationItem.md +1 -1
  133. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  134. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  135. package/docs/api/interfaces/Organisation.md +1 -1
  136. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  137. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  138. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  139. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  140. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  141. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  142. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  143. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  144. package/docs/api/interfaces/PagePermissionGuardProps.md +2 -2
  145. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  146. package/docs/api/interfaces/PaletteData.md +1 -1
  147. package/docs/api/interfaces/ParsedAddress.md +2 -2
  148. package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
  149. package/docs/api/interfaces/ProgressProps.md +1 -1
  150. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  151. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  152. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  153. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  154. package/docs/api/interfaces/QuickFix.md +1 -1
  155. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  156. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  157. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  158. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  159. package/docs/api/interfaces/RBACConfig.md +2 -2
  160. package/docs/api/interfaces/RBACContext.md +1 -1
  161. package/docs/api/interfaces/RBACLogger.md +1 -1
  162. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  163. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  164. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  165. package/docs/api/interfaces/RBACPermissionCheckResult.md +2 -2
  166. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  167. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  168. package/docs/api/interfaces/RBACResult.md +1 -1
  169. package/docs/api/interfaces/RBACRoleGrantParams.md +2 -2
  170. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  171. package/docs/api/interfaces/RBACRoleRevokeParams.md +2 -2
  172. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  173. package/docs/api/interfaces/RBACRoleValidateParams.md +2 -2
  174. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  175. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  176. package/docs/api/interfaces/RBACRolesListResult.md +2 -2
  177. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  178. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  179. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  180. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  181. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  182. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  183. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  184. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  185. package/docs/api/interfaces/RouteConfig.md +2 -2
  186. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  187. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  188. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  189. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  190. package/docs/api/interfaces/SetupIssue.md +1 -1
  191. package/docs/api/interfaces/StorageConfig.md +1 -1
  192. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  193. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  194. package/docs/api/interfaces/StorageListOptions.md +1 -1
  195. package/docs/api/interfaces/StorageListResult.md +1 -1
  196. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  197. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  198. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  199. package/docs/api/interfaces/StyleImport.md +1 -1
  200. package/docs/api/interfaces/SwitchProps.md +1 -1
  201. package/docs/api/interfaces/TabsContentProps.md +1 -1
  202. package/docs/api/interfaces/TabsListProps.md +1 -1
  203. package/docs/api/interfaces/TabsProps.md +1 -1
  204. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  205. package/docs/api/interfaces/TextareaProps.md +1 -1
  206. package/docs/api/interfaces/ToastActionElement.md +1 -1
  207. package/docs/api/interfaces/ToastProps.md +1 -1
  208. package/docs/api/interfaces/UnifiedAuthContextType.md +60 -38
  209. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  210. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  211. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  212. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  213. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  214. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  215. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  216. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  217. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  218. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  219. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  220. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  221. package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
  222. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  223. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  224. package/docs/api/interfaces/UserEventAccess.md +1 -1
  225. package/docs/api/interfaces/UserMenuProps.md +1 -1
  226. package/docs/api/interfaces/UserProfile.md +1 -1
  227. package/docs/api/modules.md +202 -217
  228. package/docs/migration/README.md +18 -0
  229. package/docs/migration/database-changes-december-2025.md +768 -0
  230. package/docs/migration/person-scoped-profiles-migration-guide.md +472 -0
  231. package/docs/rbac/event-based-apps.md +124 -6
  232. package/package.json +1 -1
  233. package/scripts/check-pace-core-compliance.cjs +292 -57
  234. package/src/__tests__/public-recipe-view.test.ts +10 -10
  235. package/src/__tests__/rls-policies.test.ts +16 -14
  236. package/src/components/AddressField/README.md +6 -6
  237. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +172 -45
  238. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +121 -28
  239. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +9 -8
  240. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +20 -52
  241. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +170 -34
  242. package/src/components/DataTable/__tests__/keyboard.test.tsx +75 -12
  243. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +75 -11
  244. package/src/components/DataTable/components/UnifiedTableBody.tsx +85 -14
  245. package/src/components/DataTable/hooks/useDataTablePermissions.ts +75 -10
  246. package/src/components/FileDisplay/FileDisplay.test.tsx +2 -1
  247. package/src/components/FileDisplay/FileDisplay.tsx +16 -4
  248. package/src/components/NavigationMenu/NavigationMenu.test.tsx +6 -4
  249. package/src/components/NavigationMenu/NavigationMenu.tsx +1 -10
  250. package/src/components/OrganisationSelector/OrganisationSelector.tsx +35 -16
  251. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +25 -2
  252. package/src/components/PaceAppLayout/PaceAppLayout.tsx +97 -68
  253. package/src/components/PaceLoginPage/PaceLoginPage.tsx +0 -7
  254. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +5 -9
  255. package/src/components/ProtectedRoute/ProtectedRoute.tsx +0 -1
  256. package/src/components/PublicLayout/PublicPageProvider.tsx +0 -1
  257. package/src/components/Select/Select.test.tsx +4 -1
  258. package/src/components/Select/Select.tsx +60 -15
  259. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +192 -0
  260. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +741 -0
  261. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +703 -0
  262. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +581 -0
  263. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +23 -15
  264. package/src/hooks/public/usePublicEvent.ts +8 -8
  265. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  266. package/src/hooks/services/useAuthService.ts +21 -3
  267. package/src/hooks/services/useEventService.ts +21 -3
  268. package/src/hooks/services/useInactivityService.ts +21 -3
  269. package/src/hooks/services/useOrganisationService.ts +21 -3
  270. package/src/hooks/useFileDisplay.ts +18 -26
  271. package/src/hooks/useQueryCache.ts +6 -6
  272. package/src/hooks/useSecureDataAccess.test.ts +24 -17
  273. package/src/hooks/useSecureDataAccess.ts +18 -13
  274. package/src/providers/__tests__/OrganisationProvider.test.tsx +27 -21
  275. package/src/providers/services/EventServiceProvider.tsx +0 -8
  276. package/src/providers/services/UnifiedAuthProvider.tsx +174 -24
  277. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +10 -16
  278. package/src/rbac/__tests__/isSuperAdmin.real.test.ts +82 -0
  279. package/src/rbac/adapters.tsx +3 -22
  280. package/src/rbac/api.test.ts +2 -2
  281. package/src/rbac/api.ts +7 -1
  282. package/src/rbac/components/EnhancedNavigationMenu.tsx +2 -15
  283. package/src/rbac/components/NavigationGuard.tsx +1 -10
  284. package/src/rbac/components/NavigationProvider.tsx +0 -1
  285. package/src/rbac/components/PermissionEnforcer.tsx +45 -12
  286. package/src/rbac/components/SecureDataProvider.tsx +0 -1
  287. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +7 -43
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +4 -11
  289. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +3 -3
  290. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +1 -1
  291. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +1 -1
  292. package/src/rbac/engine.ts +14 -2
  293. package/src/rbac/hooks/index.ts +0 -3
  294. package/src/rbac/hooks/usePermissions.ts +51 -11
  295. package/src/rbac/hooks/useRBAC.simple.test.ts +95 -0
  296. package/src/rbac/hooks/useRBAC.ts +3 -13
  297. package/src/rbac/hooks/useResolvedScope.test.ts +75 -54
  298. package/src/rbac/hooks/useResolvedScope.ts +58 -33
  299. package/src/rbac/hooks/useSecureSupabase.ts +4 -9
  300. package/src/rbac/secureClient.ts +31 -0
  301. package/src/rbac/utils/__tests__/eventContext.test.ts +2 -2
  302. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +490 -0
  303. package/src/rbac/utils/eventContext.ts +5 -2
  304. package/src/services/AuthService.ts +37 -8
  305. package/src/services/EventService.ts +4 -57
  306. package/src/services/InactivityService.ts +127 -34
  307. package/src/services/OrganisationService.ts +160 -149
  308. package/src/services/__tests__/OrganisationService.pagination.test.ts +34 -8
  309. package/src/services/__tests__/OrganisationService.test.ts +218 -86
  310. package/src/types/database.generated.ts +166 -201
  311. package/src/types/supabase.ts +2 -2
  312. package/src/utils/__tests__/secureDataAccess.unit.test.ts +3 -2
  313. package/src/utils/file-reference/index.ts +4 -4
  314. package/src/utils/google-places/googlePlacesUtils.ts +1 -1
  315. package/src/utils/google-places/types.ts +1 -1
  316. package/src/utils/request-deduplication.ts +4 -4
  317. package/src/utils/security/secureDataAccess.test.ts +1 -1
  318. package/src/utils/security/secureDataAccess.ts +7 -4
  319. package/src/utils/storage/README.md +1 -1
  320. package/dist/chunk-4QYC5L4K.js.map +0 -1
  321. package/dist/chunk-73HSNNOQ.js.map +0 -1
  322. package/dist/chunk-HQVPB5MZ.js.map +0 -1
  323. package/dist/chunk-J2XXC7R5.js.map +0 -1
  324. package/dist/chunk-NIU6J6OX.js.map +0 -1
  325. package/dist/chunk-RUYZKXOD.js.map +0 -1
  326. package/dist/chunk-STYK4OH2.js.map +0 -1
  327. package/dist/chunk-VVBAW5A5.js.map +0 -1
  328. package/dist/chunk-Y4BUBBHD.js.map +0 -1
  329. package/scripts/check-pace-core-compliance.js +0 -512
  330. package/src/rbac/hooks/useSuperAdminBypass.ts +0 -126
  331. package/src/utils/context/superAdminOverride.ts +0 -58
  332. /package/dist/{DataTable-ON3IXISJ.js.map → DataTable-5FU7IESH.js.map} +0 -0
  333. /package/dist/{UnifiedAuthProvider-X5NXANVI.js.map → UnifiedAuthProvider-RGJTDE2C.js.map} +0 -0
  334. /package/dist/{api-I6UCQ5S6.js.map → api-N774RPUA.js.map} +0 -0
@@ -0,0 +1,472 @@
1
+ # Person-Scoped Profiles Migration Guide
2
+
3
+ **Version:** 0.5.190+
4
+ **Migration Date:** 2025-12-05
5
+ **Breaking Changes:** Yes
6
+
7
+ ## Overview
8
+
9
+ Profiles (membership, medical, and contact) have been migrated from **organisation-scoped** to **person-scoped**. Each person now has:
10
+
11
+ - **One membership profile** (`pace_member`) - regardless of organisation
12
+ - **One medical profile** (`medi_profile`) - regardless of organisation
13
+ - **Multiple contact profiles** (`pace_contact`) - person-scoped, multiple per type allowed
14
+
15
+ This change means profiles are no longer tied to specific organisations and are shared across all organisations a person belongs to.
16
+
17
+ ## What Changed
18
+
19
+ ### Tables Modified
20
+
21
+ #### 1. `pace_member`
22
+ - **Removed:** `organisation_id` column
23
+ - **Added:** Unique constraint on `person_id` (one membership per person)
24
+ - **Impact:** A person can now only have ONE membership record, regardless of how many organisations they belong to
25
+
26
+ #### 2. `medi_profile`
27
+ - **Removed:** `organisation_id` column
28
+ - **Impact:** One medical profile per person (via member relationship)
29
+
30
+ #### 3. `pace_contact`
31
+ - **Removed:** `organisation_id` and `member_id` columns
32
+ - **Added:** `person_id` column (NOT NULL, FK to `pace_person`)
33
+ - **Impact:** Contacts are now directly linked to persons, not members
34
+
35
+ #### 4. Related Tables (organisation_id removed)
36
+ - `medi_condition`
37
+ - `medi_diet`
38
+ - `medi_action_plan`
39
+ - `medi_profile_versions`
40
+ - `pace_consent`
41
+ - `pace_identification`
42
+ - `pace_qualification`
43
+
44
+ ### RLS Policy Changes
45
+
46
+ All RLS policies for these tables have been updated to:
47
+ - Remove organisation-based access checks
48
+ - Use person-scoped access control instead
49
+ - Allow access based on person ownership, not organisation membership
50
+
51
+ ## Breaking Changes
52
+
53
+ ### 1. Queries Filtering by `organisation_id`
54
+
55
+ **Before:**
56
+ ```typescript
57
+ // ❌ This will fail - organisation_id column no longer exists
58
+ const { data } = await supabase
59
+ .from('pace_member')
60
+ .select('*')
61
+ .eq('organisation_id', orgId);
62
+ ```
63
+
64
+ **After:**
65
+ ```typescript
66
+ // ✅ Filter by person_id instead
67
+ const { data } = await supabase
68
+ .from('pace_member')
69
+ .select('*')
70
+ .eq('person_id', personId);
71
+ ```
72
+
73
+ ### 2. Joins Using `organisation_id`
74
+
75
+ **Before:**
76
+ ```typescript
77
+ // ❌ This will fail
78
+ const { data } = await supabase
79
+ .from('pace_member')
80
+ .select('*, organisations(*)')
81
+ .eq('organisation_id', orgId);
82
+ ```
83
+
84
+ **After:**
85
+ ```typescript
86
+ // ✅ Join via person → user → organisation memberships
87
+ const { data } = await supabase
88
+ .from('pace_member')
89
+ .select('*, pace_person(*, user_profiles(*))')
90
+ .eq('person_id', personId);
91
+ ```
92
+
93
+ ### 3. Contact Queries Using `member_id`
94
+
95
+ **Before:**
96
+ ```typescript
97
+ // ❌ This will fail - member_id column no longer exists
98
+ const { data } = await supabase
99
+ .from('pace_contact')
100
+ .select('*')
101
+ .eq('member_id', memberId);
102
+ ```
103
+
104
+ **After:**
105
+ ```typescript
106
+ // ✅ Use person_id instead
107
+ const { data } = await supabase
108
+ .from('pace_contact')
109
+ .select('*')
110
+ .eq('person_id', personId);
111
+ ```
112
+
113
+ ### 4. Insert/Update Operations
114
+
115
+ **Before:**
116
+ ```typescript
117
+ // ❌ This will fail - organisation_id required
118
+ await supabase
119
+ .from('pace_member')
120
+ .insert({
121
+ person_id: personId,
122
+ organisation_id: orgId, // ❌ Column doesn't exist
123
+ membership_number: '12345'
124
+ });
125
+ ```
126
+
127
+ **After:**
128
+ ```typescript
129
+ // ✅ No organisation_id needed
130
+ await supabase
131
+ .from('pace_member')
132
+ .insert({
133
+ person_id: personId,
134
+ membership_number: '12345'
135
+ });
136
+ ```
137
+
138
+ ## Impact Assessment Checklist
139
+
140
+ Use this checklist to identify areas in your app that need updates:
141
+
142
+ ### Database Queries
143
+
144
+ - [ ] Search codebase for `pace_member` queries filtering by `organisation_id`
145
+ - [ ] Search codebase for `medi_profile` queries filtering by `organisation_id`
146
+ - [ ] Search codebase for `pace_contact` queries using `member_id`
147
+ - [ ] Search codebase for `pace_consent` queries filtering by `organisation_id`
148
+ - [ ] Search codebase for `pace_identification` queries filtering by `organisation_id`
149
+ - [ ] Search codebase for `pace_qualification` queries filtering by `organisation_id`
150
+ - [ ] Search codebase for `medi_condition`, `medi_diet`, `medi_action_plan` queries filtering by `organisation_id`
151
+
152
+ ### TypeScript Types
153
+
154
+ - [ ] Update TypeScript types (regenerate from database schema)
155
+ - [ ] Remove `organisation_id` from type definitions for profile tables
156
+ - [ ] Update `pace_contact` types to use `person_id` instead of `member_id`
157
+
158
+ ### UI Components
159
+
160
+ - [ ] Review profile display components - remove organisation context assumptions
161
+ - [ ] Update forms that create/edit profiles - remove organisation_id fields
162
+ - [ ] Update contact management - use person_id instead of member_id
163
+ - [ ] Review profile selection/filtering UI - remove organisation filters
164
+
165
+ ### Business Logic
166
+
167
+ - [ ] Review code that assumes multiple memberships per person
168
+ - [ ] Update logic that creates profiles per organisation
169
+ - [ ] Review permission checks that rely on organisation_id for profiles
170
+ - [ ] Update any code that merges/duplicates profiles across organisations
171
+
172
+ ### Data Access Patterns
173
+
174
+ - [ ] Review use of `useSecureDataAccess` hook with profile tables
175
+ - [ ] Update any custom data access utilities
176
+ - [ ] Review RPC functions that query profile tables
177
+
178
+ ## Code Migration Examples
179
+
180
+ ### Example 1: Fetching Member Profile
181
+
182
+ **Before:**
183
+ ```typescript
184
+ async function getMemberProfile(personId: string, orgId: string) {
185
+ const { data } = await supabase
186
+ .from('pace_member')
187
+ .select('*')
188
+ .eq('person_id', personId)
189
+ .eq('organisation_id', orgId) // ❌
190
+ .single();
191
+ return data;
192
+ }
193
+ ```
194
+
195
+ **After:**
196
+ ```typescript
197
+ async function getMemberProfile(personId: string) {
198
+ // ✅ No organisation_id needed - one profile per person
199
+ const { data } = await supabase
200
+ .from('pace_member')
201
+ .select('*')
202
+ .eq('person_id', personId)
203
+ .single();
204
+ return data;
205
+ }
206
+ ```
207
+
208
+ ### Example 2: Fetching Contacts
209
+
210
+ **Before:**
211
+ ```typescript
212
+ async function getContacts(memberId: string) {
213
+ const { data } = await supabase
214
+ .from('pace_contact')
215
+ .select('*')
216
+ .eq('member_id', memberId) // ❌
217
+ .eq('organisation_id', orgId); // ❌
218
+ return data;
219
+ }
220
+ ```
221
+
222
+ **After:**
223
+ ```typescript
224
+ async function getContacts(personId: string) {
225
+ // ✅ Use person_id directly
226
+ const { data } = await supabase
227
+ .from('pace_contact')
228
+ .select('*')
229
+ .eq('person_id', personId);
230
+ return data;
231
+ }
232
+ ```
233
+
234
+ ### Example 3: Creating Medical Profile
235
+
236
+ **Before:**
237
+ ```typescript
238
+ async function createMedicalProfile(memberId: string, orgId: string, data: MedicalData) {
239
+ const { data: profile } = await supabase
240
+ .from('medi_profile')
241
+ .insert({
242
+ member_id: memberId,
243
+ organisation_id: orgId, // ❌
244
+ ...data
245
+ })
246
+ .select()
247
+ .single();
248
+ return profile;
249
+ }
250
+ ```
251
+
252
+ **After:**
253
+ ```typescript
254
+ async function createMedicalProfile(memberId: string, data: MedicalData) {
255
+ // ✅ No organisation_id needed
256
+ const { data: profile } = await supabase
257
+ .from('medi_profile')
258
+ .insert({
259
+ member_id: memberId,
260
+ ...data
261
+ })
262
+ .select()
263
+ .single();
264
+ return profile;
265
+ }
266
+ ```
267
+
268
+ ### Example 4: Getting Person's Member in Organisation Context
269
+
270
+ **Before:**
271
+ ```typescript
272
+ // ❌ This pattern no longer works
273
+ const member = await getMemberForPersonInOrg(personId, orgId);
274
+ ```
275
+
276
+ **After:**
277
+ ```typescript
278
+ // ✅ Get the person's single membership
279
+ const { data: member } = await supabase
280
+ .from('pace_member')
281
+ .select('*')
282
+ .eq('person_id', personId)
283
+ .single();
284
+
285
+ // If you need to check organisation access, check via rbac_organisation_roles
286
+ const { data: orgRoles } = await supabase
287
+ .from('rbac_organisation_roles')
288
+ .select('organisation_id')
289
+ .eq('user_id', userId)
290
+ .eq('organisation_id', orgId)
291
+ .eq('status', 'active');
292
+ ```
293
+
294
+ ## Testing Recommendations
295
+
296
+ ### 1. Unit Tests
297
+
298
+ - [ ] Update test fixtures to remove `organisation_id` from profile records
299
+ - [ ] Update mock data generators
300
+ - [ ] Fix tests that assert organisation_id values
301
+
302
+ ### 2. Integration Tests
303
+
304
+ - [ ] Test profile creation without organisation_id
305
+ - [ ] Test profile queries by person_id
306
+ - [ ] Test contact management with person_id
307
+ - [ ] Verify RLS policies work correctly
308
+
309
+ ### 3. E2E Tests
310
+
311
+ - [ ] Test profile display across different organisations
312
+ - [ ] Verify profiles are shared correctly
313
+ - [ ] Test contact management flows
314
+ - [ ] Verify permission checks still work
315
+
316
+ ### 4. Data Validation
317
+
318
+ - [ ] Verify no duplicate memberships exist per person
319
+ - [ ] Verify medical profiles are correctly linked
320
+ - [ ] Verify contacts are correctly migrated to person_id
321
+
322
+ ## Common Patterns to Update
323
+
324
+ ### Pattern 1: Organisation-Scoped Profile Lists
325
+
326
+ **Before:**
327
+ ```typescript
328
+ // Get all members in an organisation
329
+ const { data } = await supabase
330
+ .from('pace_member')
331
+ .select('*')
332
+ .eq('organisation_id', orgId);
333
+ ```
334
+
335
+ **After:**
336
+ ```typescript
337
+ // Get all members in an organisation via person → user → org roles
338
+ const { data: orgMembers } = await supabase
339
+ .from('rbac_organisation_roles')
340
+ .select(`
341
+ organisation_id,
342
+ user_id,
343
+ pace_person!inner(
344
+ id,
345
+ pace_member(*)
346
+ )
347
+ `)
348
+ .eq('organisation_id', orgId)
349
+ .eq('status', 'active');
350
+ ```
351
+
352
+ ### Pattern 2: Profile Existence Checks
353
+
354
+ **Before:**
355
+ ```typescript
356
+ // Check if member exists in organisation
357
+ const { data } = await supabase
358
+ .from('pace_member')
359
+ .select('id')
360
+ .eq('person_id', personId)
361
+ .eq('organisation_id', orgId)
362
+ .single();
363
+ ```
364
+
365
+ **After:**
366
+ ```typescript
367
+ // Check if person has a membership (regardless of org)
368
+ const { data } = await supabase
369
+ .from('pace_member')
370
+ .select('id')
371
+ .eq('person_id', personId)
372
+ .single();
373
+ ```
374
+
375
+ ### Pattern 3: Profile Creation with Organisation Context
376
+
377
+ **Before:**
378
+ ```typescript
379
+ // Create profile for person in organisation
380
+ await supabase
381
+ .from('pace_member')
382
+ .insert({
383
+ person_id: personId,
384
+ organisation_id: orgId,
385
+ membership_number: generateNumber()
386
+ });
387
+ ```
388
+
389
+ **After:**
390
+ ```typescript
391
+ // Create profile for person (one per person, not per org)
392
+ // Check if already exists first
393
+ const { data: existing } = await supabase
394
+ .from('pace_member')
395
+ .select('id')
396
+ .eq('person_id', personId)
397
+ .single();
398
+
399
+ if (!existing) {
400
+ await supabase
401
+ .from('pace_member')
402
+ .insert({
403
+ person_id: personId,
404
+ membership_number: generateNumber()
405
+ });
406
+ }
407
+ ```
408
+
409
+ ## TypeScript Type Updates
410
+
411
+ After applying migrations, regenerate your database types:
412
+
413
+ ```bash
414
+ npx supabase gen types typescript --project-id <your-project-id> > src/types/database.generated.ts
415
+ ```
416
+
417
+ The updated types will reflect:
418
+ - Removed `organisation_id` from profile tables
419
+ - `pace_contact` using `person_id` instead of `member_id`
420
+ - Updated relationships
421
+
422
+ ## RLS Policy Behavior
423
+
424
+ RLS policies now work as follows:
425
+
426
+ 1. **Person Ownership**: Users can access profiles for persons they own (via `pace_person.user_id`)
427
+ 2. **Contact Permissions**: Users can access contacts where they are the contact person or own the person
428
+ 3. **No Organisation Filtering**: Profiles are accessible regardless of organisation context
429
+ 4. **Super Admin Override**: Super admins can access all profiles
430
+
431
+ ## Migration Support
432
+
433
+ If you encounter issues:
434
+
435
+ 1. **Check Migration Status**: Verify all migrations are applied
436
+ 2. **Verify Types**: Regenerate TypeScript types from current schema
437
+ 3. **Review RLS**: Ensure RLS policies are correctly applied
438
+ 4. **Check Logs**: Review Supabase logs for RLS policy violations
439
+
440
+ ## RPC Functions Updated
441
+
442
+ The following RPC functions have been updated to work with person-scoped profiles:
443
+
444
+ - **`data_pace_linked_profiles_list`** - Now uses `person_id` from `pace_contact` instead of `member_id`
445
+ - **`data_pace_contacts_list`** - Now uses `person_id` from `pace_contact` instead of `member_id`
446
+ - **`data_pace_contact_get`** - Now uses `person_id` from `pace_contact` instead of `member_id`
447
+
448
+ These functions now:
449
+ - Join `pace_contact` via `person_id` instead of `member_id`
450
+ - Get `member_id` from `pace_member` via `person_id` join
451
+ - Get `organisation_id` from user's organisation roles (since profiles are no longer organisation-scoped)
452
+
453
+ If you have custom RPC functions that reference `pace_contact.member_id` or profile table `organisation_id` columns, you'll need to update them similarly.
454
+
455
+ ## Questions?
456
+
457
+ For questions or issues related to this migration:
458
+ - Review the migration files in `supabase/migrations/`
459
+ - Check RLS policy definitions in the migration files
460
+ - Review the pace-core documentation for updated API patterns
461
+ - Check for custom RPC functions that may need updates
462
+
463
+ ## Summary
464
+
465
+ **Key Takeaways:**
466
+ - Profiles are now person-scoped, not organisation-scoped
467
+ - Remove all `organisation_id` filters/queries for profile tables
468
+ - Use `person_id` instead of `member_id` for contacts
469
+ - One membership per person (enforced by unique constraint)
470
+ - Update all TypeScript types after migration
471
+ - Test thoroughly, especially cross-organisation scenarios
472
+
@@ -29,7 +29,9 @@ A simple event management app that demonstrates:
29
29
  4. **ALWAYS set up providers correctly** in the exact order shown below
30
30
  5. **Use the exact app name** from your environment variable (must match database exactly, case-sensitive)
31
31
  6. **Ensure database setup is complete** before starting the app - App must be registered with `requires_event = true`
32
- 7. **User must have organisation role** - Users need roles assigned in `rbac_organisation_roles` table
32
+ 7. **User must have organisation role OR event access** - Users need either:
33
+ - Explicit roles in `rbac_organisation_roles` table, OR
34
+ - Event access via `rbac_event_app_roles` (organisation access is automatically inferred)
33
35
  8. **Event must be selected** - `selectedEventId` must be set in UnifiedAuth context before permission checks
34
36
  9. **Event must belong to organisation** - The event's `organisation_id` must match the user's organisation
35
37
 
@@ -200,6 +202,8 @@ RETURNING event_id, event_name, event_code, organisation_id;
200
202
 
201
203
  #### 5.5 Assign User Roles
202
204
 
205
+ **Option 1: Explicit Organisation Membership (Traditional)**
206
+
203
207
  ```sql
204
208
  -- Grant a user the org_admin role (replace with actual user and organisation IDs)
205
209
  INSERT INTO rbac_organisation_roles (user_id, organisation_id, role, status, granted_at)
@@ -216,6 +220,42 @@ ON CONFLICT (user_id, organisation_id) DO UPDATE SET
216
220
  updated_at = NOW();
217
221
  ```
218
222
 
223
+ **Option 2: Event-Based Access (Automatic Organisation Inference)**
224
+
225
+ For event-based apps, you can grant access via event roles. The system will automatically infer organisation access from event access:
226
+
227
+ ```sql
228
+ -- Grant a user event access (organisation access is automatically inferred)
229
+ -- Replace with actual user, event, app, and organisation IDs
230
+ INSERT INTO rbac_event_app_roles (
231
+ user_id,
232
+ event_id,
233
+ app_id,
234
+ organisation_id,
235
+ role,
236
+ status,
237
+ granted_at
238
+ )
239
+ VALUES (
240
+ 'your-user-id'::uuid,
241
+ 'your-event-id'::text,
242
+ (SELECT id FROM rbac_apps WHERE name = 'pace-trac'),
243
+ 'your-organisation-id'::uuid, -- Must match event's organisation_id
244
+ 'planner', -- or 'event_admin', 'participant', etc.
245
+ 'active',
246
+ NOW()
247
+ )
248
+ ON CONFLICT (user_id, event_id, app_id, role) DO UPDATE SET
249
+ status = EXCLUDED.status,
250
+ updated_at = NOW();
251
+ ```
252
+
253
+ **Important Notes:**
254
+ - When a user has event access via `rbac_event_app_roles`, they automatically get implicit organisation access
255
+ - The system grants an implicit 'member' role for permission checks
256
+ - Explicit organisation memberships take precedence over inferred access
257
+ - This eliminates the need to maintain duplicate organisation memberships for event-only users
258
+
219
259
  ### 6. Create Supabase Client
220
260
 
221
261
  Create `src/lib/supabase.ts`:
@@ -640,7 +680,9 @@ Your event-based RBAC setup is working correctly if:
640
680
  - [ ] App is registered in `rbac_apps` table with `requires_event = true` and `is_active = true`
641
681
  - [ ] Pages exist in `rbac_app_pages` for your app
642
682
  - [ ] Page permissions exist in `rbac_page_permissions` for your pages, roles, and organisation
643
- - [ ] User has an active role in `rbac_organisation_roles` for the organisation
683
+ - [ ] User has either:
684
+ - An active role in `rbac_organisation_roles` for the organisation, OR
685
+ - Event access via `rbac_event_app_roles` (organisation access is automatically inferred)
644
686
  - [ ] At least one event exists in the `event` table for your organisation
645
687
  - [ ] `VITE_APP_NAME` environment variable matches database `rbac_apps.name` exactly
646
688
  - [ ] `EventProvider` wraps your app content
@@ -762,15 +804,40 @@ WHERE event_id = 'your-event-id'::uuid;
762
804
  ```
763
805
  - Must have pages for `dashboard`, `participants`, etc.
764
806
 
765
- 5. **Verify user has organisation role**:
807
+ 5. **Verify user has organisation role OR event access**:
766
808
  ```sql
767
- SELECT ror.*, u.email
809
+ -- Check explicit organisation roles
810
+ SELECT ror.*, u.email, 'explicit' as access_type
768
811
  FROM rbac_organisation_roles ror
769
812
  JOIN auth.users u ON ror.user_id = u.id
770
813
  WHERE ror.user_id = 'your-user-id'::uuid
771
- AND ror.status = 'active';
814
+ AND ror.status = 'active'
815
+
816
+ UNION ALL
817
+
818
+ -- Check event-based access (which infers organisation access)
819
+ SELECT
820
+ rear.id,
821
+ rear.user_id,
822
+ e.organisation_id as organisation_id,
823
+ 'member' as role, -- Implicit role granted from event access
824
+ rear.status,
825
+ rear.granted_at,
826
+ rear.granted_by,
827
+ rear.revoked_at,
828
+ rear.revoked_by,
829
+ u.email,
830
+ 'inferred' as access_type
831
+ FROM rbac_event_app_roles rear
832
+ JOIN event e ON e.event_id = rear.event_id
833
+ JOIN auth.users u ON rear.user_id = u.id
834
+ WHERE rear.user_id = 'your-user-id'::uuid
835
+ AND rear.status = 'active'
836
+ AND e.organisation_id = 'your-organisation-id'::uuid;
772
837
  ```
773
- - User must have at least one active role
838
+ - User must have either:
839
+ - At least one active explicit organisation role, OR
840
+ - Event access via `rbac_event_app_roles` (organisation access is automatically inferred)
774
841
  - Must be for the organisation that owns the event
775
842
 
776
843
  6. **Verify event belongs to user's organisation**:
@@ -847,8 +914,59 @@ WHERE event_id = 'your-event-id'::uuid;
847
914
  | **Context Required** | `organisationId` | `eventId` (org auto-resolved) |
848
915
  | **PagePermissionGuard** | Needs `organisationId` | Needs `eventId` (org auto-resolved) |
849
916
  | **Scope Resolution** | Direct from context | Organisation resolved from event |
917
+ | **User Access** | Requires explicit `rbac_organisation_roles` | Can use `rbac_event_app_roles` (org access inferred) |
850
918
  | **Use Case** | User management, org settings | Event registration, event management |
851
919
 
920
+ ## 🎯 Organisation Access Inference from Events
921
+
922
+ **New Feature:** The RBAC system can now automatically infer organisation access from event access, eliminating the need for explicit organisation memberships when users have event access.
923
+
924
+ ### How It Works
925
+
926
+ 1. **User has event access** via `rbac_event_app_roles` table
927
+ 2. **System derives organisation** from the event's `organisation_id`
928
+ 3. **System grants implicit 'member' role** for permission checks
929
+ 4. **Permission checks proceed** as if user had explicit organisation membership
930
+
931
+ ### Benefits
932
+
933
+ - **Eliminates data duplication** - No need to maintain both event and organisation memberships
934
+ - **Simplifies onboarding** - Grant event access, organisation access is automatic
935
+ - **Maintains security** - Still validates that user has valid event access
936
+ - **Backward compatible** - Explicit organisation memberships still work and take precedence
937
+
938
+ ### Example
939
+
940
+ ```sql
941
+ -- User has event access but no explicit organisation membership
942
+ INSERT INTO rbac_event_app_roles (
943
+ user_id,
944
+ event_id,
945
+ app_id,
946
+ organisation_id,
947
+ role,
948
+ status
949
+ )
950
+ VALUES (
951
+ 'user-123'::uuid,
952
+ 'event-456'::text,
953
+ (SELECT id FROM rbac_apps WHERE name = 'pace-trac'),
954
+ 'org-789'::uuid,
955
+ 'planner',
956
+ 'active'
957
+ );
958
+
959
+ -- System automatically allows organisation access for permission checks
960
+ -- User can now access pages that require organisation context
961
+ -- Implicit role: 'member' (for permission matching)
962
+ ```
963
+
964
+ ### When Explicit Membership is Still Required
965
+
966
+ - Users who need organisation-level access without event context
967
+ - Users who need specific organisation roles (org_admin, leader) that aren't granted via events
968
+ - Organisation management features that don't require event context
969
+
852
970
  ## 🚀 Next Steps
853
971
 
854
972
  - **[RBAC Overview](./README.md)** - Complete RBAC system documentation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmruthers/pace-core",
3
- "version": "0.5.190",
3
+ "version": "0.5.193",
4
4
  "description": "Clean, modern React component library with Tailwind v4 styling and native utilities",
5
5
  "private": false,
6
6
  "publishConfig": {