@jmruthers/pace-core 0.5.191 → 0.6.1

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 (380) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +7 -1
  3. package/cursor-rules/00-pace-core-compliance.mdc +372 -0
  4. package/cursor-rules/01-standards-compliance.mdc +275 -0
  5. package/cursor-rules/02-project-structure.mdc +200 -0
  6. package/cursor-rules/03-solid-principles.mdc +341 -0
  7. package/cursor-rules/04-testing-standards.mdc +315 -0
  8. package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
  9. package/cursor-rules/06-code-quality.mdc +392 -0
  10. package/cursor-rules/07-tech-stack-compliance.mdc +309 -0
  11. package/cursor-rules/CHANGELOG.md +101 -0
  12. package/cursor-rules/README.md +191 -0
  13. package/dist/{AuthService-CbP_utw2.d.ts → AuthService-DjnJHDtC.d.ts} +1 -0
  14. package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-CH1U5Tpy.d.ts} +1 -1
  15. package/dist/{DataTable-WKRZD47S.js → DataTable-DQ7RSOHE.js} +8 -7
  16. package/dist/{PublicPageProvider-ULXC_u6U.d.ts → PublicPageProvider-ce4xlHYA.d.ts} +37 -156
  17. package/dist/{UnifiedAuthProvider-BYA9qB-o.d.ts → UnifiedAuthProvider-185Ih4dj.d.ts} +2 -0
  18. package/dist/{UnifiedAuthProvider-FTSG5XH7.js → UnifiedAuthProvider-ATAP5UTR.js} +3 -3
  19. package/dist/{api-IHKALJZD.js → api-N774RPUA.js} +2 -2
  20. package/dist/{chunk-6C4YBBJM.js → chunk-3QRJFVBR.js} +1 -1
  21. package/dist/chunk-3QRJFVBR.js.map +1 -0
  22. package/dist/{chunk-OETXORNB.js → chunk-3XTALGJF.js} +211 -136
  23. package/dist/chunk-3XTALGJF.js.map +1 -0
  24. package/dist/{chunk-6TQDD426.js → chunk-4N5C5XZU.js} +47 -228
  25. package/dist/chunk-4N5C5XZU.js.map +1 -0
  26. package/dist/{chunk-LOMZXPSN.js → chunk-4ZC4GX36.js} +47 -74
  27. package/dist/chunk-4ZC4GX36.js.map +1 -0
  28. package/dist/{chunk-6LTQQAT6.js → chunk-BYFSK72L.js} +357 -158
  29. package/dist/chunk-BYFSK72L.js.map +1 -0
  30. package/dist/{chunk-XYXSXPUK.js → chunk-EXUD6RNJ.js} +50 -10
  31. package/dist/chunk-EXUD6RNJ.js.map +1 -0
  32. package/dist/{chunk-VKB2CO4Z.js → chunk-GLK6VM3F.js} +244 -249
  33. package/dist/chunk-GLK6VM3F.js.map +1 -0
  34. package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
  35. package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
  36. package/dist/{chunk-XNYQOL3Z.js → chunk-JBKQ3SAO.js} +9 -18
  37. package/dist/chunk-JBKQ3SAO.js.map +1 -0
  38. package/dist/{chunk-ROXMHMY2.js → chunk-KNC55RTG.js} +13 -3
  39. package/dist/{chunk-ROXMHMY2.js.map → chunk-KNC55RTG.js.map} +1 -1
  40. package/dist/{chunk-QWWZ5CAQ.js → chunk-LXQLPRQ2.js} +2 -2
  41. package/dist/{chunk-ULHIJK66.js → chunk-T33XF5ZC.js} +255 -140
  42. package/dist/chunk-T33XF5ZC.js.map +1 -0
  43. package/dist/{chunk-VRGWKHDB.js → chunk-XM25TVIE.js} +100 -33
  44. package/dist/chunk-XM25TVIE.js.map +1 -0
  45. package/dist/components.d.ts +4 -4
  46. package/dist/components.js +9 -9
  47. package/dist/hooks.d.ts +6 -6
  48. package/dist/hooks.js +20 -25
  49. package/dist/hooks.js.map +1 -1
  50. package/dist/index.d.ts +11 -11
  51. package/dist/index.js +18 -21
  52. package/dist/index.js.map +1 -1
  53. package/dist/providers.d.ts +3 -3
  54. package/dist/providers.js +2 -2
  55. package/dist/rbac/index.d.ts +2 -20
  56. package/dist/rbac/index.js +7 -9
  57. package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-BJAlWfuJ.d.ts} +3 -3
  58. package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
  59. package/dist/utils.d.ts +1 -1
  60. package/dist/utils.js +3 -3
  61. package/docs/api/classes/ColumnFactory.md +1 -1
  62. package/docs/api/classes/ErrorBoundary.md +1 -1
  63. package/docs/api/classes/InvalidScopeError.md +1 -1
  64. package/docs/api/classes/Logger.md +1 -1
  65. package/docs/api/classes/MissingUserContextError.md +1 -1
  66. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  67. package/docs/api/classes/PermissionDeniedError.md +2 -2
  68. package/docs/api/classes/RBACAuditManager.md +2 -2
  69. package/docs/api/classes/RBACCache.md +1 -1
  70. package/docs/api/classes/RBACEngine.md +2 -2
  71. package/docs/api/classes/RBACError.md +1 -1
  72. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  73. package/docs/api/classes/SecureSupabaseClient.md +10 -10
  74. package/docs/api/classes/StorageUtils.md +1 -1
  75. package/docs/api/enums/FileCategory.md +1 -1
  76. package/docs/api/enums/LogLevel.md +1 -1
  77. package/docs/api/enums/RBACErrorCode.md +1 -1
  78. package/docs/api/enums/RPCFunction.md +1 -1
  79. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  80. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  81. package/docs/api/interfaces/AggregateConfig.md +1 -1
  82. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  83. package/docs/api/interfaces/AvatarProps.md +1 -1
  84. package/docs/api/interfaces/BadgeProps.md +1 -1
  85. package/docs/api/interfaces/ButtonProps.md +1 -1
  86. package/docs/api/interfaces/CalendarProps.md +1 -1
  87. package/docs/api/interfaces/CardProps.md +1 -1
  88. package/docs/api/interfaces/ColorPalette.md +1 -1
  89. package/docs/api/interfaces/ColorShade.md +1 -1
  90. package/docs/api/interfaces/ComplianceResult.md +1 -1
  91. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  92. package/docs/api/interfaces/DataRecord.md +1 -1
  93. package/docs/api/interfaces/DataTableAction.md +1 -1
  94. package/docs/api/interfaces/DataTableColumn.md +1 -1
  95. package/docs/api/interfaces/DataTableProps.md +1 -1
  96. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  97. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  98. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  99. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  100. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  101. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  102. package/docs/api/interfaces/ExportColumn.md +1 -1
  103. package/docs/api/interfaces/ExportOptions.md +1 -1
  104. package/docs/api/interfaces/FileDisplayProps.md +24 -11
  105. package/docs/api/interfaces/FileMetadata.md +1 -1
  106. package/docs/api/interfaces/FileReference.md +1 -1
  107. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  108. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  109. package/docs/api/interfaces/FileUploadProps.md +1 -1
  110. package/docs/api/interfaces/FooterProps.md +1 -1
  111. package/docs/api/interfaces/FormFieldProps.md +1 -1
  112. package/docs/api/interfaces/FormProps.md +1 -1
  113. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  114. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  115. package/docs/api/interfaces/InputProps.md +1 -1
  116. package/docs/api/interfaces/LabelProps.md +1 -1
  117. package/docs/api/interfaces/LoggerConfig.md +1 -1
  118. package/docs/api/interfaces/LoginFormProps.md +1 -1
  119. package/docs/api/interfaces/NavigationAccessRecord.md +2 -2
  120. package/docs/api/interfaces/NavigationContextType.md +1 -1
  121. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  122. package/docs/api/interfaces/NavigationItem.md +1 -1
  123. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  124. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  125. package/docs/api/interfaces/Organisation.md +1 -1
  126. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  127. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  128. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  129. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  130. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  131. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  132. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  133. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  134. package/docs/api/interfaces/PagePermissionGuardProps.md +2 -2
  135. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  136. package/docs/api/interfaces/PaletteData.md +1 -1
  137. package/docs/api/interfaces/ParsedAddress.md +1 -1
  138. package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
  139. package/docs/api/interfaces/ProgressProps.md +1 -1
  140. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  141. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  142. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  143. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  144. package/docs/api/interfaces/QuickFix.md +1 -1
  145. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  146. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  147. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  148. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  149. package/docs/api/interfaces/RBACConfig.md +2 -2
  150. package/docs/api/interfaces/RBACContext.md +1 -1
  151. package/docs/api/interfaces/RBACLogger.md +1 -1
  152. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  153. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  154. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  155. package/docs/api/interfaces/RBACPermissionCheckResult.md +2 -2
  156. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  157. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  158. package/docs/api/interfaces/RBACResult.md +1 -1
  159. package/docs/api/interfaces/RBACRoleGrantParams.md +2 -2
  160. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  161. package/docs/api/interfaces/RBACRoleRevokeParams.md +2 -2
  162. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  163. package/docs/api/interfaces/RBACRoleValidateParams.md +2 -2
  164. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  165. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  166. package/docs/api/interfaces/RBACRolesListResult.md +2 -2
  167. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  168. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  169. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  170. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  171. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  172. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  173. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  174. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  175. package/docs/api/interfaces/RouteConfig.md +2 -2
  176. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  177. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  178. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  179. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  180. package/docs/api/interfaces/SetupIssue.md +1 -1
  181. package/docs/api/interfaces/StorageConfig.md +1 -1
  182. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  183. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  184. package/docs/api/interfaces/StorageListOptions.md +1 -1
  185. package/docs/api/interfaces/StorageListResult.md +1 -1
  186. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  187. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  188. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  189. package/docs/api/interfaces/StyleImport.md +1 -1
  190. package/docs/api/interfaces/SwitchProps.md +1 -1
  191. package/docs/api/interfaces/TabsContentProps.md +1 -1
  192. package/docs/api/interfaces/TabsListProps.md +1 -1
  193. package/docs/api/interfaces/TabsProps.md +1 -1
  194. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  195. package/docs/api/interfaces/TextareaProps.md +1 -1
  196. package/docs/api/interfaces/ToastActionElement.md +1 -1
  197. package/docs/api/interfaces/ToastProps.md +1 -1
  198. package/docs/api/interfaces/UnifiedAuthContextType.md +60 -38
  199. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  200. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  201. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  202. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  203. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  204. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  205. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  206. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  207. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  208. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  209. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  210. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  211. package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
  212. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  213. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  214. package/docs/api/interfaces/UserEventAccess.md +1 -1
  215. package/docs/api/interfaces/UserMenuProps.md +1 -1
  216. package/docs/api/interfaces/UserProfile.md +1 -1
  217. package/docs/api/modules.md +194 -209
  218. package/docs/getting-started/cursor-rules.md +262 -0
  219. package/docs/getting-started/installation-guide.md +6 -1
  220. package/docs/getting-started/quick-start.md +6 -1
  221. package/docs/migration/MIGRATION_GUIDE.md +4 -4
  222. package/docs/migration/REACT_19_MIGRATION.md +227 -0
  223. package/docs/migration/database-changes-december-2025.md +2 -1
  224. package/docs/rbac/event-based-apps.md +124 -6
  225. package/docs/standards/README.md +39 -0
  226. package/docs/troubleshooting/migration.md +4 -4
  227. package/examples/PublicPages/PublicEventPage.tsx +1 -1
  228. package/package.json +11 -6
  229. package/scripts/audit-consuming-app.cjs +961 -0
  230. package/scripts/check-pace-core-compliance.cjs +315 -61
  231. package/scripts/install-cursor-rules.cjs +236 -0
  232. package/src/__tests__/helpers/test-providers.tsx +1 -1
  233. package/src/__tests__/helpers/test-utils.tsx +1 -1
  234. package/src/__tests__/rls-policies.test.ts +3 -1
  235. package/src/components/Badge/Badge.tsx +2 -4
  236. package/src/components/Button/Button.tsx +5 -4
  237. package/src/components/Calendar/Calendar.tsx +1 -1
  238. package/src/components/DataTable/DataTable.test.tsx +57 -93
  239. package/src/components/DataTable/DataTable.tsx +2 -2
  240. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +172 -45
  241. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +121 -28
  242. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +9 -8
  243. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +20 -52
  244. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +170 -34
  245. package/src/components/DataTable/__tests__/keyboard.test.tsx +75 -12
  246. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +88 -16
  247. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
  248. package/src/components/DataTable/components/AccessDeniedPage.tsx +1 -1
  249. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
  250. package/src/components/DataTable/components/DataTableCore.tsx +4 -7
  251. package/src/components/DataTable/components/DataTableModals.tsx +1 -1
  252. package/src/components/DataTable/components/EditableRow.tsx +1 -1
  253. package/src/components/DataTable/components/UnifiedTableBody.tsx +86 -17
  254. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
  255. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
  256. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
  257. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
  258. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
  259. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
  260. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
  261. package/src/components/DataTable/hooks/useColumnReordering.ts +2 -2
  262. package/src/components/DataTable/hooks/useDataTablePermissions.ts +75 -10
  263. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
  264. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
  265. package/src/components/Dialog/Dialog.tsx +6 -5
  266. package/src/components/ErrorBoundary/ErrorBoundary.tsx +1 -1
  267. package/src/components/EventSelector/EventSelector.tsx +1 -1
  268. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -3
  269. package/src/components/FileDisplay/FileDisplay.tsx +16 -4
  270. package/src/components/Footer/Footer.tsx +1 -1
  271. package/src/components/Form/Form.test.tsx +36 -15
  272. package/src/components/Form/Form.tsx +30 -26
  273. package/src/components/Header/Header.tsx +1 -1
  274. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
  275. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
  276. package/src/components/Input/Input.tsx +28 -30
  277. package/src/components/Label/Label.tsx +1 -1
  278. package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
  279. package/src/components/LoginForm/LoginForm.test.tsx +42 -42
  280. package/src/components/LoginForm/LoginForm.tsx +8 -8
  281. package/src/components/NavigationMenu/NavigationMenu.test.tsx +6 -4
  282. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -11
  283. package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -1
  284. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
  285. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +75 -52
  286. package/src/components/PaceAppLayout/PaceAppLayout.tsx +98 -69
  287. package/src/components/PaceAppLayout/README.md +1 -1
  288. package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -8
  289. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
  290. package/src/components/PasswordChange/PasswordChangeForm.tsx +1 -1
  291. package/src/components/Progress/Progress.tsx +1 -1
  292. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +5 -9
  293. package/src/components/ProtectedRoute/ProtectedRoute.tsx +0 -1
  294. package/src/components/PublicLayout/PublicPageLayout.tsx +1 -1
  295. package/src/components/PublicLayout/PublicPageProvider.tsx +0 -1
  296. package/src/components/Select/Select.tsx +33 -22
  297. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +1 -1
  298. package/src/components/Table/Table.tsx +1 -1
  299. package/src/components/Textarea/Textarea.tsx +27 -29
  300. package/src/components/Toast/Toast.tsx +1 -1
  301. package/src/components/Tooltip/Tooltip.tsx +1 -1
  302. package/src/components/UserMenu/UserMenu.tsx +1 -1
  303. package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
  304. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +14 -7
  305. package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
  306. package/src/hooks/public/usePublicEvent.ts +1 -1
  307. package/src/hooks/public/usePublicEventLogo.ts +1 -1
  308. package/src/hooks/public/usePublicRouteParams.ts +1 -1
  309. package/src/hooks/services/useAuthService.ts +21 -3
  310. package/src/hooks/services/useEventService.ts +21 -3
  311. package/src/hooks/services/useInactivityService.ts +21 -3
  312. package/src/hooks/services/useOrganisationService.ts +21 -3
  313. package/src/hooks/useDataTableState.ts +8 -18
  314. package/src/hooks/useFileDisplay.ts +10 -17
  315. package/src/hooks/useFocusManagement.ts +2 -2
  316. package/src/hooks/useFocusTrap.ts +4 -4
  317. package/src/hooks/useFormDialog.ts +8 -7
  318. package/src/hooks/useInactivityTracker.ts +1 -1
  319. package/src/hooks/usePermissionCache.ts +1 -1
  320. package/src/hooks/useSecureDataAccess.test.ts +16 -9
  321. package/src/hooks/useSecureDataAccess.ts +22 -6
  322. package/src/hooks/useToast.ts +2 -2
  323. package/src/providers/__tests__/OrganisationProvider.test.tsx +57 -13
  324. package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
  325. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
  326. package/src/providers/services/EventServiceProvider.tsx +0 -8
  327. package/src/providers/services/UnifiedAuthProvider.tsx +196 -46
  328. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +13 -3
  329. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +34 -40
  330. package/src/rbac/__tests__/isSuperAdmin.real.test.ts +82 -0
  331. package/src/rbac/adapters.tsx +3 -22
  332. package/src/rbac/api.test.ts +2 -2
  333. package/src/rbac/api.ts +7 -1
  334. package/src/rbac/components/EnhancedNavigationMenu.tsx +3 -16
  335. package/src/rbac/components/NavigationGuard.tsx +2 -11
  336. package/src/rbac/components/NavigationProvider.tsx +1 -2
  337. package/src/rbac/components/PagePermissionGuard.tsx +1 -1
  338. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  339. package/src/rbac/components/PermissionEnforcer.tsx +46 -13
  340. package/src/rbac/components/RoleBasedRouter.tsx +1 -1
  341. package/src/rbac/components/SecureDataProvider.tsx +1 -2
  342. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +7 -43
  343. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +4 -11
  344. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +3 -3
  345. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +1 -1
  346. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +1 -1
  347. package/src/rbac/engine.ts +14 -2
  348. package/src/rbac/hooks/index.ts +0 -3
  349. package/src/rbac/hooks/usePermissions.ts +51 -11
  350. package/src/rbac/hooks/useRBAC.ts +3 -13
  351. package/src/rbac/hooks/useResolvedScope.test.ts +75 -54
  352. package/src/rbac/hooks/useResolvedScope.ts +58 -33
  353. package/src/rbac/hooks/useSecureSupabase.ts +4 -9
  354. package/src/rbac/secureClient.ts +43 -0
  355. package/src/services/EventService.ts +4 -57
  356. package/src/services/InactivityService.ts +127 -34
  357. package/src/services/OrganisationService.ts +68 -10
  358. package/src/utils/security/secureDataAccess.test.ts +31 -20
  359. package/src/utils/security/secureDataAccess.ts +4 -3
  360. package/dist/chunk-6C4YBBJM.js.map +0 -1
  361. package/dist/chunk-6LTQQAT6.js.map +0 -1
  362. package/dist/chunk-6TQDD426.js.map +0 -1
  363. package/dist/chunk-LOMZXPSN.js.map +0 -1
  364. package/dist/chunk-OETXORNB.js.map +0 -1
  365. package/dist/chunk-ULHIJK66.js.map +0 -1
  366. package/dist/chunk-VKB2CO4Z.js.map +0 -1
  367. package/dist/chunk-VRGWKHDB.js.map +0 -1
  368. package/dist/chunk-XNYQOL3Z.js.map +0 -1
  369. package/dist/chunk-XYXSXPUK.js.map +0 -1
  370. package/scripts/check-pace-core-compliance.js +0 -512
  371. package/src/rbac/hooks/useSuperAdminBypass.ts +0 -126
  372. package/src/utils/context/superAdminOverride.ts +0 -58
  373. /package/dist/{DataTable-WKRZD47S.js.map → DataTable-DQ7RSOHE.js.map} +0 -0
  374. /package/dist/{UnifiedAuthProvider-FTSG5XH7.js.map → UnifiedAuthProvider-ATAP5UTR.js.map} +0 -0
  375. /package/dist/{api-IHKALJZD.js.map → api-N774RPUA.js.map} +0 -0
  376. /package/dist/{chunk-QWWZ5CAQ.js.map → chunk-LXQLPRQ2.js.map} +0 -0
  377. /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
  378. /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
  379. /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
  380. /package/examples/{rbac → RBAC}/index.ts +0 -0
