@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,662 @@
1
+ # API & Tech Stack Standards
2
+
3
+ **🤖 Cursor Rule**: See [07-api-tech-stack.mdc](../../cursor-rules/07-api-tech-stack.mdc) for AI-optimized directives that automatically enforce tech stack compliance.
4
+
5
+ **🔧 ESLint Rules**: See [07-api-tech-stack.cjs](../../eslint-rules/rules/07-api-tech-stack.cjs) for mechanically checkable API and tech stack rules.
6
+
7
+ ## Purpose
8
+
9
+ This standard defines the required technology stack, API design patterns, and RPC conventions to ensure consistency, type safety, and maintainability across pace-core and consuming apps.
10
+
11
+ ---
12
+
13
+ ## Required Tech Stack
14
+
15
+ ### Core Technologies
16
+
17
+ **MUST** use these technologies and versions:
18
+
19
+ - **React 19+** - Functional components only, no class components
20
+ - **TypeScript 5+** - With `strict` mode enabled
21
+ - **Vite** - For tooling; use `import.meta.env` for environment variables
22
+ - **Tailwind v4** - CSS-first with `app.css` scaffold (see [Styling Standards](./5-styling-standards.md))
23
+ - **Supabase** - Via secure clients/hooks (`useSecureSupabase`); never bypass RLS
24
+ - **TanStack Query** - For server state management
25
+ - **React Hook Form + Zod** - Prefer `useZodForm` from pace-core for forms
26
+
27
+ ### Version Requirements
28
+
29
+ ```json
30
+ {
31
+ "dependencies": {
32
+ "react": "^19.0.0",
33
+ "react-dom": "^19.0.0",
34
+ "@types/react": "^19.0.0",
35
+ "@types/react-dom": "^19.0.0",
36
+ "typescript": "^5.0.0",
37
+ "@supabase/supabase-js": "^2.0.0",
38
+ "@tanstack/react-query": "^5.0.0",
39
+ "react-hook-form": "^7.0.0",
40
+ "zod": "^3.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "vite": "^5.0.0",
44
+ "@vitejs/plugin-react": "^4.0.0"
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Environment Variables
50
+
51
+ **MUST** use `import.meta.env` (Vite) for environment variables:
52
+
53
+ ```typescript
54
+ // ✅ CORRECT - Vite environment variables
55
+ const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
56
+ const supabaseKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY;
57
+
58
+ // ❌ WRONG - Node.js process.env
59
+ const supabaseUrl = process.env.VITE_SUPABASE_URL;
60
+ ```
61
+
62
+ ---
63
+
64
+ ## API & RPC Naming Conventions
65
+
66
+ ### RPC Naming Pattern
67
+
68
+ **MUST** follow this naming pattern: `<family>_<domain>_<verb>`
69
+
70
+ - **Family**: `data` (read operations), `app` (write operations)
71
+ - **Domain**: Feature/domain name (e.g., `events`, `users`, `cake_dish`)
72
+ - **Verb**: Operation name (e.g., `list`, `get`, `create`, `update`, `delete`)
73
+
74
+ **Examples:**
75
+ ```typescript
76
+ // Read operations (data_*)
77
+ data_events_list
78
+ data_events_get
79
+ data_users_list
80
+ data_cake_dish_list
81
+
82
+ // Write operations (app_*)
83
+ app_events_create
84
+ app_events_update
85
+ app_events_delete
86
+ app_cake_dish_create
87
+
88
+ // Bulk operations (use _bulk_ prefix)
89
+ app_events_bulk_create
90
+ app_cake_dish_bulk_update
91
+ ```
92
+
93
+ ### Naming Rules
94
+
95
+ 1. **Use snake_case** for all RPC names
96
+ 2. **Read operations** start with `data_`
97
+ 3. **Write operations** start with `app_`
98
+ 4. **Bulk operations** use `_bulk_` prefix (e.g., `app_events_bulk_create`)
99
+ 5. **Domain names** should match table names where applicable
100
+ 6. **Verb names** should be clear and consistent (`list`, `get`, `create`, `update`, `delete`)
101
+
102
+ ---
103
+
104
+ ## API Result Shape
105
+
106
+ ### Standard Result Type
107
+
108
+ **MUST** use this result type for all APIs:
109
+
110
+ ```typescript
111
+ type ApiResult<T> =
112
+ | { ok: true; data: T }
113
+ | { ok: false; error: ApiError };
114
+
115
+ type ApiError = {
116
+ code: string; // Machine-readable error code
117
+ message: string; // User-friendly message
118
+ details?: object; // Optional additional context (non-sensitive)
119
+ };
120
+ ```
121
+
122
+ ### Example Usage
123
+
124
+ ```typescript
125
+ // ✅ CORRECT - Using ApiResult type
126
+ async function fetchEvent(id: string): Promise<ApiResult<Event>> {
127
+ try {
128
+ const { data, error } = await supabase
129
+ .from('events')
130
+ .select('*')
131
+ .eq('id', id)
132
+ .single();
133
+
134
+ if (error) {
135
+ return {
136
+ ok: false,
137
+ error: {
138
+ code: 'EVENT_NOT_FOUND',
139
+ message: 'Event not found',
140
+ details: { eventId: id },
141
+ },
142
+ };
143
+ }
144
+
145
+ return { ok: true, data };
146
+ } catch (error) {
147
+ return {
148
+ ok: false,
149
+ error: {
150
+ code: 'UNKNOWN_ERROR',
151
+ message: 'An unexpected error occurred',
152
+ },
153
+ };
154
+ }
155
+ }
156
+
157
+ // Usage
158
+ const result = await fetchEvent(eventId);
159
+ if (result.ok) {
160
+ // TypeScript knows result.data exists
161
+ console.log(result.data.name);
162
+ } else {
163
+ // TypeScript knows result.error exists
164
+ toast.error(result.error.message);
165
+ }
166
+ ```
167
+
168
+ ### RPC Result Shape
169
+
170
+ **RPCs MUST** return data in a format that can be wrapped in `ApiResult`:
171
+
172
+ ```sql
173
+ -- ✅ CORRECT - RPC returns data directly
174
+ CREATE OR REPLACE FUNCTION data_events_list(
175
+ p_organisation_id UUID
176
+ )
177
+ RETURNS TABLE (
178
+ id UUID,
179
+ name TEXT,
180
+ date TIMESTAMPTZ
181
+ )
182
+ LANGUAGE plpgsql
183
+ STABLE
184
+ SECURITY DEFINER
185
+ SET search_path TO public
186
+ AS $$
187
+ BEGIN
188
+ RETURN QUERY
189
+ SELECT e.id, e.name, e.date
190
+ FROM events e
191
+ WHERE e.organisation_id = p_organisation_id;
192
+ END;
193
+ $$;
194
+ ```
195
+
196
+ **Client-side wrapper:**
197
+ ```typescript
198
+ async function listEvents(organisationId: string): Promise<ApiResult<Event[]>> {
199
+ const { data, error } = await supabase.rpc('data_events_list', {
200
+ p_organisation_id: organisationId,
201
+ });
202
+
203
+ if (error) {
204
+ return {
205
+ ok: false,
206
+ error: {
207
+ code: 'LIST_FAILED',
208
+ message: 'Failed to list events',
209
+ details: { error: error.message },
210
+ },
211
+ };
212
+ }
213
+
214
+ return { ok: true, data: data ?? [] };
215
+ }
216
+ ```
217
+
218
+ ---
219
+
220
+ ## RPC Rules
221
+
222
+ ### Read RPCs Never Mutate
223
+
224
+ **Read operations MUST NOT have side effects.**
225
+
226
+ ```sql
227
+ -- ❌ WRONG - Read operation with side effect
228
+ CREATE OR REPLACE FUNCTION data_events_get(p_event_id UUID)
229
+ RETURNS TABLE (...)
230
+ AS $$
231
+ BEGIN
232
+ -- Side effect: updates last_accessed
233
+ UPDATE events SET last_accessed = NOW() WHERE id = p_event_id;
234
+ RETURN QUERY SELECT * FROM events WHERE id = p_event_id;
235
+ END;
236
+ $$;
237
+
238
+ -- ✅ CORRECT - Pure read operation
239
+ CREATE OR REPLACE FUNCTION data_events_get(p_event_id UUID)
240
+ RETURNS TABLE (...)
241
+ LANGUAGE plpgsql
242
+ STABLE -- ✅ STABLE for read operations
243
+ SECURITY DEFINER
244
+ SET search_path TO public
245
+ AS $$
246
+ BEGIN
247
+ RETURN QUERY
248
+ SELECT * FROM events WHERE id = p_event_id;
249
+ END;
250
+ $$;
251
+ ```
252
+
253
+ ### Write RPCs Should Be Idempotent
254
+
255
+ **Write operations SHOULD be idempotent when possible.**
256
+
257
+ ```sql
258
+ -- ✅ CORRECT - Idempotent upsert
259
+ CREATE OR REPLACE FUNCTION app_events_upsert(
260
+ p_id UUID,
261
+ p_name TEXT,
262
+ p_date TIMESTAMPTZ
263
+ )
264
+ RETURNS UUID
265
+ LANGUAGE plpgsql
266
+ SECURITY DEFINER
267
+ SET search_path TO public
268
+ AS $$
269
+ DECLARE
270
+ v_event_id UUID;
271
+ BEGIN
272
+ INSERT INTO events (id, name, date, organisation_id)
273
+ VALUES (p_id, p_name, p_date, get_organisation_context())
274
+ ON CONFLICT (id) DO UPDATE
275
+ SET name = EXCLUDED.name, date = EXCLUDED.date
276
+ RETURNING id INTO v_event_id;
277
+
278
+ RETURN v_event_id;
279
+ END;
280
+ $$;
281
+ ```
282
+
283
+ ### Never Accept Dynamic SQL
284
+
285
+ **NEVER accept SQL strings as parameters. Use parameterized queries or RPCs.**
286
+
287
+ ```sql
288
+ -- ❌ WRONG - Dynamic SQL injection risk
289
+ CREATE OR REPLACE FUNCTION execute_query(p_sql TEXT)
290
+ RETURNS TABLE (...)
291
+ AS $$
292
+ BEGIN
293
+ RETURN QUERY EXECUTE p_sql; -- DANGEROUS!
294
+ END;
295
+ $$;
296
+
297
+ -- ✅ CORRECT - Parameterized query
298
+ CREATE OR REPLACE FUNCTION data_events_list(
299
+ p_organisation_id UUID,
300
+ p_status TEXT DEFAULT NULL,
301
+ p_limit INTEGER DEFAULT 100
302
+ )
303
+ RETURNS TABLE (...)
304
+ AS $$
305
+ BEGIN
306
+ RETURN QUERY
307
+ SELECT * FROM events
308
+ WHERE organisation_id = p_organisation_id
309
+ AND (p_status IS NULL OR status = p_status)
310
+ LIMIT p_limit;
311
+ END;
312
+ $$;
313
+ ```
314
+
315
+ ### Enforce RLS + Tenant Boundaries
316
+
317
+ **RPCs MUST enforce RLS and tenant boundaries. Never bypass security checks.**
318
+
319
+ ```sql
320
+ -- ✅ CORRECT - RLS enforced via helper functions
321
+ CREATE OR REPLACE FUNCTION data_events_list(p_organisation_id UUID)
322
+ RETURNS TABLE (...)
323
+ LANGUAGE plpgsql
324
+ STABLE
325
+ SECURITY DEFINER
326
+ SET search_path TO public
327
+ AS $$
328
+ BEGIN
329
+ -- Check organisation access
330
+ IF NOT check_user_organisation_access(p_organisation_id) THEN
331
+ RAISE EXCEPTION 'Access denied';
332
+ END IF;
333
+
334
+ RETURN QUERY
335
+ SELECT * FROM events
336
+ WHERE organisation_id = p_organisation_id;
337
+ END;
338
+ $$;
339
+ ```
340
+
341
+ **Real-World Example: Complex RPC with Multiple Security Checks**
342
+
343
+ ```sql
344
+ -- Real-world example: Creating an event with attendees and permissions
345
+ CREATE OR REPLACE FUNCTION app_events_create_with_attendees(
346
+ p_name TEXT,
347
+ p_date TIMESTAMPTZ,
348
+ p_organisation_id UUID,
349
+ p_attendee_ids UUID[]
350
+ )
351
+ RETURNS UUID
352
+ LANGUAGE plpgsql
353
+ SECURITY DEFINER
354
+ SET search_path TO public
355
+ AS $$
356
+ DECLARE
357
+ v_event_id UUID;
358
+ v_user_id UUID;
359
+ v_has_permission BOOLEAN;
360
+ BEGIN
361
+ -- 1. Get current user ID
362
+ v_user_id := safe_get_user_id_for_rls();
363
+
364
+ -- 2. Check organisation access
365
+ IF NOT check_user_organisation_access(p_organisation_id) THEN
366
+ RAISE EXCEPTION 'You do not have access to this organisation';
367
+ END IF;
368
+
369
+ -- 3. Check create permission using RBAC
370
+ v_has_permission := check_rbac_permission_with_context(
371
+ 'create:page.events',
372
+ 'events',
373
+ p_organisation_id,
374
+ NULL,
375
+ get_app_id('PACE')
376
+ );
377
+
378
+ IF NOT v_has_permission THEN
379
+ RAISE EXCEPTION 'You do not have permission to create events';
380
+ END IF;
381
+
382
+ -- 4. Validate attendee IDs belong to the same organisation
383
+ IF array_length(p_attendee_ids, 1) > 0 THEN
384
+ IF EXISTS (
385
+ SELECT 1 FROM users
386
+ WHERE id = ANY(p_attendee_ids)
387
+ AND organisation_id != p_organisation_id
388
+ ) THEN
389
+ RAISE EXCEPTION 'All attendees must belong to the same organisation';
390
+ END IF;
391
+ END IF;
392
+
393
+ -- 5. Create event
394
+ INSERT INTO events (name, date, organisation_id, created_by)
395
+ VALUES (p_name, p_date, p_organisation_id, v_user_id)
396
+ RETURNING id INTO v_event_id;
397
+
398
+ -- 6. Create attendee records
399
+ IF array_length(p_attendee_ids, 1) > 0 THEN
400
+ INSERT INTO event_attendees (event_id, user_id, organisation_id)
401
+ SELECT v_event_id, unnest(p_attendee_ids), p_organisation_id;
402
+ END IF;
403
+
404
+ RETURN v_event_id;
405
+ END;
406
+ $$;
407
+
408
+ -- Usage in TypeScript
409
+ async function createEventWithAttendees(
410
+ name: string,
411
+ date: Date,
412
+ organisationId: string,
413
+ attendeeIds: string[]
414
+ ): Promise<ApiResult<{ eventId: string }>> {
415
+ const { data, error } = await secureSupabase.rpc('app_events_create_with_attendees', {
416
+ p_name: name,
417
+ p_date: date.toISOString(),
418
+ p_organisation_id: organisationId,
419
+ p_attendee_ids: attendeeIds,
420
+ });
421
+
422
+ if (error) {
423
+ // Map database errors to user-friendly messages
424
+ if (error.message.includes('access to this organisation')) {
425
+ return {
426
+ ok: false,
427
+ error: {
428
+ code: 'ORGANISATION_ACCESS_DENIED',
429
+ message: 'You do not have access to this organisation',
430
+ },
431
+ };
432
+ }
433
+ if (error.message.includes('permission to create events')) {
434
+ return {
435
+ ok: false,
436
+ error: {
437
+ code: 'PERMISSION_DENIED',
438
+ message: 'You do not have permission to create events',
439
+ },
440
+ };
441
+ }
442
+ if (error.message.includes('same organisation')) {
443
+ return {
444
+ ok: false,
445
+ error: {
446
+ code: 'INVALID_ATTENDEES',
447
+ message: 'All attendees must belong to the same organisation',
448
+ },
449
+ };
450
+ }
451
+
452
+ return {
453
+ ok: false,
454
+ error: {
455
+ code: 'CREATE_FAILED',
456
+ message: 'Unable to create event. Please try again.',
457
+ },
458
+ };
459
+ }
460
+
461
+ return { ok: true, data: { eventId: data } };
462
+ }
463
+ ```
464
+
465
+ ### User-Safe Error Messages
466
+
467
+ **Errors MUST be user-friendly and not expose internal details.**
468
+
469
+ ```sql
470
+ -- ❌ WRONG - Exposes internal details
471
+ CREATE OR REPLACE FUNCTION app_events_create(...)
472
+ AS $$
473
+ BEGIN
474
+ IF some_condition THEN
475
+ RAISE EXCEPTION 'SQLSTATE[23000]: Integrity constraint violation: duplicate key';
476
+ END IF;
477
+ END;
478
+ $$;
479
+
480
+ -- ✅ CORRECT - User-friendly error
481
+ CREATE OR REPLACE FUNCTION app_events_create(...)
482
+ AS $$
483
+ BEGIN
484
+ IF some_condition THEN
485
+ RAISE EXCEPTION 'An event with this name already exists';
486
+ END IF;
487
+ END;
488
+ $$;
489
+ ```
490
+
491
+ ---
492
+
493
+ ## Deprecation Policy
494
+
495
+ ### Deprecation Process
496
+
497
+ **When deprecating APIs or RPCs:**
498
+
499
+ 1. **Mark with `@deprecated`** JSDoc comment
500
+ 2. **Add migration notes** in documentation
501
+ 3. **Retirement window** = 2 stable releases
502
+ 4. **Remove after retirement window** expires
503
+
504
+ ### Example Deprecation
505
+
506
+ ```typescript
507
+ /**
508
+ * @deprecated Use `data_events_list` instead. This function will be removed in v2.0.0.
509
+ *
510
+ * Migration:
511
+ * ```typescript
512
+ * // Old
513
+ * const events = await getEvents(orgId);
514
+ *
515
+ * // New
516
+ * const result = await listEvents(orgId);
517
+ * if (result.ok) {
518
+ * const events = result.data;
519
+ * }
520
+ * ```
521
+ */
522
+ async function getEvents(organisationId: string): Promise<Event[]> {
523
+ // Implementation
524
+ }
525
+ ```
526
+
527
+ ---
528
+
529
+ ## Tech Stack Configuration
530
+
531
+ ### TypeScript Configuration
532
+
533
+ **MUST** enable strict mode:
534
+
535
+ ```json
536
+ {
537
+ "compilerOptions": {
538
+ "strict": true,
539
+ "noImplicitAny": true,
540
+ "strictNullChecks": true,
541
+ "strictFunctionTypes": true,
542
+ "strictBindCallApply": true,
543
+ "strictPropertyInitialization": true,
544
+ "noImplicitThis": true,
545
+ "alwaysStrict": true
546
+ }
547
+ }
548
+ ```
549
+
550
+ ### Vite Configuration
551
+
552
+ **MUST** configure path aliases, React plugin, and dependency optimization:
553
+
554
+ ```typescript
555
+ // vite.config.ts
556
+ import { defineConfig } from 'vite';
557
+ import react from '@vitejs/plugin-react';
558
+ import path from 'path';
559
+
560
+ export default defineConfig({
561
+ plugins: [react()],
562
+ resolve: {
563
+ alias: {
564
+ '@': path.resolve(__dirname, './src'),
565
+ },
566
+ // CRITICAL: Dedupe React dependencies to prevent context mismatches
567
+ dedupe: ['react', 'react-dom', 'react-router-dom'],
568
+ },
569
+ optimizeDeps: {
570
+ include: [
571
+ 'react',
572
+ 'react-dom',
573
+ 'react/jsx-runtime',
574
+ ],
575
+ // CRITICAL: Exclude pace-core and react-router-dom to prevent React context mismatches
576
+ exclude: ['@jmruthers/pace-core', 'react-router-dom'],
577
+ },
578
+ envPrefix: 'VITE_', // Only expose VITE_* env vars
579
+ });
580
+ ```
581
+
582
+ **Why this configuration is required:**
583
+ - Pre-bundling `@jmruthers/pace-core` creates separate React instances, causing "useUnifiedAuth must be used within a UnifiedAuthProvider" errors
584
+ - Excluding it ensures pace-core uses the same React instance as your app
585
+ - `react-router-dom` must also be excluded and deduped to prevent Router context errors
586
+
587
+ **If you encounter context errors:**
588
+ 1. Verify `@jmruthers/pace-core` is in `optimizeDeps.exclude`
589
+ 2. Verify `react-router-dom` is in both `resolve.dedupe` and `optimizeDeps.exclude`
590
+ 3. Clear Vite cache: `rm -rf node_modules/.vite`
591
+ 4. Restart dev server
592
+
593
+ ### TanStack Query Configuration
594
+
595
+ **MUST** configure appropriate cache times:
596
+
597
+ ```typescript
598
+ import { QueryClient } from '@tanstack/react-query';
599
+
600
+ export const queryClient = new QueryClient({
601
+ defaultOptions: {
602
+ queries: {
603
+ staleTime: 5 * 60 * 1000, // 5 minutes
604
+ gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
605
+ retry: 1,
606
+ refetchOnWindowFocus: false,
607
+ },
608
+ },
609
+ });
610
+ ```
611
+
612
+ ---
613
+
614
+ ## API Design Checklist
615
+
616
+ Before creating or updating an API/RPC, verify:
617
+
618
+ - [ ] RPC name follows naming convention (`data_*` or `app_*`)
619
+ - [ ] Uses `ApiResult<T>` type for return values
620
+ - [ ] Read RPCs are `STABLE` and have no side effects
621
+ - [ ] Write RPCs are idempotent when possible
622
+ - [ ] No dynamic SQL accepted as parameters
623
+ - [ ] RLS and tenant boundaries enforced
624
+ - [ ] Error messages are user-friendly
625
+ - [ ] TypeScript types are complete and accurate
626
+ - [ ] Deprecation process followed if removing/changing APIs
627
+
628
+ ---
629
+
630
+ ## ESLint Rules
631
+
632
+ The following ESLint rules enforce API and tech stack standards:
633
+
634
+ ### RPC Naming
635
+
636
+ - **`rpc-naming-pattern`** - Enforces `data_*` prefix for read operations and `app_*` prefix for write operations
637
+
638
+ ### React 19+ Patterns
639
+
640
+ - **`no-class-components`** - Disallows React class components (functional components only)
641
+
642
+ ### Environment Variables
643
+
644
+ - **`prefer-import-meta-env`** - Enforces `import.meta.env` (Vite) instead of `process.env` in client code
645
+
646
+ These rules are part of the `pace-core-compliance` plugin and are automatically enabled when you extend `@jmruthers/pace-core/eslint-config`.
647
+
648
+ **Setup**: Run `node node_modules/@jmruthers/pace-core/scripts/install-eslint-config.cjs` to configure ESLint in your consuming app.
649
+
650
+ ## Related Documentation
651
+
652
+ - [Standards Overview](./0-standards-overview.md) - Standards system overview
653
+ - [Architecture](./3-architecture-standards.md) - API design principles
654
+ - [Code Quality](./4-code-quality-standards.md) - TypeScript standards
655
+ - [Security & RBAC](./6-security-rbac-standards.md) - RLS and security requirements
656
+ - [Operations](./9-operations-standards.md) - Error handling patterns
657
+
658
+ ---
659
+
660
+ **Last Updated:** 2025-01-28
661
+ **Version:** 2.0.0
662
+ **Applies to:** All pace-core and consuming apps