@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
@@ -12,6 +12,8 @@ The PACE Core RBAC (Role-Based Access Control) system provides comprehensive per
12
12
 
13
13
  ## 🚨 Critical Rules (Follow These or It Won't Work)
14
14
 
15
+ > **📋 IMPORTANT**: See [RBAC Contract](./RBAC_CONTRACT.md) for the complete, enforceable contract. This section provides a quick overview.
16
+
15
17
  **MANDATORY Setup Steps (in order):**
16
18
 
17
19
  1. **Call `setupRBAC(supabase)` FIRST** - Must be called before any RBAC components or hooks
@@ -42,6 +44,8 @@ The PACE Core RBAC (Role-Based Access Control) system provides comprehensive per
42
44
  6. **App name must match exactly** - Environment variable must match `rbac_apps.name` (case-sensitive)
43
45
  7. **Never query RBAC tables directly** - Always use `PagePermissionGuard` or RBAC API functions
44
46
 
47
+ **⚠️ Contract Compliance**: All consuming apps must comply with the [RBAC Contract](./RBAC_CONTRACT.md). Violations will result in build errors.
48
+
45
49
  ## 🚀 Quick Start
46
50
 
47
51
  ```tsx
@@ -52,7 +56,7 @@ function MyComponent() {
52
56
  <PagePermissionGuard
53
57
  pageName="users"
54
58
  operation="read"
55
- fallback={<div>Access Denied</div>}
59
+ fallback={<p>Access Denied</p>}
56
60
  >
57
61
  <UserList />
58
62
  </PagePermissionGuard>
@@ -62,6 +66,8 @@ function MyComponent() {
62
66
 
63
67
  ## 📖 Core Concepts
64
68
 
69
+ - **[RBAC Contract](./RBAC_CONTRACT.md)** - ⚠️ **START HERE** - The definitive, enforceable contract (MUST read)
70
+ - **[Migration Guide](./MIGRATION_GUIDE.md)** - Migrating to RBAC Contract v2.0.0
65
71
  - **[Quick Start](./quick-start.md)** - Get up and running in 10 minutes (foolproof guide for organisation-based apps)
66
72
  - **[Event-Based Apps](./event-based-apps.md)** - Get up and running in 10 minutes (foolproof guide for event-based apps)
67
73
  - **[API Reference](./api-reference.md)** - Complete API documentation
@@ -138,11 +144,14 @@ graph TD
138
144
  - `useCan` - Check individual permissions
139
145
  - `usePermissions` - Get all permissions for a scope
140
146
  - `useAccessLevel` - Get user's access level
141
- - `useMultiplePermissions` - Check multiple permissions efficiently
147
+ - `useMultiplePermissions` - Check multiple permissions efficiently (covers any/all logic)
148
+ - `useResourcePermissions` - Resource CRUD permissions
149
+ - `useSecureSupabase` - Secure Supabase client access
142
150
 
143
151
  ### Components
144
- - `PermissionGuard` - Conditional rendering based on permissions
145
- - `AccessLevelGuard` - Conditional rendering based on access level
152
+ - `PagePermissionGuard` - Page-level permission protection (single canonical component)
153
+ - `NavigationGuard` - Navigation item protection
154
+ - `AccessDenied` - Standard access denied component
146
155
 
147
156
  ### Utilities
148
157
  - `isPermitted` - Server-side permission checking
@@ -223,9 +232,9 @@ function UsersPage() {
223
232
  <PagePermissionGuard
224
233
  pageName="users"
225
234
  operation="read"
226
- fallback={<div>You don't have permission to view this page</div>}
235
+ fallback={<p>You don't have permission to view this page</p>}
227
236
  >
228
- <div>
237
+ <section>
229
238
  <h1>User Management</h1>
230
239
 
231
240
  {/* Multiple operations on same page */}
@@ -252,7 +261,7 @@ function UsersPage() {
252
261
  >
253
262
  <DeleteUserButtons />
254
263
  </PagePermissionGuard>
255
- </div>
264
+ </section>
256
265
  </PagePermissionGuard>
257
266
  );
258
267
  }
@@ -273,7 +282,7 @@ function AdminPanel() {
273
282
  <PagePermissionGuard
274
283
  pageName="admin"
275
284
  operation="read"
276
- fallback={<div>Access denied</div>}
285
+ fallback={<p>Access denied</p>}
277
286
  >
278
287
  <UserManagement />
279
288
  </PagePermissionGuard>
@@ -379,7 +379,7 @@ export function withPermission(permission: string, fallback?: React.ComponentTyp
379
379
 
380
380
  // Usage
381
381
  const ProtectedUserList = withPermission('read:users', () => (
382
- <div>Access denied to user list</div>
382
+ <p>Access denied to user list</p>
383
383
  ))(UserList);
384
384
 
385
385
  // In component
@@ -436,16 +436,16 @@ export const useOrganisationPermissions = createPermissionHook('organisations');
436
436
  function UserManagement({ userId, scope }) {
437
437
  const { permissions, isLoading } = useUserPermissions(userId, scope);
438
438
 
439
- if (isLoading) return <div>Loading permissions...</div>;
439
+ if (isLoading) return <p>Loading permissions...</p>;
440
440
 
441
441
  return (
442
- <div>
442
+ <section>
443
443
  {permissions.read && <UserList />}
444
444
  {permissions.create && <CreateUserButton />}
445
445
  {permissions.update && <EditUserButton />}
446
446
  {permissions.delete && <DeleteUserButton />}
447
447
  {permissions.manage && <UserManagementPanel />}
448
- </div>
448
+ </section>
449
449
  );
450
450
  }
451
451
  ```