@@ -0,0 +1,392 @@
1
+ ---
2
+ description: Enforce code quality standards including TypeScript, ESLint, formatting, performance, and accessibility
3
+ globs: ["src/**/*.{ts,tsx,js,jsx}"]
4
+ alwaysApply: true
5
+ paceCoreVersion: "0.5.x"
6
+ rulesVersion: "2025-01-15"
7
+ ---
8
+ # Code Quality Guide
9
+
10
+ This guide enforces code quality standards to ensure maintainable, performant, and accessible code.
11
+
12
+ ## TypeScript Standards
13
+
14
+ ### MUST: Use Strict Mode
15
+
16
+ **TypeScript MUST use strict mode:**
17
+
18
+ ```json
19
+ // tsconfig.json
20
+ {
21
+ "compilerOptions": {
22
+ "strict": true,
23
+ "noImplicitAny": true,
24
+ "strictNullChecks": true,
25
+ "strictFunctionTypes": true,
26
+ "strictBindCallApply": true,
27
+ "strictPropertyInitialization": true,
28
+ "noImplicitThis": true,
29
+ "alwaysStrict": true
30
+ }
31
+ }
32
+ ```
33
+
34
+ ### MUST NOT: Use `any`
35
+
36
+ **MUST NOT use `any` type. Use `unknown` if type is truly unknown:**
37
+
38
+ ```tsx
39
+ // ❌ WRONG - Using any
40
+ function processData(data: any) {
41
+ return data.value;
42
+ }
43
+
44
+ // ✅ CORRECT - Using unknown with type guard
45
+ function processData(data: unknown) {
46
+ if (typeof data === 'object' && data !== null && 'value' in data) {
47
+ return (data as { value: string }).value;
48
+ }
49
+ throw new Error('Invalid data');
50
+ }
51
+
52
+ // ✅ CORRECT - Using proper types
53
+ interface Data {
54
+ value: string;
55
+ }
56
+
57
+ function processData(data: Data) {
58
+ return data.value;
59
+ }
60
+ ```
61
+
62
+ ### MUST: Use Discriminated Unions
63
+
64
+ **MUST use discriminated unions instead of boolean flags:**
65
+
66
+ ```tsx
67
+ // ❌ WRONG - Boolean flags
68
+ interface User {
69
+ isAdmin: boolean;
70
+ isGuest: boolean;
71
+ // Confusing: what if both are true?
72
+ }
73
+
74
+ // ✅ CORRECT - Discriminated union
75
+ type User =
76
+ | { type: 'admin'; permissions: Permission[] }
77
+ | { type: 'guest'; limitedAccess: boolean }
78
+ | { type: 'user'; role: UserRole };
79
+ ```
80
+
81
+ ### SHOULD: Use ReadonlyArray
82
+
83
+ **SHOULD use ReadonlyArray for immutable arrays:**
84
+
85
+ ```tsx
86
+ // ✅ CORRECT - ReadonlyArray
87
+ function processItems(items: ReadonlyArray<Item>) {
88
+ // Can't mutate items
89
+ return items.map(item => transform(item));
90
+ }
91
+ ```
92
+
93
+ ## ESLint Configuration
94
+
95
+ ### MUST: Use pace-core ESLint Config
96
+
97
+ **MUST extend pace-core ESLint configuration:**
98
+
99
+ ```javascript
100
+ // eslint.config.js
101
+ import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
102
+
103
+ export default [
104
+ ...paceCoreConfig,
105
+ // Your additional config
106
+ ];
107
+ ```
108
+
109
+ ### MUST: Fix ESLint Errors
110
+
111
+ **MUST fix all ESLint errors before committing:**
112
+
113
+ ```bash
114
+ npm run lint
115
+ npm run lint:fix # Auto-fix where possible
116
+ ```
117
+
118
+ ## Code Formatting
119
+
120
+ ### MUST: Use Consistent Formatting
121
+
122
+ **MUST use Prettier or equivalent for consistent formatting:**
123
+
124
+ ```json
125
+ // .prettierrc
126
+ {
127
+ "semi": true,
128
+ "singleQuote": true,
129
+ "tabWidth": 2,
130
+ "trailingComma": "es5",
131
+ "printWidth": 100
132
+ }
133
+ ```
134
+
135
+ ### MUST: Format Before Committing
136
+
137
+ **MUST format code before committing:**
138
+
139
+ ```bash
140
+ npm run format
141
+ # Or use pre-commit hook
142
+ ```
143
+
144
+ ## Performance Considerations
145
+
146
+ ### SHOULD: Optimize Re-renders
147
+
148
+ **SHOULD use React.memo, useMemo, useCallback appropriately:**
149
+
150
+ ```tsx
151
+ // ✅ CORRECT - Memoize expensive computations
152
+ const expensiveValue = useMemo(() => {
153
+ return computeExpensiveValue(data);
154
+ }, [data]);
155
+
156
+ // ✅ CORRECT - Memoize callbacks
157
+ const handleClick = useCallback(() => {
158
+ doSomething(id);
159
+ }, [id]);
160
+
161
+ // ✅ CORRECT - Memoize components
162
+ const ExpensiveComponent = React.memo(({ data }) => {
163
+ return <div>{/* ... */}</div>;
164
+ });
165
+ ```
166
+
167
+ ### SHOULD: Avoid Unnecessary Re-renders
168
+
169
+ **SHOULD avoid causing unnecessary re-renders:**
170
+
171
+ ```tsx
172
+ // ❌ WRONG - New object on every render
173
+ function Component({ items }) {
174
+ const config = { items, enabled: true }; // New object each render
175
+ return <Child config={config} />;
176
+ }
177
+
178
+ // ✅ CORRECT - Memoize object
179
+ function Component({ items }) {
180
+ const config = useMemo(
181
+ () => ({ items, enabled: true }),
182
+ [items]
183
+ );
184
+ return <Child config={config} />;
185
+ }
186
+ ```
187
+
188
+ ### SHOULD: Lazy Load Heavy Components
189
+
190
+ **SHOULD lazy load heavy components:**
191
+
192
+ ```tsx
193
+ // ✅ CORRECT - Lazy loading
194
+ import { lazy, Suspense } from 'react';
195
+
196
+ const HeavyComponent = lazy(() => import('./HeavyComponent'));
197
+
198
+ function App() {
199
+ return (
200
+ <Suspense fallback={<Loading />}>
201
+ <HeavyComponent />
202
+ </Suspense>
203
+ );
204
+ }
205
+ ```
206
+
207
+ ## Accessibility Requirements
208
+
209
+ ### MUST: Use Semantic HTML
210
+
211
+ **MUST use semantic HTML elements:**
212
+
213
+ ```tsx
214
+ // ❌ WRONG - Non-semantic
215
+ <div onClick={handleClick}>Click me</div>
216
+
217
+ // ✅ CORRECT - Semantic
218
+ <button onClick={handleClick}>Click me</button>
219
+ ```
220
+
221
+ ### MUST: Provide ARIA Labels
222
+
223
+ **MUST provide ARIA labels for interactive elements:**
224
+
225
+ ```tsx
226
+ // ✅ CORRECT - ARIA labels
227
+ <button aria-label="Close dialog">×</button>
228
+ <input aria-label="Search" type="search" />
229
+ ```
230
+
231
+ ### MUST: Ensure Keyboard Navigation
232
+
233
+ **MUST ensure all interactive elements are keyboard accessible:**
234
+
235
+ ```tsx
236
+ // ✅ CORRECT - Keyboard accessible
237
+ <button
238
+ onClick={handleClick}
239
+ onKeyDown={(e) => {
240
+ if (e.key === 'Enter' || e.key === ' ') {
241
+ handleClick();
242
+ }
243
+ }}
244
+ >
245
+ Click me
246
+ </button>
247
+ ```
248
+
249
+ ### MUST: Provide Focus Indicators
250
+
251
+ **MUST provide visible focus indicators:**
252
+
253
+ ```tsx
254
+ // ✅ CORRECT - Focus styles
255
+ <button className="focus:outline-none focus:ring-2 focus:ring-main-500">
256
+ Click me
257
+ </button>
258
+ ```
259
+
260
+ ## Code Review Checklist
261
+
262
+ **Before submitting code for review, verify:**
263
+
264
+ - [ ] TypeScript strict mode enabled
265
+ - [ ] No `any` types used
266
+ - [ ] ESLint passes with no errors
267
+ - [ ] Code is formatted consistently
268
+ - [ ] Performance optimizations applied where needed
269
+ - [ ] Accessibility requirements met
270
+ - [ ] Semantic HTML used
271
+ - [ ] ARIA labels provided
272
+ - [ ] Keyboard navigation works
273
+ - [ ] Focus indicators visible
274
+ - [ ] Code is readable and maintainable
275
+ - [ ] Comments explain "why", not "what"
276
+
277
+ ## Code Complexity
278
+
279
+ ### SHOULD: Keep Functions Small
280
+
281
+ **Functions SHOULD be small and focused:**
282
+
283
+ ```tsx
284
+ // ❌ WRONG - Large function
285
+ function processUserData(user) {
286
+ // 100+ lines of logic
287
+ }
288
+
289
+ // ✅ CORRECT - Small, focused functions
290
+ function validateUser(user: User): ValidationResult {
291
+ // Validation logic
292
+ }
293
+
294
+ function transformUser(user: User): TransformedUser {
295
+ // Transformation logic
296
+ }
297
+
298
+ function processUserData(user: User) {
299
+ const validation = validateUser(user);
300
+ if (!validation.valid) return validation;
301
+ return transformUser(user);
302
+ }
303
+ ```
304
+
305
+ ### SHOULD: Limit Cyclomatic Complexity
306
+
307
+ **Functions SHOULD have low cyclomatic complexity (< 10):**
308
+
309
+ ```tsx
310
+ // ❌ WRONG - High complexity
311
+ function processData(data) {
312
+ if (condition1) {
313
+ if (condition2) {
314
+ if (condition3) {
315
+ // ... many nested conditions
316
+ }
317
+ }
318
+ }
319
+ }
320
+
321
+ // ✅ CORRECT - Lower complexity
322
+ function processData(data) {
323
+ if (!condition1) return;
324
+ if (!condition2) return;
325
+ if (!condition3) return;
326
+ // Process
327
+ }
328
+ ```
329
+
330
+ ## Error Handling
331
+
332
+ ### MUST: Handle Errors Gracefully
333
+
334
+ **MUST handle errors and provide user feedback:**
335
+
336
+ ```tsx
337
+ // ✅ CORRECT - Error handling
338
+ try {
339
+ const data = await fetchData();
340
+ setData(data);
341
+ } catch (error) {
342
+ logger.error('Failed to fetch data', error);
343
+ toast.error('Failed to load data. Please try again.');
344
+ }
345
+ ```
346
+
347
+ ### MUST: Use Type-Safe Error Handling
348
+
349
+ **MUST use type-safe error handling:**
350
+
351
+ ```tsx
352
+ // ✅ CORRECT - Type-safe errors
353
+ function isApiError(error: unknown): error is ApiError {
354
+ return (
355
+ typeof error === 'object' &&
356
+ error !== null &&
357
+ 'code' in error &&
358
+ 'message' in error
359
+ );
360
+ }
361
+
362
+ try {
363
+ await apiCall();
364
+ } catch (error) {
365
+ if (isApiError(error)) {
366
+ handleApiError(error);
367
+ } else {
368
+ handleUnknownError(error);
369
+ }
370
+ }
371
+ ```
372
+
373
+ ## Code Quality Checklist
374
+
375
+ Before committing, verify:
376
+ - [ ] TypeScript strict mode enabled
377
+ - [ ] No `any` types
378
+ - [ ] ESLint passes
379
+ - [ ] Code formatted
380
+ - [ ] Performance optimized
381
+ - [ ] Accessible (semantic HTML, ARIA, keyboard)
382
+ - [ ] Functions are small and focused
383
+ - [ ] Error handling in place
384
+ - [ ] Code is readable
385
+ - [ ] Comments explain "why"
386
+
387
+ ## Reference
388
+
389
+ - TypeScript Handbook: https://www.typescriptlang.org/docs/
390
+ - ESLint Rules: pace-core eslint-config
391
+ - React Performance: https://react.dev/learn/render-and-commit
392
+ - Web Accessibility: https://www.w3.org/WAI/
@@ -0,0 +1,309 @@
1
+ ---
2
+ description: Enforce tech stack compliance including Tailwind v4, React 19+, Supabase, and other required technologies
3
+ globs: ["src/**/*.{ts,tsx,js,jsx,css}", "*.config.{ts,js}"]
4
+ alwaysApply: true
5
+ paceCoreVersion: "0.6.x"
6
+ rulesVersion: "2025-01-28"
7
+ ---
8
+ # Tech Stack Compliance Guide
9
+
10
+ This guide ensures consuming apps use the correct versions and patterns for all technologies in the PACE stack.
11
+
12
+ ## Tailwind CSS v4
13
+
14
+ ### MUST: Use Tailwind v4 CSS-First Approach
15
+
16
+ **MUST use Tailwind v4 CSS-first syntax, NOT v3 patterns:**
17
+
18
+ ```css
19
+ /* ✅ CORRECT - Tailwind v4 */
20
+ @import 'tailwindcss';
21
+
22
+ @theme {
23
+ --color-main-*: oklch(...);
24
+ --color-sec-*: oklch(...);
25
+ --color-acc-*: oklch(...);
26
+ }
27
+
28
+ /* ❌ WRONG - Tailwind v3 */
29
+ @tailwind base;
30
+ @tailwind components;
31
+ @tailwind utilities;
32
+ ```
33
+
34
+ ### MUST NOT: Use Bracket Syntax
35
+
36
+ **MUST NOT use bracket syntax like `bg-[oklch(...)]`. Map everything through theme variables:**
37
+
38
+ ```tsx
39
+ // ❌ WRONG - Bracket syntax
40
+ <div className="bg-[oklch(0.5 0.2 200)]">
41
+
42
+ // ✅ CORRECT - Theme variable
43
+ <div className="bg-main-500">
44
+ ```
45
+
46
+ ### MUST: Use Custom Color Namespaces
47
+
48
+ **MUST use custom color namespaces:**
49
+ - `main-*` for primary colors (green, emerald, teal, cyan, sky, blue)
50
+ - `sec-*` for secondary colors (indigo, violet, purple, fuchsia, slate, gray, zinc, neutral, stone)
51
+ - `acc-*` for accent colors (red, orange, amber, yellow, lime, pink, rose)
52
+
53
+ ```tsx
54
+ // ✅ CORRECT - Custom namespaces
55
+ <div className="bg-main-500 text-sec-800 border-acc-300">
56
+
57
+ // ❌ WRONG - Standard Tailwind colors
58
+ <div className="bg-blue-500 text-gray-800 border-red-300">
59
+ ```
60
+
61
+ ### MUST: Use Semantic Classes
62
+
63
+ **MUST use semantic classes mapped in index.css:**
64
+
65
+ ```tsx
66
+ // ✅ CORRECT - Semantic classes
67
+ <div className="bg-background text-foreground">
68
+
69
+ // ❌ WRONG - Direct color classes (unless necessary)
70
+ <div className="bg-main-50 text-main-950">
71
+ ```
72
+
73
+ ## React 19+
74
+
75
+ ### MUST: Use React 19+ Features
76
+
77
+ **MUST use React 19+ patterns:**
78
+
79
+ ```tsx
80
+ // ✅ CORRECT - React 19 features
81
+ import { Suspense, useTransition } from 'react';
82
+
83
+ function App() {
84
+ const [isPending, startTransition] = useTransition();
85
+
86
+ return (
87
+ <Suspense fallback={<Loading />}>
88
+ <Component />
89
+ </Suspense>
90
+ );
91
+ }
92
+ ```
93
+
94
+ ### MUST: Use Functional Components
95
+
96
+ **MUST use functional components with hooks exclusively:**
97
+
98
+ ```tsx
99
+ // ✅ CORRECT - Functional component
100
+ function MyComponent() {
101
+ const [state, setState] = useState();
102
+ return <div>...</div>;
103
+ }
104
+
105
+ // ❌ WRONG - Class component
106
+ class MyComponent extends React.Component {
107
+ // ...
108
+ }
109
+ ```
110
+
111
+ ## Supabase
112
+
113
+ ### MUST: Use Secure Supabase Client
114
+
115
+ **MUST use `useSecureSupabase()` for all database operations:**
116
+
117
+ ```tsx
118
+ // ✅ CORRECT - Secure client
119
+ import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
120
+
121
+ function Component() {
122
+ const secureSupabase = useSecureSupabase();
123
+ const { data } = await secureSupabase.from('table').select('*');
124
+ }
125
+
126
+ // ❌ WRONG - Base client
127
+ import { createClient } from '@supabase/supabase-js';
128
+ const supabase = createClient(...);
129
+ ```
130
+
131
+ ### MUST: Enforce RLS
132
+
133
+ **MUST ensure RLS is enabled on all tables. Never bypass RLS.**
134
+
135
+ ### SHOULD: Use RPC Functions
136
+
137
+ **SHOULD use RPC functions for complex queries:**
138
+
139
+ ```tsx
140
+ // ✅ CORRECT - RPC function
141
+ const { data } = await secureSupabase.rpc('data_events_list', {
142
+ organisation_id: orgId
143
+ });
144
+
145
+ // ❌ AVOID - Complex client-side queries
146
+ const { data } = await secureSupabase
147
+ .from('events')
148
+ .select('*, organisations(*), users(*)')
149
+ .eq('organisation_id', orgId)
150
+ // ... many joins
151
+ ```
152
+
153
+ ## TanStack Query
154
+
155
+ ### MUST: Use TanStack Query for Server State
156
+
157
+ **MUST use TanStack Query for all server state management:**
158
+
159
+ ```tsx
160
+ // ✅ CORRECT - TanStack Query
161
+ import { useQuery, useMutation } from '@tanstack/react-query';
162
+
163
+ function Component() {
164
+ const { data, isLoading } = useQuery({
165
+ queryKey: ['events', orgId],
166
+ queryFn: () => fetchEvents(orgId)
167
+ });
168
+
169
+ const mutation = useMutation({
170
+ mutationFn: createEvent,
171
+ onSuccess: () => {
172
+ queryClient.invalidateQueries({ queryKey: ['events'] });
173
+ }
174
+ });
175
+ }
176
+
177
+ // ❌ WRONG - useState for server state
178
+ const [data, setData] = useState();
179
+ useEffect(() => {
180
+ fetchEvents().then(setData);
181
+ }, []);
182
+ ```
183
+
184
+ ### SHOULD: Configure Query Client
185
+
186
+ **SHOULD configure QueryClient with appropriate defaults:**
187
+
188
+ ```tsx
189
+ // ✅ CORRECT - Configured QueryClient
190
+ const queryClient = new QueryClient({
191
+ defaultOptions: {
192
+ queries: {
193
+ staleTime: 5 * 60 * 1000, // 5 minutes
194
+ cacheTime: 10 * 60 * 1000, // 10 minutes
195
+ retry: 1,
196
+ },
197
+ },
198
+ });
199
+ ```
200
+
201
+ ## React Hook Form + Zod
202
+
203
+ ### MUST: Use React Hook Form with Zod
204
+
205
+ **MUST use React Hook Form with Zod for all forms:**
206
+
207
+ ```tsx
208
+ // ✅ CORRECT - React Hook Form + Zod
209
+ import { useZodForm } from '@jmruthers/pace-core';
210
+ import { z } from 'zod';
211
+
212
+ const schema = z.object({
213
+ email: z.string().email(),
214
+ name: z.string().min(1),
215
+ });
216
+
217
+ function Form() {
218
+ const form = useZodForm(schema);
219
+ return <Form {...form}>...</Form>;
220
+ }
221
+
222
+ // ❌ WRONG - Manual form handling
223
+ const [email, setEmail] = useState('');
224
+ const [errors, setErrors] = useState({});
225
+ ```
226
+
227
+ ## Vite
228
+
229
+ ### MUST: Use Vite for Build Tooling
230
+
231
+ **MUST use Vite for all build tooling:**
232
+
233
+ ```typescript
234
+ // vite.config.ts
235
+ import { defineConfig } from 'vite';
236
+ import react from '@vitejs/plugin-react';
237
+
238
+ export default defineConfig({
239
+ plugins: [react()],
240
+ // ...
241
+ });
242
+ ```
243
+
244
+ ### MUST: Use Environment Variables Correctly
245
+
246
+ **MUST use `import.meta.env` for environment variables:**
247
+
248
+ ```tsx
249
+ // ✅ CORRECT - Vite env vars
250
+ const apiUrl = import.meta.env.VITE_API_URL;
251
+
252
+ // ❌ WRONG - Node.js env vars
253
+ const apiUrl = process.env.VITE_API_URL;
254
+ ```
255
+
256
+ ## TypeScript
257
+
258
+ ### MUST: Use TypeScript 5+
259
+
260
+ **MUST use TypeScript 5+ with strict mode:**
261
+
262
+ ```json
263
+ // tsconfig.json
264
+ {
265
+ "compilerOptions": {
266
+ "target": "ES2022",
267
+ "module": "ESNext",
268
+ "strict": true,
269
+ // ...
270
+ }
271
+ }
272
+ ```
273
+
274
+ ## Version Requirements
275
+
276
+ ### MUST: Use Required Versions
277
+
278
+ **MUST use compatible versions:**
279
+
280
+ - React: `^19.0.0`
281
+ - TypeScript: `^5.0.0`
282
+ - Tailwind CSS: `^4.0.0`
283
+ - Vite: `^6.0.0`
284
+ - Supabase: `^2.49.0+`
285
+
286
+ **Check `package.json` for exact versions required by pace-core.**
287
+
288
+ ## Tech Stack Checklist
289
+
290
+ Before committing, verify:
291
+ - [ ] Tailwind v4 CSS-first syntax (no @tailwind directives)
292
+ - [ ] No bracket syntax for colors (use theme variables)
293
+ - [ ] Custom color namespaces (main-*, sec-*, acc-*)
294
+ - [ ] React 19+ functional components
295
+ - [ ] Secure Supabase client (useSecureSupabase)
296
+ - [ ] TanStack Query for server state
297
+ - [ ] React Hook Form + Zod for forms
298
+ - [ ] Vite for build tooling
299
+ - [ ] TypeScript 5+ with strict mode
300
+ - [ ] All versions compatible with pace-core
301
+
302
+ ## Reference
303
+
304
+ - Tailwind v4: https://tailwindcss.com/blog/tailwindcss-v4
305
+ - React 19: https://react.dev/blog/2024/04/25/react-19-upgrade-guide
306
+ - Supabase: https://supabase.com/docs
307
+ - TanStack Query: https://tanstack.com/query
308
+ - React Hook Form: https://react-hook-form.com
309
+ - Vite: https://vitejs.dev