@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -0,0 +1,819 @@
1
+ ---
2
+ lastUpdated: 2025-01-04T00:00:00+00:00
3
+ version: 2.0.0
4
+ reviewedBy: rbac-architecture-review
5
+ ---
6
+
7
+ # RBAC Migration Guide
8
+
9
+ > **🔄 Migrating to RBAC Contract v2.0.0** | [← Back to RBAC Documentation](./README.md) | [RBAC Contract](./RBAC_CONTRACT.md)
10
+
11
+ This guide helps you migrate your consuming application to comply with the RBAC Contract v2.0.0.
12
+
13
+ ## Breaking Changes
14
+
15
+ ### 1. RBAC Package Surface Area Reduction
16
+
17
+ **What Changed:**
18
+ - Removed redundant and overlapping RBAC exports to enforce a single correct pattern
19
+ - Reduced API surface area by ~40-50%
20
+ - All removed functionality has clear migration paths
21
+
22
+ **Impact:**
23
+ - Code using removed components/hooks/APIs will fail to build
24
+ - Must migrate to the minimal, canonical API
25
+
26
+ **Migration:**
27
+
28
+ #### Components Removed
29
+
30
+ **PermissionEnforcer → PagePermissionGuard**
31
+
32
+ ```tsx
33
+ // ❌ OLD
34
+ import { PermissionEnforcer } from '@jmruthers/pace-core/rbac';
35
+
36
+ <PermissionEnforcer permissions={['read:events']} operation="event-management">
37
+ <Content />
38
+ </PermissionEnforcer>
39
+
40
+ // ✅ NEW
41
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
42
+
43
+ <PagePermissionGuard pageName="events" operation="read">
44
+ <Content />
45
+ </PagePermissionGuard>
46
+ ```
47
+
48
+ **PermissionGuard (from adapters) → PagePermissionGuard**
49
+
50
+ ```tsx
51
+ // ❌ OLD
52
+ import { PermissionGuard } from '@jmruthers/pace-core/rbac';
53
+
54
+ <PermissionGuard permission="update:events" scope={{ organisationId: 'org-123' }}>
55
+ <Content />
56
+ </PermissionGuard>
57
+
58
+ // ✅ NEW
59
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
60
+
61
+ <PagePermissionGuard pageName="events" operation="update">
62
+ <Content />
63
+ </PagePermissionGuard>
64
+ ```
65
+
66
+ **AccessLevelGuard → useAccessLevel Hook**
67
+
68
+ ```tsx
69
+ // ❌ OLD
70
+ import { AccessLevelGuard } from '@jmruthers/pace-core/rbac';
71
+
72
+ <AccessLevelGuard minLevel="admin" scope={{ organisationId: 'org-123' }}>
73
+ <AdminPanel />
74
+ </AccessLevelGuard>
75
+
76
+ // ✅ NEW
77
+ import { useAccessLevel } from '@jmruthers/pace-core/rbac';
78
+
79
+ function AdminPanel() {
80
+ const { accessLevel } = useAccessLevel();
81
+
82
+ if (accessLevel !== 'admin' && accessLevel !== 'super') {
83
+ return <AccessDenied />;
84
+ }
85
+
86
+ return <AdminPanelContent />;
87
+ }
88
+ ```
89
+
90
+ **RoleBasedRouter → PagePermissionGuard + React Router**
91
+
92
+ ```tsx
93
+ // ❌ OLD
94
+ import { RoleBasedRouter } from '@jmruthers/pace-core/rbac';
95
+
96
+ <RoleBasedRouter routes={routeConfig}>
97
+ <App />
98
+ </RoleBasedRouter>
99
+
100
+ // ✅ NEW
101
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
102
+ import { Routes, Route } from 'react-router-dom';
103
+
104
+ <Routes>
105
+ <Route path="/dashboard" element={
106
+ <PagePermissionGuard pageName="dashboard" operation="read">
107
+ <Dashboard />
108
+ </PagePermissionGuard>
109
+ } />
110
+ </Routes>
111
+ ```
112
+
113
+ **EnhancedNavigationMenu → NavigationMenu + NavigationGuard**
114
+
115
+ ```tsx
116
+ // ❌ OLD
117
+ import { EnhancedNavigationMenu } from '@jmruthers/pace-core/rbac';
118
+
119
+ <EnhancedNavigationMenu items={items} />
120
+
121
+ // ✅ NEW
122
+ import { NavigationMenu, NavigationGuard } from '@jmruthers/pace-core';
123
+
124
+ <NavigationMenu>
125
+ {items.map(item => (
126
+ <NavigationGuard key={item.id} permission={item.permission}>
127
+ <NavigationItem {...item} />
128
+ </NavigationGuard>
129
+ ))}
130
+ </NavigationMenu>
131
+ ```
132
+
133
+ **Context Providers Removed**
134
+
135
+ All context providers have been removed. Use components/hooks directly:
136
+
137
+ ```tsx
138
+ // ❌ OLD
139
+ import { PagePermissionProvider, SecureDataProvider, NavigationProvider } from '@jmruthers/pace-core/rbac';
140
+
141
+ <PagePermissionProvider>
142
+ <SecureDataProvider>
143
+ <NavigationProvider>
144
+ <App />
145
+ </NavigationProvider>
146
+ </SecureDataProvider>
147
+ </PagePermissionProvider>
148
+
149
+ // ✅ NEW - No providers needed, use components/hooks directly
150
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
151
+ import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
152
+
153
+ // Use PagePermissionGuard in routes
154
+ // Use useSecureSupabase hook in components that need secure client
155
+ ```
156
+
157
+ #### Hooks Removed
158
+
159
+ **useHasAnyPermission → useMultiplePermissions**
160
+
161
+ ```tsx
162
+ // ❌ OLD
163
+ import { useHasAnyPermission } from '@jmruthers/pace-core/rbac';
164
+
165
+ const hasAny = useHasAnyPermission(['read:events', 'read:users']);
166
+
167
+ // ✅ NEW
168
+ import { useMultiplePermissions } from '@jmruthers/pace-core/rbac';
169
+
170
+ const { permissions } = useMultiplePermissions(['read:events', 'read:users']);
171
+ const hasAny = Object.values(permissions).some(Boolean);
172
+ ```
173
+
174
+ **useHasAllPermissions → useMultiplePermissions**
175
+
176
+ ```tsx
177
+ // ❌ OLD
178
+ import { useHasAllPermissions } from '@jmruthers/pace-core/rbac';
179
+
180
+ const hasAll = useHasAllPermissions(['read:events', 'update:events']);
181
+
182
+ // ✅ NEW
183
+ import { useMultiplePermissions } from '@jmruthers/pace-core/rbac';
184
+
185
+ const { permissions } = useMultiplePermissions(['read:events', 'update:events']);
186
+ const hasAll = Object.values(permissions).every(Boolean);
187
+ ```
188
+
189
+ **useCachedPermissions → Automatic Caching**
190
+
191
+ ```tsx
192
+ // ❌ OLD
193
+ import { useCachedPermissions } from '@jmruthers/pace-core/rbac';
194
+
195
+ const cached = useCachedPermissions(['read:events']);
196
+
197
+ // ✅ NEW - Caching is automatic in all hooks
198
+ import { useCan } from '@jmruthers/pace-core/rbac';
199
+
200
+ const can = useCan('read:events'); // Automatically cached
201
+ ```
202
+
203
+ #### API Functions Removed
204
+
205
+ **hasPermission → isPermitted**
206
+
207
+ ```tsx
208
+ // ❌ OLD
209
+ import { hasPermission } from '@jmruthers/pace-core/rbac';
210
+
211
+ const hasAccess = await hasPermission({
212
+ permission: 'read:events',
213
+ pageName: 'events'
214
+ });
215
+
216
+ // ✅ NEW
217
+ import { isPermitted } from '@jmruthers/pace-core/rbac';
218
+
219
+ const hasAccess = await isPermitted({
220
+ permission: 'read:events',
221
+ pageName: 'events'
222
+ });
223
+ ```
224
+
225
+ **Cache-only helpers → Automatic Caching**
226
+
227
+ ```tsx
228
+ // ❌ OLD
229
+ import { hasPermissionCached, hasAnyPermissionCached } from '@jmruthers/pace-core/rbac';
230
+
231
+ const cached = hasPermissionCached(userId, scope, 'read:events');
232
+ const anyCached = hasAnyPermissionCached(userId, scope, ['read:events', 'read:users']);
233
+
234
+ // ✅ NEW - Use hooks or API with automatic caching
235
+ import { useCan, useMultiplePermissions } from '@jmruthers/pace-core/rbac';
236
+ import { isPermittedCached } from '@jmruthers/pace-core/rbac';
237
+
238
+ // In components (automatic caching)
239
+ const can = useCan('read:events');
240
+
241
+ // In API/server code
242
+ const cached = await isPermittedCached({
243
+ permission: 'read:events',
244
+ pageName: 'events'
245
+ });
246
+ ```
247
+
248
+ #### Internal Exports
249
+
250
+ The following exports are now marked as `@internal` and should not be used by consuming apps:
251
+
252
+ - `RBACEngine`, `createRBACEngine` → Use `isPermitted` API instead
253
+ - `RBACCache`, `rbacCache`, `CACHE_PATTERNS` → Caching is automatic
254
+ - `SecureSupabaseClient`, `createSecureClient`, `fromSupabaseClient` → Use `useSecureSupabase` hook instead
255
+
256
+ **Migration Steps:**
257
+
258
+ 1. **Search for removed exports:**
259
+ ```bash
260
+ grep -r "PermissionEnforcer\|PermissionGuard\|AccessLevelGuard\|RoleBasedRouter\|EnhancedNavigationMenu\|PagePermissionProvider\|SecureDataProvider\|NavigationProvider\|useHasAnyPermission\|useHasAllPermissions\|useCachedPermissions\|hasPermission\|hasPermissionCached\|hasAnyPermissionCached" src/
261
+ ```
262
+
263
+ 2. **Replace with canonical alternatives** (see examples above)
264
+
265
+ 3. **Remove internal export usage:**
266
+ ```bash
267
+ grep -r "RBACEngine\|createRBACEngine\|RBACCache\|rbacCache\|CACHE_PATTERNS\|SecureSupabaseClient\|createSecureClient\|fromSupabaseClient" src/
268
+ ```
269
+ Replace with public APIs/hooks
270
+
271
+ 4. **Verify build:**
272
+ ```bash
273
+ npm run build
274
+ ```
275
+
276
+ ### 2. ESLint Rules Now ERROR (Not Warning)
277
+
278
+ **What Changed:**
279
+ - All RBAC compliance ESLint rules are now **ERROR** severity
280
+ - Builds will fail if violations are detected
281
+ - No more warnings - violations must be fixed
282
+
283
+ **Impact:**
284
+ - Existing code with violations will fail to build
285
+ - Must fix all violations before deployment
286
+
287
+ **Migration:**
288
+ 1. Run ESLint to identify violations:
289
+ ```bash
290
+ npm run lint
291
+ ```
292
+ 2. Fix all violations (see sections below)
293
+ 3. Verify build passes:
294
+ ```bash
295
+ npm run build
296
+ ```
297
+
298
+ ### 2. EventPageGuard Wrapper Pattern Removed
299
+
300
+ **What Changed:**
301
+ - `EventPageGuard` wrapper components are **forbidden**
302
+ - Must use `PagePermissionGuard` directly
303
+ - Event context validation should be in page components
304
+
305
+ **Before:**
306
+
307
+ ```tsx
308
+ // ❌ OLD PATTERN - Remove this
309
+ import { EventPageGuard } from '@/components/permissions';
310
+
311
+ function DashboardPage() {
312
+ return (
313
+ <EventPageGuard pageName={PAGE_NAMES.DASHBOARD}>
314
+ <DashboardContent />
315
+ </EventPageGuard>
316
+ );
317
+ }
318
+ ```
319
+
320
+ **After:**
321
+
322
+ ```tsx
323
+ // ✅ NEW PATTERN - Use this
324
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
325
+ import { useEvents } from '@jmruthers/pace-core';
326
+ import { EventSelectionPrompt } from '@/components/permissions/EventSelectionPrompt';
327
+
328
+ function DashboardPage() {
329
+ const { selectedEvent } = useEvents();
330
+
331
+ // Handle event context validation in page
332
+ if (!selectedEvent) {
333
+ return <EventSelectionPrompt />;
334
+ }
335
+
336
+ return (
337
+ <PagePermissionGuard pageName={PAGE_NAMES.DASHBOARD} operation="read">
338
+ <DashboardContent />
339
+ </PagePermissionGuard>
340
+ );
341
+ }
342
+ ```
343
+
344
+ **Migration Steps:**
345
+
346
+ 1. **Remove EventPageGuard component:**
347
+ ```bash
348
+ rm src/components/permissions/EventPageGuard.tsx
349
+ ```
350
+
351
+ 2. **Update all imports:**
352
+ ```tsx
353
+ // Remove
354
+ import { EventPageGuard } from '@/components/permissions';
355
+
356
+ // Add
357
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
358
+ ```
359
+
360
+ 3. **Replace all usages:**
361
+ - Replace `<EventPageGuard pageName="...">` with `<PagePermissionGuard pageName="..." operation="read">`
362
+ - Add event context validation in page components
363
+ - Add `operation` prop (usually `"read"`)
364
+
365
+ 4. **Update index exports:**
366
+ ```tsx
367
+ // src/components/permissions/index.ts
368
+ // Remove EventPageGuard export
369
+ // export { EventPageGuard } from './EventPageGuard';
370
+ ```
371
+
372
+ ### 3. Custom AccessDenied Components No Longer Allowed
373
+
374
+ **What Changed:**
375
+ - Custom access denied components are **forbidden**
376
+ - Must use `AccessDenied` from pace-core
377
+ - Ensures consistent UX across all apps
378
+
379
+ **Before:**
380
+
381
+ ```tsx
382
+ // ❌ OLD PATTERN - Remove this
383
+ function CustomAccessDenied() {
384
+ return (
385
+ <div>
386
+ <h2>Access Denied</h2>
387
+ <p>You don't have permission.</p>
388
+ </div>
389
+ );
390
+ }
391
+
392
+ <PagePermissionGuard
393
+ pageName="dashboard"
394
+ fallback={<CustomAccessDenied />}
395
+ >
396
+ <DashboardContent />
397
+ </PagePermissionGuard>
398
+ ```
399
+
400
+ **After:**
401
+
402
+ ```tsx
403
+ // ✅ NEW PATTERN - Use this
404
+ import { AccessDenied } from '@jmruthers/pace-core/rbac';
405
+
406
+ <PagePermissionGuard
407
+ pageName="dashboard"
408
+ operation="read"
409
+ fallback={<AccessDenied />}
410
+ >
411
+ <DashboardContent />
412
+ </PagePermissionGuard>
413
+ ```
414
+
415
+ **Migration Steps:**
416
+
417
+ 1. **Remove custom access denied components:**
418
+ ```bash
419
+ rm src/components/permissions/CustomAccessDenied.tsx
420
+ rm src/components/permissions/StandardAccessDenied.tsx
421
+ # etc.
422
+ ```
423
+
424
+ 2. **Update imports:**
425
+ ```tsx
426
+ // Remove
427
+ import { CustomAccessDenied } from '@/components/permissions';
428
+
429
+ // Add
430
+ import { AccessDenied } from '@jmruthers/pace-core/rbac';
431
+ ```
432
+
433
+ 3. **Replace all usages:**
434
+ ```tsx
435
+ // Replace
436
+ fallback={<CustomAccessDenied />}
437
+
438
+ // With
439
+ fallback={<AccessDenied />}
440
+ ```
441
+
442
+ 4. **Customize if needed (via props):**
443
+ ```tsx
444
+ <AccessDenied
445
+ message="Custom message"
446
+ onGoBack={() => navigate('/dashboard')}
447
+ showSignOut={true}
448
+ />
449
+ ```
450
+
451
+ ### 4. Direct RBAC Table Queries Now Errors
452
+
453
+ **What Changed:**
454
+ - Direct queries to RBAC tables are **forbidden**
455
+ - Must use `useSecureSupabase` hook
456
+ - ESLint will error on violations
457
+
458
+ **Before:**
459
+
460
+ ```tsx
461
+ // ❌ OLD PATTERN - Remove this
462
+ const { data } = await supabase
463
+ .from('rbac_user_profiles')
464
+ .select('user_id, display_name')
465
+ .in('user_id', userIds);
466
+ ```
467
+
468
+ **After:**
469
+
470
+ ```tsx
471
+ // ✅ NEW PATTERN - Use this
472
+ import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
473
+
474
+ function MyComponent() {
475
+ const secureSupabase = useSecureSupabase(supabase);
476
+
477
+ const { data } = await secureSupabase
478
+ .from('rbac_user_profiles')
479
+ .select('user_id, display_name')
480
+ .in('user_id', userIds);
481
+ }
482
+ ```
483
+
484
+ **Migration Steps:**
485
+
486
+ 1. **Find all direct RBAC table queries:**
487
+ ```bash
488
+ # Search for RBAC table queries
489
+ grep -r "\.from(['\"]rbac_" src/
490
+ ```
491
+
492
+ 2. **Update to use useSecureSupabase:**
493
+ - Import `useSecureSupabase` from `@jmruthers/pace-core/rbac`
494
+ - Call `useSecureSupabase(supabase)` in component
495
+ - Replace `supabase` with `secureSupabase` in queries
496
+
497
+ 3. **Verify queries work:**
498
+ - Test that queries still return expected data
499
+ - Verify security is maintained
500
+
501
+ ### 5. Direct RPC Calls Now Errors
502
+
503
+ **What Changed:**
504
+ - Direct calls to `rbac_check_permission_simplified` are **forbidden**
505
+ - Must use `isPermitted` from pace-core
506
+ - ESLint will error on violations
507
+
508
+ **Before:**
509
+
510
+ ```tsx
511
+ // ❌ OLD PATTERN - Remove this
512
+ const { data, error } = await supabase.rpc('rbac_check_permission_simplified', {
513
+ p_user_id: userId,
514
+ p_permission: 'read:dashboard',
515
+ p_organisation_id: orgId
516
+ });
517
+ ```
518
+
519
+ **After:**
520
+
521
+ ```tsx
522
+ // ✅ NEW PATTERN - Use this
523
+ import { isPermitted } from '@jmruthers/pace-core/rbac';
524
+
525
+ const hasAccess = await isPermitted({
526
+ permission: 'read:dashboard',
527
+ pageName: 'dashboard'
528
+ });
529
+ ```
530
+
531
+ **Migration Steps:**
532
+
533
+ 1. **Find all direct RPC calls:**
534
+ ```bash
535
+ # Search for RPC calls
536
+ grep -r "rbac_check_permission_simplified" src/
537
+ ```
538
+
539
+ 2. **Replace with isPermitted:**
540
+ - Import `isPermitted` from `@jmruthers/pace-core/rbac`
541
+ - Replace RPC call with `isPermitted` call
542
+ - Update permission format if needed
543
+
544
+ 3. **Verify permission checks work:**
545
+ - Test that permission checks return expected results
546
+ - Verify caching behavior is correct
547
+
548
+ ### 6. enforcePermissions Pattern Clarified
549
+
550
+ **What Changed:**
551
+ - `enforcePermissions` usage clarified for event-based apps
552
+ - Must be `false` for event-based apps
553
+ - Must be `true` for organisation-based apps
554
+
555
+ **Before (Event-Based Apps):**
556
+
557
+ ```tsx
558
+ // ❌ OLD PATTERN - May have been true
559
+ <PaceAppLayout
560
+ appName="MyApp"
561
+ enforcePermissions={true} // Wrong for event-based apps
562
+ showEvents={true}
563
+ >
564
+ ```
565
+
566
+ **After (Event-Based Apps):**
567
+
568
+ ```tsx
569
+ // ✅ NEW PATTERN - Must be false
570
+ <PaceAppLayout
571
+ appName="MyApp"
572
+ enforcePermissions={false} // Correct for event-based apps
573
+ showEvents={true}
574
+ >
575
+ ```
576
+
577
+ **Migration Steps:**
578
+
579
+ 1. **Identify app type:**
580
+ - Event-based: Uses events, pages handle checks
581
+ - Organisation-based: Uses organisations, layout handles checks
582
+
583
+ 2. **Update enforcePermissions:**
584
+ - Event-based apps: Set to `false`
585
+ - Organisation-based apps: Set to `true`
586
+
587
+ 3. **Verify behavior:**
588
+ - Test that pages are properly protected
589
+ - Verify no redundant permission checks
590
+
591
+ ## Step-by-Step Migration Checklist
592
+
593
+ ### Phase 1: Preparation
594
+
595
+ - [ ] Review [RBAC Contract](./RBAC_CONTRACT.md)
596
+ - [ ] Run ESLint: `npm run lint`
597
+ - [ ] Document current violations
598
+
599
+ ### Phase 2: Remove Wrapper Components
600
+
601
+ - [ ] Remove `EventPageGuard` component
602
+ - [ ] Update all imports
603
+ - [ ] Replace all `EventPageGuard` usages with `PagePermissionGuard`
604
+ - [ ] Add event context validation in pages
605
+ - [ ] Test all pages load correctly
606
+
607
+ ### Phase 3: Replace Custom Access Denied
608
+
609
+ - [ ] Remove custom access denied components
610
+ - [ ] Update imports to use `AccessDenied` from pace-core
611
+ - [ ] Replace all fallback props
612
+ - [ ] Customize via props if needed
613
+ - [ ] Test access denied scenarios
614
+
615
+ ### Phase 4: Fix Direct Queries
616
+
617
+ - [ ] Find all direct RBAC table queries
618
+ - [ ] Replace with `useSecureSupabase`
619
+ - [ ] Find all direct RPC calls
620
+ - [ ] Replace with `isPermitted`
621
+ - [ ] Test all queries work correctly
622
+
623
+ ### Phase 5: Remove Hardcoded Role Checks
624
+
625
+ - [ ] Find all hardcoded role comparisons (`role === 'admin'`, etc.)
626
+ - [ ] Replace with `useAccessLevel` hook or `getRoleContext` API
627
+ - [ ] Test role-based logic still works correctly
628
+
629
+ **Example Migration:**
630
+
631
+ ```tsx
632
+ // ❌ OLD
633
+ if (user.role === 'admin') {
634
+ // ...
635
+ }
636
+
637
+ // ✅ NEW
638
+ import { useAccessLevel } from '@jmruthers/pace-core/rbac';
639
+ const { accessLevel } = useAccessLevel();
640
+ if (accessLevel === 'admin') {
641
+ // ...
642
+ }
643
+ ```
644
+
645
+ ### Phase 6: Remove Custom Permission Utilities
646
+
647
+ - [ ] Find all custom permission utility functions (`checkPermission`, `hasPermission`, etc.)
648
+ - [ ] Replace with `isPermitted` API or `useCan` hook
649
+ - [ ] Test permission checks still work correctly
650
+
651
+ **Example Migration:**
652
+
653
+ ```tsx
654
+ // ❌ OLD
655
+ function checkPermission(userId, permission) {
656
+ // Custom logic...
657
+ }
658
+
659
+ // ✅ NEW
660
+ import { isPermitted } from '@jmruthers/pace-core/rbac';
661
+ const hasAccess = await isPermitted({ permission: 'read:dashboard' });
662
+ ```
663
+
664
+ ### Phase 7: Enforce Type-Safe Resource Names
665
+
666
+ - [ ] Create `RESOURCE_NAMES` constant object in your config
667
+ - [ ] Replace all `useResourcePermissions('string-literal')` with `RESOURCE_NAMES.CONSTANT`
668
+ - [ ] Update all permission checks to use constants
669
+ - [ ] Test all resource permissions still work
670
+
671
+ **Example Migration:**
672
+
673
+ ```tsx
674
+ // ❌ OLD
675
+ const { canCreate } = useResourcePermissions('journal');
676
+
677
+ // ✅ NEW
678
+ // 1. Create config/resource-names.ts
679
+ export const RESOURCE_NAMES = {
680
+ JOURNAL: 'journal',
681
+ RISKS: 'risks',
682
+ CONTACTS: 'contacts',
683
+ } as const;
684
+
685
+ // 2. Use in components
686
+ import { RESOURCE_NAMES } from '@/config/resource-names';
687
+ const { canCreate } = useResourcePermissions(RESOURCE_NAMES.JOURNAL);
688
+ ```
689
+
690
+ ### Phase 8: Remove Permission Wrapper Functions
691
+
692
+ - [ ] Find all permission wrapper functions (e.g., `canEdit(postId)`, `canDeletePost(postId)`)
693
+ - [ ] Remove wrapper functions from hooks
694
+ - [ ] Update components to use `useResourcePermissions` directly
695
+ - [ ] Test permission checks still work correctly
696
+
697
+ **Example Migration:**
698
+
699
+ ```tsx
700
+ // ❌ OLD - In hook
701
+ const canEdit = useCallback((postId: string) => {
702
+ const hasPermission = canUpdate('journal');
703
+ const post = posts.find(p => p.id === postId);
704
+ return hasPermission && !!post;
705
+ }, [posts, canUpdate]);
706
+
707
+ // ❌ OLD - In component
708
+ <JournalEntry canEdit={canEdit(post.id)} />
709
+
710
+ // ✅ NEW - In component
711
+ import { RESOURCE_NAMES } from '@/config/resource-names';
712
+ const { canUpdate } = useResourcePermissions(RESOURCE_NAMES.JOURNAL);
713
+ <JournalEntry canEdit={canUpdate(RESOURCE_NAMES.JOURNAL)} />
714
+ ```
715
+
716
+ ### Phase 9: Update Configuration
717
+
718
+ - [ ] Update `enforcePermissions` for app type
719
+ - [ ] Verify `PagePermissionGuard` on all pages
720
+ - [ ] Test permission enforcement works
721
+
722
+ ### Phase 10: Verification
723
+
724
+ - [ ] Run ESLint: `npm run lint`
725
+ - [ ] Run build: `npm run build`
726
+ - [ ] Test all pages and permission checks
727
+ - [ ] Verify no console errors
728
+
729
+ ## Common Issues and Solutions
730
+
731
+ ### Issue: "EventPageGuard is not defined"
732
+
733
+ **Solution:**
734
+ - Remove `EventPageGuard` import
735
+ - Use `PagePermissionGuard` from `@jmruthers/pace-core/rbac` instead
736
+
737
+ ### Issue: "AccessDenied is not defined"
738
+
739
+ **Solution:**
740
+ - Import `AccessDenied` from `@jmruthers/pace-core/rbac`
741
+ - Remove custom access denied components
742
+
743
+ ### Issue: "Direct query to RBAC table detected"
744
+
745
+ **Solution:**
746
+ - Use `useSecureSupabase` hook
747
+ - Replace `supabase` with `secureSupabase` in queries
748
+
749
+ ### Issue: "Direct RPC call detected"
750
+
751
+ **Solution:**
752
+ - Use `isPermitted` from `@jmruthers/pace-core/rbac`
753
+ - Replace RPC call with `isPermitted` call
754
+
755
+ ### Issue: "Route found without PagePermissionGuard"
756
+
757
+ **Solution:**
758
+ - Wrap all route components with `PagePermissionGuard`
759
+ - Add `operation` prop (usually `"read"`)
760
+
761
+ ### Issue: "Hardcoded role check detected"
762
+
763
+ **Solution:**
764
+ - Replace `user.role === 'admin'` with `useAccessLevel` hook
765
+ - Use `getRoleContext` API for programmatic checks
766
+
767
+ ### Issue: "Custom permission utility function detected"
768
+
769
+ **Solution:**
770
+ - Remove custom permission functions
771
+ - Use `isPermitted` API or `useCan` hook from pace-core
772
+
773
+ ### Issue: "Resource permission string literal detected"
774
+
775
+ **Solution:**
776
+ - Create `RESOURCE_NAMES` constant object
777
+ - Replace `useResourcePermissions('journal')` with `useResourcePermissions(RESOURCE_NAMES.JOURNAL)`
778
+
779
+ ### Issue: "Permission wrapper function detected"
780
+
781
+ **Solution:**
782
+ - Remove wrapper functions from hooks
783
+ - Use `useResourcePermissions` directly in components
784
+
785
+ ## Timeline
786
+
787
+ **Recommended migration order:**
788
+
789
+ 1. **Week 1**: Remove wrapper components (EventPageGuard)
790
+ 2. **Week 2**: Replace custom access denied components
791
+ 3. **Week 3**: Fix direct queries and RPC calls
792
+ 4. **Week 4**: Remove hardcoded role checks and custom permission utilities
793
+ 5. **Week 5**: Enforce type-safe resource names and remove wrapper functions
794
+ 6. **Week 6**: Update configuration and verify
795
+
796
+ **Total estimated time:** 4-6 weeks depending on codebase size
797
+
798
+ ## Getting Help
799
+
800
+ If you encounter issues during migration:
801
+
802
+ 1. Review [RBAC Contract](./RBAC_CONTRACT.md) for contract details
803
+ 2. Check [Troubleshooting Guide](./troubleshooting.md) for common issues
804
+ 3. Review [Examples](./examples.md) for migration patterns
805
+ 4. Check [API Reference](./api-reference.md) for API details
806
+
807
+ ## Related Documentation
808
+
809
+ - [RBAC Contract](./RBAC_CONTRACT.md) - The definitive contract
810
+ - [RBAC README](./README.md) - Overview and quick start
811
+ - [Quick Start Guide](./quick-start.md) - Step-by-step setup
812
+ - [Event-Based Apps](./event-based-apps.md) - Event-based app patterns
813
+ - [Permission Enforcement](../implementation-guides/permission-enforcement.md) - Detailed enforcement patterns
814
+
815
+ ---
816
+
817
+ **Last Updated**: 2025-01-04
818
+ **Version**: 2.0.0
819
+