@@ -647,7 +647,7 @@ import { withPermission } from './permission-decorators';
647
647
 
648
648
  // Mock component
649
649
  const TestComponent = ({ data }: { data: string }) => (
650
- <div>Test Component: {data}</div>
650
+ <p>Test Component: {data}</p>
651
651
  );
652
652
 
653
653
  describe('Permission Decorators', () => {
@@ -684,7 +684,7 @@ describe('Permission Decorators', () => {
684
684
  })
685
685
  }));
686
686
 
687
- const FallbackComponent = () => <div>Access Denied</div>;
687
+ const FallbackComponent = () => <p>Access Denied</p>;
688
688
  const ProtectedComponent = withPermission('read:users', FallbackComponent)(TestComponent);
689
689
 
690
690
  render(
@@ -44,13 +44,13 @@ function UserActions() {
44
44
  undefined // No pageId for event-app permissions
45
45
  );
46
46
 
47
- if (error) return <div>Error: {error.message}</div>;
48
- if (isLoading) return <div>Checking permissions...</div>;
47
+ if (error) return <p>Error: {error.message}</p>;
48
+ if (isLoading) return <p>Checking permissions...</p>;
49
49
 
50
50
  return (
51
- <div>
51
+ <section>
52
52
  {can && <EventActions />}
53
- </div>
53
+ </section>
54
54
  );
55
55
  }
56
56
  ```
@@ -87,19 +87,19 @@ function PermissionDisplay() {
87
87
  }
88
88
  );
89
89
 
90
- if (isLoading) return <div>Loading permissions...</div>;
91
- if (error) return <div>Error: {error.message}</div>;
90
+ if (isLoading) return <p>Loading permissions...</p>;
91
+ if (error) return <p>Error: {error.message}</p>;
92
92
 
93
93
  return (
94
- <div>
94
+ <section>
95
95
  <h3>User Permissions</h3>
96
96
  {Object.entries(permissions).map(([pageId, operations]) => (
97
- <div key={pageId}>
97
+ <p key={pageId}>
98
98
  <strong>{pageId}:</strong> {operations.join(', ')}
99
- </div>
99
+ </p>
100
100
  ))}
101
101
  <button onClick={refetch}>Refresh</button>
102
- </div>
102
+ </section>
103
103
  );
104
104
  }
105
105
  ```
@@ -128,13 +128,13 @@ function AccessLevelDisplay({ userId, scope }) {
128
128
  scope
129
129
  });
130
130
 
131
- if (isLoading) return <div>Loading access level...</div>;
132
- if (error) return <div>Error: {error.message}</div>;
131
+ if (isLoading) return <p>Loading access level...</p>;
132
+ if (error) return <p>Error: {error.message}</p>;
133
133
 
