@jmruthers/pace-core 0.6.5 → 0.6.7

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 (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -0,0 +1,724 @@
1
+ ---
2
+ lastUpdated: 2025-01-04T00:00:00+00:00
3
+ version: 2.0.0
4
+ reviewedBy: rbac-architecture-review
5
+ ---
6
+
7
+ # RBAC Contract
8
+
9
+ > **📋 The Definitive RBAC Contract** | [← Back to RBAC Documentation](./README.md) | [Quick Start](./quick-start.md) | [Migration Guide](./MIGRATION_GUIDE.md)
10
+
11
+ This document defines the **mandatory contract** between `pace-core` and consuming applications for RBAC (Role-Based Access Control) integration. This contract is **enforced** by ESLint rules.
12
+
13
+ **⚠️ CRITICAL**: This contract is **non-negotiable**. Violations will result in build errors.
14
+
15
+ ## Table of Contents
16
+
17
+ 1. [The Contract](#the-contract)
18
+ 2. [Architecture Boundary](#architecture-boundary)
19
+ 3. [Compliance Checklist](#compliance-checklist)
20
+ 4. [Anti-Patterns](#anti-patterns)
21
+ 5. [Enforcement](#enforcement)
22
+ 6. [enforcePermissions Configuration](#enforcepermissions-configuration)
23
+
24
+ ## The Contract
25
+
26
+ ### What Consuming Apps MUST Do
27
+
28
+ #### 1. **MUST Use pace-core RBAC Components**
29
+
30
+ **MUST use `PagePermissionGuard` for all protected pages:**
31
+
32
+ ```tsx
33
+ // ✅ CORRECT
34
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
35
+
36
+ function DashboardPage() {
37
+ return (
38
+ <PagePermissionGuard pageName="dashboard" operation="read">
39
+ <DashboardContent />
40
+ </PagePermissionGuard>
41
+ );
42
+ }
43
+ ```
44
+
45
+ **MUST use pace-core hooks for permission checks:**
46
+
47
+ ```tsx
48
+ // ✅ CORRECT
49
+ import { useCan, useResourcePermissions } from '@jmruthers/pace-core/rbac';
50
+
51
+ function MyComponent() {
52
+ const canEdit = useCan('update:users');
53
+ const permissions = useResourcePermissions('users');
54
+ // ...
55
+ }
56
+ ```
57
+
58
+ **MUST use pace-core API functions for programmatic checks:**
59
+
60
+ ```tsx
61
+ // ✅ CORRECT
62
+ import { isPermitted } from '@jmruthers/pace-core/rbac';
63
+
64
+ const hasAccess = await isPermitted({
65
+ permission: 'read:dashboard',
66
+ pageName: 'dashboard'
67
+ });
68
+ ```
69
+
70
+ #### 2. **MUST Use Standard AccessDenied Component**
71
+
72
+ **MUST use `AccessDenied` from pace-core for all access denied scenarios:**
73
+
74
+ ```tsx
75
+ // ✅ CORRECT
76
+ import { AccessDenied } from '@jmruthers/pace-core/rbac';
77
+
78
+ <PagePermissionGuard
79
+ pageName="dashboard"
80
+ operation="read"
81
+ fallback={<AccessDenied />}
82
+ >
83
+ <DashboardContent />
84
+ </PagePermissionGuard>
85
+ ```
86
+
87
+ #### 3. **MUST Configure enforcePermissions Correctly**
88
+
89
+ **For event-based apps (where pages handle their own checks):**
90
+
91
+ ```tsx
92
+ // ✅ CORRECT - Event-based app pattern
93
+ <PaceAppLayout
94
+ appName="MyApp"
95
+ enforcePermissions={false} // Pages handle checks via PagePermissionGuard
96
+ // ...
97
+ >
98
+ ```
99
+
100
+ **For organisation-based apps (where layout handles checks):**
101
+
102
+ ```tsx
103
+ // ✅ CORRECT - Organisation-based app pattern
104
+ <PaceAppLayout
105
+ appName="MyApp"
106
+ enforcePermissions={true} // Layout handles checks
107
+ defaultPermission="read"
108
+ // ...
109
+ >
110
+ ```
111
+
112
+ #### 4. **MUST Use useSecureSupabase for RBAC Table Queries**
113
+
114
+ **If you must query RBAC tables (rare), MUST use `useSecureSupabase`:**
115
+
116
+ ```tsx
117
+ // ✅ CORRECT - Using secure client
118
+ import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
119
+
120
+ function MyComponent() {
121
+ const secureSupabase = useSecureSupabase(supabase);
122
+ const { data } = await secureSupabase
123
+ .from('rbac_user_profiles') // Allowed through secure client
124
+ .select('*');
125
+ }
126
+ ```
127
+
128
+ ### What Consuming Apps MUST NOT Do
129
+
130
+ #### 1. **MUST NOT Create Wrapper Components**
131
+
132
+ **MUST NOT create wrapper components around `PagePermissionGuard`:**
133
+
134
+ ```tsx
135
+ // ❌ FORBIDDEN - Wrapper component
136
+ function EventPageGuard({ pageName, children }) {
137
+ // Event validation logic...
138
+ return (
139
+ <PagePermissionGuard pageName={pageName}>
140
+ {children}
141
+ </PagePermissionGuard>
142
+ );
143
+ }
144
+ ```
145
+
146
+ **Instead, handle validation directly in page components:**
147
+
148
+ ```tsx
149
+ // ✅ CORRECT - Direct usage
150
+ function DashboardPage() {
151
+ const { selectedEvent } = useEvents();
152
+
153
+ if (!selectedEvent) {
154
+ return <EventSelectionPrompt />;
155
+ }
156
+
157
+ return (
158
+ <PagePermissionGuard pageName="dashboard" operation="read">
159
+ <DashboardContent />
160
+ </PagePermissionGuard>
161
+ );
162
+ }
163
+ ```
164
+
165
+ #### 2. **MUST NOT Query RBAC Tables Directly**
166
+
167
+ **MUST NOT query RBAC tables without using `useSecureSupabase`:**
168
+
169
+ ```tsx
170
+ // ❌ FORBIDDEN - Direct query
171
+ const { data } = await supabase
172
+ .from('rbac_user_profiles') // ERROR: Direct RBAC table query
173
+ .select('*');
174
+ ```
175
+
176
+ **MUST NOT query these tables directly:**
177
+ - `rbac_organisation_roles`
178
+ - `rbac_event_app_roles`
179
+ - `rbac_global_roles`
180
+ - `rbac_apps`
181
+ - `rbac_app_pages`
182
+ - `rbac_page_permissions`
183
+ - `rbac_user_profiles`
184
+
185
+ #### 3. **MUST NOT Call RBAC RPC Functions Directly**
186
+
187
+ **MUST NOT call `rbac_check_permission_simplified` directly:**
188
+
189
+ ```tsx
190
+ // ❌ FORBIDDEN - Direct RPC call
191
+ const { data } = await supabase.rpc('rbac_check_permission_simplified', {
192
+ p_user_id: userId,
193
+ p_permission: 'read:dashboard'
194
+ });
195
+ ```
196
+
197
+ **Instead, use pace-core API:**
198
+
199
+ ```tsx
200
+ // ✅ CORRECT - Using pace-core API
201
+ import { isPermitted } from '@jmruthers/pace-core/rbac';
202
+ const hasAccess = await isPermitted({
203
+ permission: 'read:dashboard',
204
+ pageName: 'dashboard'
205
+ });
206
+ ```
207
+
208
+ #### 4. **MUST NOT Create Custom Access Denied Components**
209
+
210
+ **MUST NOT create custom access denied components:**
211
+
212
+ ```tsx
213
+ // ❌ FORBIDDEN - Custom component
214
+ function CustomAccessDenied() {
215
+ return <div>Access Denied</div>;
216
+ }
217
+ ```
218
+
219
+ **MUST use standard component:**
220
+
221
+ ```tsx
222
+ // ✅ CORRECT - Standard component
223
+ import { AccessDenied } from '@jmruthers/pace-core/rbac';
224
+ <AccessDenied />
225
+ ```
226
+
227
+ #### 5. **MUST NOT Bypass PagePermissionGuard**
228
+
229
+ **MUST NOT render protected content without `PagePermissionGuard`:**
230
+
231
+ ```tsx
232
+ // ❌ FORBIDDEN - No guard
233
+ function DashboardPage() {
234
+ return <DashboardContent />; // ERROR: Unprotected page
235
+ }
236
+ ```
237
+
238
+ **MUST protect all pages:**
239
+
240
+ ```tsx
241
+ // ✅ CORRECT - Protected page
242
+ function DashboardPage() {
243
+ return (
244
+ <PagePermissionGuard pageName="dashboard" operation="read">
245
+ <DashboardContent />
246
+ </PagePermissionGuard>
247
+ );
248
+ }
249
+ ```
250
+
251
+ #### 6. **MUST NOT Implement Custom Permission Logic**
252
+
253
+ **MUST NOT create custom permission checking functions:**
254
+
255
+ ```tsx
256
+ // ❌ FORBIDDEN - Custom permission logic
257
+ function checkPermission(userId, permission) {
258
+ // Custom logic...
259
+ }
260
+ ```
261
+
262
+ **MUST use pace-core functions:**
263
+
264
+ ```tsx
265
+ // ✅ CORRECT - Using pace-core
266
+ import { isPermitted } from '@jmruthers/pace-core/rbac';
267
+ const hasAccess = await isPermitted({ permission: 'read:dashboard' });
268
+ ```
269
+
270
+ #### 7. **MUST NOT Use Hardcoded Role Checks**
271
+
272
+ **MUST NOT compare roles directly:**
273
+
274
+ ```tsx
275
+ // ❌ FORBIDDEN - Hardcoded role check
276
+ if (user.role === 'admin') {
277
+ // ...
278
+ }
279
+ ```
280
+
281
+ **MUST use pace-core hooks/APIs:**
282
+
283
+ ```tsx
284
+ // ✅ CORRECT - Using pace-core
285
+ import { useAccessLevel } from '@jmruthers/pace-core/rbac';
286
+ const { accessLevel } = useAccessLevel();
287
+ if (accessLevel === 'admin') {
288
+ // ...
289
+ }
290
+ ```
291
+
292
+ #### 8. **MUST NOT Use Resource Permission String Literals**
293
+
294
+ **MUST NOT use string literals in `useResourcePermissions`:**
295
+
296
+ ```tsx
297
+ // ❌ FORBIDDEN - String literal
298
+ const { canCreate } = useResourcePermissions('journal');
299
+ ```
300
+
301
+ **MUST use RESOURCE_NAMES constant:**
302
+
303
+ ```tsx
304
+ // ✅ CORRECT - Using constant
305
+ import { RESOURCE_NAMES } from '@/config/resource-names';
306
+ const { canCreate } = useResourcePermissions(RESOURCE_NAMES.JOURNAL);
307
+ ```
308
+
309
+ #### 9. **MUST NOT Create Permission Wrapper Functions**
310
+
311
+ **MUST NOT create wrapper functions around permission checks:**
312
+
313
+ ```tsx
314
+ // ❌ FORBIDDEN - Wrapper function
315
+ const canEdit = (postId: string) => {
316
+ const hasPermission = canUpdate('journal');
317
+ const post = posts.find(p => p.id === postId);
318
+ return hasPermission && !!post;
319
+ };
320
+ ```
321
+
322
+ **MUST use pace-core hooks directly:**
323
+
324
+ ```tsx
325
+ // ✅ CORRECT - Direct usage
326
+ const { canUpdate } = useResourcePermissions(RESOURCE_NAMES.JOURNAL);
327
+ // Use canUpdate directly in components
328
+ ```
329
+
330
+ ### What Consuming Apps MAY Do
331
+
332
+ #### 1. **MAY Configure Navigation**
333
+
334
+ **MAY define navigation configuration:**
335
+
336
+ ```tsx
337
+ // ✅ ALLOWED - Navigation configuration
338
+ const navItems = [
339
+ { label: 'Dashboard', path: '/dashboard' },
340
+ { label: 'Users', path: '/users' }
341
+ ];
342
+
343
+ const routePermissions = {
344
+ '/dashboard': 'read:dashboard',
345
+ '/users': 'read:users'
346
+ };
347
+ ```
348
+
349
+ #### 2. **MAY Customize AccessDenied Props**
350
+
351
+ **MAY customize `AccessDenied` component with props:**
352
+
353
+ ```tsx
354
+ // ✅ ALLOWED - Customized AccessDenied
355
+ <AccessDenied
356
+ message="You don't have permission to view this page."
357
+ onGoBack={() => navigate('/dashboard')}
358
+ showSignOut={true}
359
+ />
360
+ ```
361
+
362
+ #### 3. **MAY Handle Event Context Validation**
363
+
364
+ **MAY validate event context in page components:**
365
+
366
+ ```tsx
367
+ // ✅ ALLOWED - Event context validation
368
+ function DashboardPage() {
369
+ const { selectedEvent } = useEvents();
370
+
371
+ if (!selectedEvent) {
372
+ return <EventSelectionPrompt />;
373
+ }
374
+
375
+ return (
376
+ <PagePermissionGuard pageName="dashboard" operation="read">
377
+ <DashboardContent />
378
+ </PagePermissionGuard>
379
+ );
380
+ }
381
+ ```
382
+
383
+ ## Architecture Boundary
384
+
385
+ ### What Lives in pace-core
386
+
387
+ **Core Permission Logic:**
388
+ - `RBACEngine.isPermitted` - Permission checking algorithm
389
+ - Database RPC calls (`rbac_check_permission_simplified`)
390
+ - Super admin detection
391
+ - Scope resolution logic
392
+ - Cache management
393
+
394
+ **Components:**
395
+ - `PagePermissionGuard` - Standard page protection (single canonical component)
396
+ - `NavigationGuard` - Navigation item protection
397
+ - `AccessDenied` - Standard access denied component
398
+
399
+ **Hooks:**
400
+ - `useCan` - Single permission check
401
+ - `usePermissions` - Permission map retrieval
402
+ - `useMultiplePermissions` - Multiple permission checks (covers any/all logic)
403
+ - `useAccessLevel` - Access level checks
404
+ - `useResourcePermissions` - Resource CRUD permissions
405
+ - `useResolvedScope` - Scope resolution
406
+ - `useSecureSupabase` - Secure Supabase client access
407
+
408
+ **API Functions:**
409
+ - `isPermitted` - Core permission check
410
+ - `getRoleContext` - Role information
411
+ - `setupRBAC` - Initialization
412
+
413
+ **Types and Utilities:**
414
+ - All RBAC types (`Permission`, `Scope`, `RBACRoleContext`)
415
+ - Security validators
416
+ - Cache utilities
417
+
418
+ ### What Lives in Consuming Apps
419
+
420
+ **Configuration:**
421
+ - Navigation configuration (`navItems`, `routePermissions`, `pageIdMapping`)
422
+ - App-specific page names and constants
423
+
424
+ **UI Integration:**
425
+ - Permission-aware UI rendering (using pace-core hooks)
426
+ - Custom styling of standard `AccessDenied` component (via props)
427
+ - Event context validation (if needed)
428
+
429
+ ## Compliance Checklist
430
+
431
+ Before deploying your application, verify:
432
+
433
+ - [ ] All pages are wrapped with `PagePermissionGuard`
434
+ - [ ] No direct queries to RBAC tables (except through `useSecureSupabase`)
435
+ - [ ] No direct RPC calls to `rbac_check_permission_simplified`
436
+ - [ ] No wrapper components around `PagePermissionGuard`
437
+ - [ ] No custom access denied components
438
+ - [ ] No hardcoded role checks (use `useAccessLevel` or `getRoleContext`)
439
+ - [ ] No custom permission utility functions
440
+ - [ ] No resource permission string literals (use `RESOURCE_NAMES` constants)
441
+ - [ ] No permission wrapper functions (use pace-core hooks directly)
442
+ - [ ] `enforcePermissions` configured correctly for your app type
443
+ - [ ] All access denied scenarios use `AccessDenied` from pace-core
444
+ - [ ] ESLint rules pass without errors
445
+
446
+ ## Anti-Patterns
447
+
448
+ ### Anti-Pattern 1: Wrapper Components
449
+
450
+ ```tsx
451
+ // ❌ ANTI-PATTERN
452
+ function EventPageGuard({ pageName, children }) {
453
+ const { selectedEvent } = useEvents();
454
+ if (!selectedEvent) return <EventSelectionPrompt />;
455
+ return <PagePermissionGuard pageName={pageName}>{children}</PagePermissionGuard>;
456
+ }
457
+ ```
458
+
459
+ **Why it's wrong:**
460
+ - Decreases maintainability
461
+ - Adds unnecessary abstraction
462
+ - Duplicates logic that should be in pages
463
+
464
+ **Correct pattern:**
465
+
466
+ ```tsx
467
+ // ✅ CORRECT
468
+ function DashboardPage() {
469
+ const { selectedEvent } = useEvents();
470
+ if (!selectedEvent) return <EventSelectionPrompt />;
471
+ return (
472
+ <PagePermissionGuard pageName="dashboard" operation="read">
473
+ <DashboardContent />
474
+ </PagePermissionGuard>
475
+ );
476
+ }
477
+ ```
478
+
479
+ ### Anti-Pattern 2: Direct Database Queries
480
+
481
+ ```tsx
482
+ // ❌ ANTI-PATTERN
483
+ const { data } = await supabase
484
+ .from('rbac_user_profiles')
485
+ .select('*');
486
+ ```
487
+
488
+ **Why it's wrong:**
489
+ - Bypasses security controls
490
+ - Violates architecture boundary
491
+ - Not future-proof
492
+
493
+ **Correct pattern:**
494
+
495
+ ```tsx
496
+ // ✅ CORRECT
497
+ import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
498
+ const secureSupabase = useSecureSupabase(supabase);
499
+ const { data } = await secureSupabase
500
+ .from('rbac_user_profiles')
501
+ .select('*');
502
+ ```
503
+
504
+ ### Anti-Pattern 3: Custom Access Denied
505
+
506
+ ```tsx
507
+ // ❌ ANTI-PATTERN
508
+ function CustomAccessDenied() {
509
+ return <div>Access Denied</div>;
510
+ }
511
+ ```
512
+
513
+ **Why it's wrong:**
514
+ - Inconsistent UX across apps
515
+ - Duplicates standard functionality
516
+ - Not maintainable
517
+
518
+ **Correct pattern:**
519
+
520
+ ```tsx
521
+ // ✅ CORRECT
522
+ import { AccessDenied } from '@jmruthers/pace-core/rbac';
523
+ <AccessDenied />
524
+ ```
525
+
526
+ ### Anti-Pattern 4: Hardcoded Role Checks
527
+
528
+ ```tsx
529
+ // ❌ ANTI-PATTERN
530
+ if (user.role === 'admin') {
531
+ // ...
532
+ }
533
+ ```
534
+
535
+ **Why it's wrong:**
536
+ - Bypasses RBAC system
537
+ - Not maintainable (role names can change)
538
+ - Doesn't respect permission hierarchy
539
+
540
+ **Correct pattern:**
541
+
542
+ ```tsx
543
+ // ✅ CORRECT
544
+ import { useAccessLevel } from '@jmruthers/pace-core/rbac';
545
+ const { accessLevel } = useAccessLevel();
546
+ if (accessLevel === 'admin') {
547
+ // ...
548
+ }
549
+ ```
550
+
551
+ ### Anti-Pattern 5: Custom Permission Utilities
552
+
553
+ ```tsx
554
+ // ❌ ANTI-PATTERN
555
+ function checkPermission(userId, permission) {
556
+ // Custom logic...
557
+ }
558
+ ```
559
+
560
+ **Why it's wrong:**
561
+ - Duplicates pace-core functionality
562
+ - Bypasses centralized RBAC logic
563
+ - Not future-proof
564
+
565
+ **Correct pattern:**
566
+
567
+ ```tsx
568
+ // ✅ CORRECT
569
+ import { isPermitted } from '@jmruthers/pace-core/rbac';
570
+ const hasAccess = await isPermitted({ permission: 'read:dashboard' });
571
+ ```
572
+
573
+ ### Anti-Pattern 6: Resource Permission String Literals
574
+
575
+ ```tsx
576
+ // ❌ ANTI-PATTERN
577
+ const { canCreate } = useResourcePermissions('journal');
578
+ ```
579
+
580
+ **Why it's wrong:**
581
+ - Not type-safe (typos possible)
582
+ - No compile-time validation
583
+ - Maintenance burden
584
+
585
+ **Correct pattern:**
586
+
587
+ ```tsx
588
+ // ✅ CORRECT
589
+ import { RESOURCE_NAMES } from '@/config/resource-names';
590
+ const { canCreate } = useResourcePermissions(RESOURCE_NAMES.JOURNAL);
591
+ ```
592
+
593
+ ### Anti-Pattern 7: Permission Wrapper Functions
594
+
595
+ ```tsx
596
+ // ❌ ANTI-PATTERN
597
+ const canEdit = (postId: string) => {
598
+ const hasPermission = canUpdate('journal');
599
+ const post = posts.find(p => p.id === postId);
600
+ return hasPermission && !!post;
601
+ };
602
+ ```
603
+
604
+ **Why it's wrong:**
605
+ - Unnecessary abstraction layer
606
+ - Encourages bypassing direct pace-core usage
607
+ - Creates maintenance burden
608
+
609
+ **Correct pattern:**
610
+
611
+ ```tsx
612
+ // ✅ CORRECT
613
+ const { canUpdate } = useResourcePermissions(RESOURCE_NAMES.JOURNAL);
614
+ // Use canUpdate directly in components
615
+ ```
616
+
617
+ ## Enforcement
618
+
619
+ ### ESLint Rules
620
+
621
+ The following ESLint rules enforce this contract (all as **ERROR** severity):
622
+
623
+ 1. **`no-direct-rbac-rpc`** - Detects direct calls to `rbac_check_permission_simplified`
624
+ 2. **`no-direct-rbac-tables`** - Detects direct queries to RBAC tables
625
+ 3. **`no-bypass-page-guard`** - Detects routes without `PagePermissionGuard`
626
+ 4. **`no-custom-access-denied`** - Detects custom access denied components
627
+ 5. **`no-hardcoded-role-checks`** - Detects hardcoded role comparisons
628
+ 6. **`no-custom-permission-utilities`** - Detects custom permission utility functions
629
+ 7. **`no-resource-permission-string-literals`** - Detects string literals in `useResourcePermissions` calls
630
+ 8. **`no-permission-wrapper-functions`** - Detects wrapper functions around pace-core permission hooks
631
+
632
+ ### Runtime Compliance
633
+
634
+ Use runtime compliance checking in development:
635
+
636
+ ```tsx
637
+ import { checkRuntimeCompliance } from '@jmruthers/pace-core/rbac/compliance';
638
+
639
+ // In development mode
640
+ if (import.meta.env.DEV) {
641
+ checkRuntimeCompliance();
642
+ }
643
+ ```
644
+
645
+ ## enforcePermissions Configuration
646
+
647
+ ### When to Use `enforcePermissions={true}`
648
+
649
+ **Use for organisation-based apps** where the layout handles permission checks:
650
+
651
+ ```tsx
652
+ <PaceAppLayout
653
+ appName="MyApp"
654
+ enforcePermissions={true} // Layout validates all routes
655
+ defaultPermission="read"
656
+ routePermissions={{
657
+ '/dashboard': 'read:dashboard',
658
+ '/users': 'read:users'
659
+ }}
660
+ >
661
+ ```
662
+
663
+ **Benefits:**
664
+ - Automatic route protection
665
+ - Safety net for forgotten permission checks
666
+ - Centralized permission configuration
667
+
668
+ ### When to Use `enforcePermissions={false}`
669
+
670
+ **Use for event-based apps** where pages handle their own checks:
671
+
672
+ ```tsx
673
+ <PaceAppLayout
674
+ appName="MyApp"
675
+ enforcePermissions={false} // Pages handle checks via PagePermissionGuard
676
+ showEvents={true}
677
+ >
678
+ {/* Pages use PagePermissionGuard directly */}
679
+ </PaceAppLayout>
680
+ ```
681
+
682
+ **Why `false` for event-based apps:**
683
+ - Pages need event context validation before permission checks
684
+ - `PagePermissionGuard` handles both event validation and permission checks
685
+ - Avoids redundant checks and timing issues
686
+
687
+ **Pattern:**
688
+
689
+ ```tsx
690
+ // Each page handles its own checks
691
+ function DashboardPage() {
692
+ const { selectedEvent } = useEvents();
693
+ if (!selectedEvent) return <EventSelectionPrompt />;
694
+
695
+ return (
696
+ <PagePermissionGuard pageName="dashboard" operation="read">
697
+ <DashboardContent />
698
+ </PagePermissionGuard>
699
+ );
700
+ }
701
+ ```
702
+
703
+ ## Related Documentation
704
+
705
+ - [RBAC README](./README.md) - Overview and quick start
706
+ - [Quick Start Guide](./quick-start.md) - Step-by-step setup
707
+ - [Event-Based Apps](./event-based-apps.md) - Event-based app patterns
708
+ - [Permission Enforcement](../implementation-guides/permission-enforcement.md) - Detailed enforcement patterns
709
+ - [Migration Guide](./MIGRATION_GUIDE.md) - Migrating to this contract
710
+
711
+ ## Support
712
+
713
+ If you have questions about this contract or need clarification:
714
+
715
+ 1. Review the [Troubleshooting Guide](./troubleshooting.md)
716
+ 2. Check [Examples](./examples.md) for common patterns
717
+ 3. Review [API Reference](./api-reference.md) for detailed API documentation
718
+
719
+ ---
720
+
721
+ **Last Updated**: 2025-01-04
722
+ **Version**: 2.0.0
723
+ **Status**: Enforced
724
+