134
134
  return (
135
- <div>
135
+ <section>
136
136
  <p>Access Level: {accessLevel || 'None'}</p>
137
- </div>
137
+ </section>
138
138
  );
139
139
  }
140
140
  ```
@@ -183,12 +183,12 @@ function UserManagement({ userId, scope }) {
183
183
  }, [checkMultiple, isLoading, userId, scope]);
184
184
 
185
185
  return (
186
- <div>
186
+ <section>
187
187
  {permissions['read:users'] && <UserList />}
188
188
  {permissions['create:users'] && <CreateUserButton />}
189
189
  {permissions['update:users'] && <EditUserButton />}
190
190
  {permissions['delete:users'] && <DeleteUserButton />}
191
- </div>
191
+ </section>
192
192
  );
193
193
  }
194
194
  ```
@@ -221,12 +221,12 @@ import { PermissionEnforcer } from '@jmruthers/pace-core/rbac';
221
221
 
222
222
  function UserActions() {
223
223
  return (
224
- <div>
224
+ <section>
225
225
  {/* Pattern 1: PermissionEnforcer - automatic scope resolution */}
226
226
  <PermissionEnforcer
227
227
  permissions={['read:users']}
228
228
  operation="user-management"
229
- fallback={<div>Access Denied</div>}
229
+ fallback={<p>Access Denied</p>}
230
230
  >
231
231
  <UserList />
232
232
  </PermissionEnforcer>
@@ -236,11 +236,11 @@ function UserActions() {
236
236
  permissions={['create:users', 'update:users']}
237
237
  operation="user-crud"
238
238
  requireAll={true} // User needs ALL permissions
239
- fallback={<div>You need create and update permissions</div>}
239
+ fallback={<p>You need create and update permissions</p>}
240
240
  >
241
241
  <UserManagementPanel />
242
242
  </PermissionEnforcer>
243
- </div>
243
+ </section>
244
244
  );
245
245
  }
246
246
  ```
@@ -0,0 +1,376 @@
1
+ ---
2
+ lastUpdated: 2025-01-28T00:00:00+11:00
3
+ version: 0.6.0
4
+ reviewedBy: rbac-compliance-audit
5
+ ---
6
+
7
+ # Edge Functions RBAC Guide
8
+
9
+ **📚 Related**: [RBAC Compliance Guide](../standards/09-rbac-compliance.md) | [RBAC API Reference](./api-reference.md)
10
+
11
+ This guide explains how to use pace-core RBAC APIs in Edge Functions (Deno serverless functions). **There are NO exceptions** - Edge Functions MUST use pace-core APIs, not custom RBAC helpers.
12
+
13
+ ## Why No Exceptions?
14
+
15
+ Edge Functions cannot use React hooks (they're Deno-based serverless functions), but pace-core provides programmatic APIs that work outside React:
16
+
17
+ - ✅ `isPermitted()` - Programmatic permission checking API
18
+ - ✅ `setupRBAC()` - Initialize RBAC engine with Supabase client
19
+ - ✅ `getAccessLevel()` - Get user access level
20
+ - ✅ `getRoleContext()` - Get user role context
21
+
22
+ **Custom RBAC helpers are FORBIDDEN** because they:
23
+ - Bypass security validation
24
+ - Skip audit logging
25
+ - Miss caching optimizations
26
+ - Duplicate functionality that pace-core already provides
27
+
28
+ ## Correct Pattern
29
+
30
+ ### Step 1: Create Supabase Client
31
+
32
+ ```typescript
33
+ import { createClient } from 'jsr:@supabase/supabase-js@2';
34
+
35
+ Deno.serve(async (req: Request) => {
36
+ // Extract auth token from request
37
+ const authHeader = req.headers.get('Authorization');
38
+ if (!authHeader) {
39
+ return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
40
+ }
41
+
42
+ // Create Supabase client with auth header
43
+ const supabase = createClient(
44
+ Deno.env.get('SUPABASE_URL') ?? '',
45
+ Deno.env.get('SUPABASE_ANON_KEY') ?? '',
46
+ {
47
+ global: {
48
+ headers: { Authorization: authHeader },
49
+ },
50
+ }
51
+ );
52
+ ```
53
+
54
+ ### Step 2: Get User from Session
55
+
56
+ ```typescript
57
+ // Get authenticated user
58
+ const { data: { user }, error: authError } = await supabase.auth.getUser();
59
+ if (authError || !user) {
60
+ return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
61
+ }
62
+ ```
63
+
64
+ ### Step 3: Setup RBAC
65
+
66
+ ```typescript
67
+ // Import pace-core RBAC functions
68
+ import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
69
+
70
+ // Setup RBAC (MUST be called before using isPermitted)
71
+ setupRBAC(supabase);
72
+ ```
73
+
74
+ ### Step 4: Extract Organisation Context
75
+
76
+ ```typescript
77
+ // Extract organisation context from request
78
+ // Option 1: From headers
79
+ const organisationId = req.headers.get('x-organisation-id');
80
+
81
+ // Option 2: From request body
82
+ if (!organisationId) {
83
+ const body = await req.json();
84
+ organisationId = body.organisationId;
85
+ }
86
+
87
+ // Option 3: From query parameters
88
+ if (!organisationId) {
89
+ const url = new URL(req.url);
90
+ organisationId = url.searchParams.get('organisationId');
91
+ }
92
+
93
+ if (!organisationId) {
94
+ return new Response(
95
+ JSON.stringify({ error: 'Organisation context required' }),
96
+ { status: 400 }
97
+ );
98
+ }
99
+ ```
100
+
101
+ ### Step 5: Check Permission
102
+
103
+ ```typescript
104
+ // Check permission using pace-core API
105
+ const hasPermission = await isPermitted({
106
+ userId: user.id,
107
+ scope: {
108
+ organisationId,
109
+ eventId: req.headers.get('x-event-id'), // Optional
110
+ appId: req.headers.get('x-app-id'), // Optional
111
+ },
112
+ permission: 'read:dashboard',
113
+ pageId: 'dashboard' // Optional, but recommended
114
+ });
115
+
116
+ if (!hasPermission) {
117
+ return new Response(
118
+ JSON.stringify({ error: 'Permission denied' }),
119
+ { status: 403 }
120
+ );
121
+ }
122
+
123
+ // Proceed with function logic
124
+ return new Response(JSON.stringify({ success: true }));
125
+ });
126
+ ```
127
+
128
+ ## Complete Example
129
+
130
+ ```typescript
131
+ // supabase/functions/protected-endpoint/index.ts
132
+ import { createClient } from 'jsr:@supabase/supabase-js@2';
133
+ import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
134
+
135
+ Deno.serve(async (req: Request) => {
136
+ try {
137
+ // 1. Extract auth token
138
+ const authHeader = req.headers.get('Authorization');
139
+ if (!authHeader) {
140
+ return new Response(
141
+ JSON.stringify({ error: 'Unauthorized' }),
142
+ { status: 401, headers: { 'Content-Type': 'application/json' } }
143
+ );
144
+ }
145
+
146
+ // 2. Create Supabase client
147
+ const supabase = createClient(
148
+ Deno.env.get('SUPABASE_URL') ?? '',
149
+ Deno.env.get('SUPABASE_ANON_KEY') ?? '',
150
+ {
151
+ global: {
152
+ headers: { Authorization: authHeader },
153
+ },
154
+ }
155
+ );
156
+
157
+ // 3. Get authenticated user
158
+ const { data: { user }, error: authError } = await supabase.auth.getUser();
159
+ if (authError || !user) {
160
+ return new Response(
161
+ JSON.stringify({ error: 'Unauthorized' }),
162
+ { status: 401, headers: { 'Content-Type': 'application/json' } }
163
+ );
164
+ }
165
+
166
+ // 4. Setup RBAC
167
+ setupRBAC(supabase);
168
+
169
+ // 5. Extract organisation context
170
+ const organisationId = req.headers.get('x-organisation-id') ||
171
+ (await req.json().catch(() => ({}))).organisationId;
172
+
173
+ if (!organisationId) {
174
+ return new Response(
175
+ JSON.stringify({ error: 'Organisation context required' }),
176
+ { status: 400, headers: { 'Content-Type': 'application/json' } }
177
+ );
178
+ }
179
+
180
+ // 6. Check permission
181
+ const hasPermission = await isPermitted({
182
+ userId: user.id,
183
+ scope: { organisationId },
184
+ permission: 'read:dashboard',
185
+ pageId: 'dashboard'
186
+ });
187
+
188
+ if (!hasPermission) {
189
+ return new Response(
190
+ JSON.stringify({ error: 'Permission denied' }),
191
+ { status: 403, headers: { 'Content-Type': 'application/json' } }
192
+ );
193
+ }
194
+
195
+ // 7. Execute function logic
196
+ const result = {
197
+ message: 'Access granted',
198
+ userId: user.id,
199
+ organisationId
200
+ };
201
+
202
+ return new Response(
203
+ JSON.stringify(result),
204
+ {
205
+ status: 200,
206
+ headers: { 'Content-Type': 'application/json' }
207
+ }
208
+ );
209
+ } catch (error) {
210
+ console.error('Edge Function error:', error);
211
+ return new Response(
212
+ JSON.stringify({ error: 'Internal server error' }),
213
+ { status: 500, headers: { 'Content-Type': 'application/json' } }
214
+ );
215
+ }
216
+ });
217
+ ```
218
+
219
+ ## Migration Guide: Removing Custom RBAC Helpers
220
+
221
+ If you have existing Edge Functions with custom RBAC helpers, follow these steps:
222
+
223
+ ### Step 1: Identify Custom Helpers
224
+
225
+ Search for custom RBAC helpers:
226
+ ```bash
227
+ # Find files with custom RBAC helpers
228
+ grep -r "rbac_check_permission_simplified" supabase/functions/
229
+ grep -r "function.*checkPermission" supabase/functions/
230
+ grep -r "pace-core-compliance-exception" supabase/functions/
231
+ ```
232
+
233
+ ### Step 2: Replace Custom Helper with pace-core API
234
+
235
+ **Before (❌ FORBIDDEN):**
236
+ ```typescript
237
+ // supabase/functions/_shared/rbac.ts
238
+ export async function checkPermission(
239
+ supabase: SupabaseClient,
240
+ userId: string,
241
+ permission: string,
242
+ organisationId: string
243
+ ): Promise<boolean> {
244
+ const { data, error } = await supabase.rpc('rbac_check_permission_simplified', {
245
+ p_user_id: userId,
246
+ p_permission: permission,
247
+ p_organisation_id: organisationId
248
+ });
249
+ return data === true;
250
+ }
251
+
252
+ // supabase/functions/my-function/index.ts
253
+ import { checkPermission } from '../_shared/rbac.ts';
254
+
255
+ const hasPermission = await checkPermission(supabase, user.id, 'read:dashboard', orgId);
256
+ ```
257
+
258
+ **After (✅ CORRECT):**
259
+ ```typescript
260
+ // supabase/functions/my-function/index.ts
261
+ import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
262
+
263
+ // Setup RBAC once
264
+ setupRBAC(supabase);
265
+
266
+ // Use pace-core API directly
267
+ const hasPermission = await isPermitted({
268
+ userId: user.id,
269
+ scope: { organisationId: orgId },
270
+ permission: 'read:dashboard',
271
+ pageId: 'dashboard'
272
+ });
273
+ ```
274
+
275
+ ### Step 3: Remove Custom Helper Files
276
+
277
+ After migrating all Edge Functions:
278
+ ```bash
279
+ # Remove custom RBAC helper file
280
+ rm supabase/functions/_shared/rbac.ts
281
+ ```
282
+
283
+ ### Step 4: Update All Edge Functions
284
+
285
+ Update each Edge Function to:
286
+ 1. Import `setupRBAC` and `isPermitted` from pace-core
287
+ 2. Call `setupRBAC(supabase)` before permission checks
288
+ 3. Use `isPermitted()` with complete `PermissionCheck` input
289
+ 4. Remove imports of custom RBAC helpers
290
+
291
+ ## Common Mistakes
292
+
293
+ ### ❌ Mistake 1: Calling RPC Directly
294
+
295
+ ```typescript
296
+ // ❌ FORBIDDEN
297
+ const { data } = await supabase.rpc('rbac_check_permission_simplified', {
298
+ p_user_id: userId,
299
+ p_permission: 'read:dashboard'
300
+ });
301
+ ```
302
+
303
+ **Fix:**
304
+ ```typescript
305
+ // ✅ CORRECT
306
+ setupRBAC(supabase);
307
+ const hasPermission = await isPermitted({
308
+ userId,
309
+ scope: { organisationId },
310
+ permission: 'read:dashboard'
311
+ });
312
+ ```
313
+
314
+ ### ❌ Mistake 2: Forgetting to Setup RBAC
315
+
316
+ ```typescript
317
+ // ❌ FORBIDDEN - Missing setupRBAC
318
+ import { isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
319
+
320
+ const hasPermission = await isPermitted({ ... }); // Will fail!
321
+ ```
322
+
323
+ **Fix:**
324
+ ```typescript
325
+ // ✅ CORRECT
326
+ import { setupRBAC, isPermitted } from 'npm:@jmruthers/pace-core@^0.6.0/rbac';
327
+
328
+ setupRBAC(supabase); // MUST be called first
329
+ const hasPermission = await isPermitted({ ... });
330
+ ```
331
+
332
+ ### ❌ Mistake 3: Missing Organisation Context
333
+
334
+ ```typescript
335
+ // ❌ FORBIDDEN - Missing organisationId
336
+ const hasPermission = await isPermitted({
337
+ userId: user.id,
338
+ scope: {}, // Missing organisationId
339
+ permission: 'read:dashboard'
340
+ });
341
+ ```
342
+
343
+ **Fix:**
344
+ ```typescript
345
+ // ✅ CORRECT
346
+ const organisationId = req.headers.get('x-organisation-id');
347
+ if (!organisationId) {
348
+ return new Response(JSON.stringify({ error: 'Organisation context required' }), { status: 400 });
349
+ }
350
+
351
+ const hasPermission = await isPermitted({
352
+ userId: user.id,
353
+ scope: { organisationId },
354
+ permission: 'read:dashboard'
355
+ });
356
+ ```
357
+
358
+ ## Verification Checklist
359
+
360
+ Before deploying Edge Functions, verify:
361
+
362
+ - [ ] `setupRBAC(supabase)` is called before any permission checks
363
+ - [ ] `isPermitted()` is used instead of custom helpers
364
+ - [ ] No direct calls to `rbac_check_permission_simplified` RPC
365
+ - [ ] Organisation context is extracted from request
366
+ - [ ] User authentication is verified before permission checks
367
+ - [ ] Error handling for missing auth/context
368
+ - [ ] No custom RBAC helper files exist
369
+ - [ ] All Edge Functions follow the correct pattern
370
+
371
+ ## Related Documentation
372
+
373
+ - [RBAC Compliance Guide](../standards/09-rbac-compliance.md) - Complete compliance rules
374
+ - [RBAC API Reference](./api-reference.md) - Complete API documentation
375
+ - [RBAC Quick Start](./quick-start.md) - Getting started guide
376
+
@@ -491,7 +491,7 @@ export function Dashboard() {
491
491
  const { user, selectedEventId, selectedOrganisationId } = useUnifiedAuth()
492
492
 
493
493
  if (!user) {
494
- return <div>Please log in</div>
494
+ return <p>Please log in</p>
495
495
  }
496
496
 
497
497
  return (
@@ -580,7 +580,7 @@ export function Participants() {
580
580
  const { user, selectedEventId, selectedOrganisationId } = useUnifiedAuth()
581
581
 
582
582
  if (!user) {
583
- return <div>Please log in</div>
583
+ return <p>Please log in</p>
584
584
  }
585
585
 
586
586
  return (
@@ -748,7 +748,7 @@ setupRBAC(supabase) // Must be called BEFORE rendering app
748
748
  setSelectedEventId('your-event-id');
749
749
  }, []);
750
750
 
751
- return <div>...</div>;
751
+ return <p>...</p>;
752
752
  }
753
753
  ```
754
754