@jmruthers/pace-core 0.5.193 → 0.6.2

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 (577) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +7 -1
  3. package/cursor-rules/00-pace-core-compliance.mdc +299 -0
  4. package/cursor-rules/01-standards-compliance.mdc +244 -0
  5. package/cursor-rules/02-project-structure.mdc +200 -0
  6. package/cursor-rules/03-solid-principles.mdc +222 -0
  7. package/cursor-rules/04-testing-standards.mdc +268 -0
  8. package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
  9. package/cursor-rules/06-code-quality.mdc +309 -0
  10. package/cursor-rules/07-tech-stack-compliance.mdc +214 -0
  11. package/cursor-rules/08-markup-quality.mdc +452 -0
  12. package/cursor-rules/CHANGELOG.md +119 -0
  13. package/cursor-rules/README.md +192 -0
  14. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-BPvc3Ka0.d.ts} +54 -0
  15. package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-BMRU8a1j.d.ts} +34 -2
  16. package/dist/{DataTable-5FU7IESH.js → DataTable-TPTKCX4D.js} +10 -9
  17. package/dist/{PublicPageProvider-C0Sm_e5k.d.ts → PublicPageProvider-DC6kCaqf.d.ts} +385 -261
  18. package/dist/{UnifiedAuthProvider-RGJTDE2C.js → UnifiedAuthProvider-CH6Z342H.js} +3 -3
  19. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CVcTjx-d.d.ts} +29 -0
  20. package/dist/{api-N774RPUA.js → api-MVVQZLJI.js} +2 -2
  21. package/dist/{chunk-KNC55RTG.js → chunk-24UVZUZG.js} +90 -54
  22. package/dist/chunk-24UVZUZG.js.map +1 -0
  23. package/dist/{chunk-HWIIPPNI.js → chunk-2UOI2FG5.js} +20 -20
  24. package/dist/chunk-2UOI2FG5.js.map +1 -0
  25. package/dist/{chunk-E3SPN4VZ 5.js → chunk-3XC4CPTD.js} +4345 -3986
  26. package/dist/chunk-3XC4CPTD.js.map +1 -0
  27. package/dist/{chunk-7EQTDTTJ.js → chunk-6J4GEEJR.js} +172 -45
  28. package/dist/chunk-6J4GEEJR.js.map +1 -0
  29. package/dist/{chunk-6C4YBBJM 5.js → chunk-6SOIHG6Z.js} +1 -1
  30. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  31. package/dist/{chunk-7FLMSG37.js → chunk-EHMR7VYL.js} +25 -25
  32. package/dist/chunk-EHMR7VYL.js.map +1 -0
  33. package/dist/{chunk-I7PSE6JW.js → chunk-F2IMUDXZ.js} +2 -75
  34. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  35. package/dist/{chunk-QWWZ5CAQ.js → chunk-FFQEQTNW.js} +7 -9
  36. package/dist/chunk-FFQEQTNW.js.map +1 -0
  37. package/dist/chunk-FMUCXFII.js +76 -0
  38. package/dist/chunk-FMUCXFII.js.map +1 -0
  39. package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
  40. package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
  41. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  42. package/dist/chunk-L4OXEN46.js.map +1 -0
  43. package/dist/{chunk-R77UEZ4E 3.js → chunk-M43Y4SSO.js} +1 -1
  44. package/dist/chunk-M43Y4SSO.js.map +1 -0
  45. package/dist/{chunk-IIELH4DL.js → chunk-MMZ7JXPU.js} +60 -223
  46. package/dist/chunk-MMZ7JXPU.js.map +1 -0
  47. package/dist/{chunk-NOAYCWCX 5.js → chunk-NECFR5MM.js} +394 -312
  48. package/dist/chunk-NECFR5MM.js.map +1 -0
  49. package/dist/{chunk-BC4IJKSL.js → chunk-SFZUDBL5.js} +40 -4
  50. package/dist/chunk-SFZUDBL5.js.map +1 -0
  51. package/dist/{chunk-XNXXZ43G.js → chunk-XWQCNGTQ.js} +748 -364
  52. package/dist/chunk-XWQCNGTQ.js.map +1 -0
  53. package/dist/components.d.ts +6 -6
  54. package/dist/components.js +15 -12
  55. package/dist/components.js.map +1 -1
  56. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  57. package/dist/hooks.d.ts +59 -126
  58. package/dist/hooks.js +19 -28
  59. package/dist/hooks.js.map +1 -1
  60. package/dist/index.d.ts +63 -16
  61. package/dist/index.js +23 -24
  62. package/dist/index.js.map +1 -1
  63. package/dist/providers.d.ts +21 -3
  64. package/dist/providers.js +2 -2
  65. package/dist/rbac/index.d.ts +146 -115
  66. package/dist/rbac/index.js +8 -11
  67. package/dist/theming/runtime.d.ts +1 -13
  68. package/dist/theming/runtime.js +1 -1
  69. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  70. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  71. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  72. package/dist/types.d.ts +2 -2
  73. package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-1oMokgLF.d.ts} +34 -4
  74. package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
  75. package/dist/utils.d.ts +4 -5
  76. package/dist/utils.js +15 -15
  77. package/dist/utils.js.map +1 -1
  78. package/docs/api/README.md +7 -1
  79. package/docs/api/classes/ColumnFactory.md +8 -8
  80. package/docs/api/classes/InvalidScopeError.md +4 -4
  81. package/docs/api/classes/Logger.md +1 -1
  82. package/docs/api/classes/MissingUserContextError.md +4 -4
  83. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  84. package/docs/api/classes/PermissionDeniedError.md +4 -4
  85. package/docs/api/classes/RBACAuditManager.md +1 -1
  86. package/docs/api/classes/RBACCache.md +1 -1
  87. package/docs/api/classes/RBACEngine.md +1 -1
  88. package/docs/api/classes/RBACError.md +4 -4
  89. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  90. package/docs/api/classes/SecureSupabaseClient.md +18 -15
  91. package/docs/api/classes/StorageUtils.md +1 -1
  92. package/docs/api/enums/FileCategory.md +1 -1
  93. package/docs/api/enums/LogLevel.md +1 -1
  94. package/docs/api/enums/RBACErrorCode.md +1 -1
  95. package/docs/api/enums/RPCFunction.md +1 -1
  96. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  97. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  98. package/docs/api/interfaces/AggregateConfig.md +4 -4
  99. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  100. package/docs/api/interfaces/AvatarProps.md +1 -1
  101. package/docs/api/interfaces/BadgeProps.md +9 -2
  102. package/docs/api/interfaces/ButtonProps.md +7 -4
  103. package/docs/api/interfaces/CalendarProps.md +8 -5
  104. package/docs/api/interfaces/CardProps.md +8 -5
  105. package/docs/api/interfaces/ColorPalette.md +1 -1
  106. package/docs/api/interfaces/ColorShade.md +1 -1
  107. package/docs/api/interfaces/ComplianceResult.md +1 -1
  108. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  109. package/docs/api/interfaces/DataRecord.md +1 -1
  110. package/docs/api/interfaces/DataTableAction.md +24 -21
  111. package/docs/api/interfaces/DataTableColumn.md +31 -31
  112. package/docs/api/interfaces/DataTableProps.md +1 -1
  113. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  114. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  115. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  116. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  117. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  118. package/docs/api/interfaces/ErrorBoundaryProps.md +147 -0
  119. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +36 -0
  120. package/docs/api/interfaces/ErrorBoundaryState.md +75 -0
  121. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  122. package/docs/api/interfaces/ExportColumn.md +1 -1
  123. package/docs/api/interfaces/ExportOptions.md +8 -8
  124. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  125. package/docs/api/interfaces/FileMetadata.md +1 -1
  126. package/docs/api/interfaces/FileReference.md +1 -1
  127. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  128. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  129. package/docs/api/interfaces/FileUploadProps.md +26 -23
  130. package/docs/api/interfaces/FooterProps.md +10 -8
  131. package/docs/api/interfaces/FormFieldProps.md +10 -10
  132. package/docs/api/interfaces/FormProps.md +1 -1
  133. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  134. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  135. package/docs/api/interfaces/InputProps.md +7 -4
  136. package/docs/api/interfaces/LabelProps.md +1 -1
  137. package/docs/api/interfaces/LoggerConfig.md +1 -1
  138. package/docs/api/interfaces/LoginFormProps.md +14 -11
  139. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  140. package/docs/api/interfaces/NavigationContextType.md +1 -1
  141. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  142. package/docs/api/interfaces/NavigationItem.md +11 -11
  143. package/docs/api/interfaces/NavigationMenuProps.md +15 -15
  144. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  145. package/docs/api/interfaces/Organisation.md +1 -1
  146. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  147. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  148. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  149. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  150. package/docs/api/interfaces/PaceAppLayoutProps.md +30 -27
  151. package/docs/api/interfaces/PaceLoginPageProps.md +6 -4
  152. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  153. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  154. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  155. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  156. package/docs/api/interfaces/PaletteData.md +1 -1
  157. package/docs/api/interfaces/ParsedAddress.md +1 -1
  158. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  159. package/docs/api/interfaces/ProgressProps.md +1 -1
  160. package/docs/api/interfaces/ProtectedRouteProps.md +7 -26
  161. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  162. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  163. package/docs/api/interfaces/PublicPageLayoutProps.md +7 -20
  164. package/docs/api/interfaces/QuickFix.md +1 -1
  165. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  166. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  167. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  168. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  169. package/docs/api/interfaces/RBACConfig.md +1 -1
  170. package/docs/api/interfaces/RBACContext.md +1 -1
  171. package/docs/api/interfaces/RBACLogger.md +1 -1
  172. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  173. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  174. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  175. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  176. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  177. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  178. package/docs/api/interfaces/RBACResult.md +1 -1
  179. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  180. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  181. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  182. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  183. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  184. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  185. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  186. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  187. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  188. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  189. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  190. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  191. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  192. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  193. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  194. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  195. package/docs/api/interfaces/RouteConfig.md +1 -1
  196. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  197. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  198. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  199. package/docs/api/interfaces/SessionRestorationLoaderProps.md +3 -3
  200. package/docs/api/interfaces/SetupIssue.md +1 -1
  201. package/docs/api/interfaces/StorageConfig.md +1 -1
  202. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  203. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  204. package/docs/api/interfaces/StorageListOptions.md +1 -1
  205. package/docs/api/interfaces/StorageListResult.md +1 -1
  206. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  207. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  208. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  209. package/docs/api/interfaces/StyleImport.md +1 -1
  210. package/docs/api/interfaces/SwitchProps.md +1 -1
  211. package/docs/api/interfaces/TabsContentProps.md +1 -1
  212. package/docs/api/interfaces/TabsListProps.md +1 -1
  213. package/docs/api/interfaces/TabsProps.md +1 -1
  214. package/docs/api/interfaces/TabsTriggerProps.md +3 -3
  215. package/docs/api/interfaces/TextareaProps.md +1 -1
  216. package/docs/api/interfaces/ToastActionElement.md +4 -1
  217. package/docs/api/interfaces/ToastProps.md +1 -1
  218. package/docs/api/interfaces/UnifiedAuthContextType.md +58 -55
  219. package/docs/api/interfaces/UnifiedAuthProviderProps.md +15 -13
  220. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  221. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  222. package/docs/api/interfaces/UseInactivityTrackerOptions.md +11 -9
  223. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  224. package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
  225. package/docs/api/interfaces/UsePublicEventLogoReturn.md +9 -6
  226. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  227. package/docs/api/interfaces/UsePublicEventReturn.md +8 -5
  228. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  229. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +12 -9
  230. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +10 -7
  231. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  232. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  233. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  234. package/docs/api/interfaces/UserEventAccess.md +14 -11
  235. package/docs/api/interfaces/UserMenuProps.md +8 -6
  236. package/docs/api/interfaces/UserProfile.md +1 -1
  237. package/docs/api/modules.md +575 -634
  238. package/docs/architecture/database-schema-requirements.md +161 -0
  239. package/docs/core-concepts/rbac-system.md +3 -3
  240. package/docs/documentation-index.md +2 -4
  241. package/docs/getting-started/cursor-rules.md +263 -0
  242. package/docs/getting-started/installation-guide.md +6 -1
  243. package/docs/getting-started/quick-start.md +6 -1
  244. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  245. package/docs/migration/MIGRATION_GUIDE.md +6 -28
  246. package/docs/migration/README.md +52 -6
  247. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  248. package/docs/migration/V0.6.0_REACT_19_MIGRATION.md +227 -0
  249. package/docs/migration/database-changes-december-2025.md +3 -3
  250. package/docs/rbac/event-based-apps.md +1 -1
  251. package/docs/rbac/getting-started.md +1 -1
  252. package/docs/rbac/quick-start.md +1 -1
  253. package/docs/standards/README.md +40 -0
  254. package/docs/troubleshooting/migration.md +4 -4
  255. package/examples/PublicPages/PublicEventPage.tsx +1 -1
  256. package/package.json +12 -6
  257. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  258. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  259. package/scripts/audit/core/checks/bundle.cjs +142 -0
  260. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +737 -691
  261. package/scripts/audit/core/checks/config.cjs +54 -0
  262. package/scripts/audit/core/checks/coverage.cjs +84 -0
  263. package/scripts/audit/core/checks/dependencies.cjs +454 -0
  264. package/scripts/audit/core/checks/documentation.cjs +203 -0
  265. package/scripts/audit/core/checks/environment.cjs +128 -0
  266. package/scripts/audit/core/checks/error-handling.cjs +299 -0
  267. package/scripts/audit/core/checks/forms.cjs +172 -0
  268. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  269. package/scripts/audit/core/checks/hooks.cjs +334 -0
  270. package/scripts/audit/core/checks/imports.cjs +244 -0
  271. package/scripts/audit/core/checks/performance.cjs +325 -0
  272. package/scripts/audit/core/checks/routes.cjs +117 -0
  273. package/scripts/audit/core/checks/state.cjs +130 -0
  274. package/scripts/audit/core/checks/structure.cjs +65 -0
  275. package/scripts/audit/core/checks/style.cjs +584 -0
  276. package/scripts/audit/core/checks/testing.cjs +122 -0
  277. package/scripts/audit/core/checks/typescript.cjs +61 -0
  278. package/scripts/audit/core/scanner.cjs +199 -0
  279. package/scripts/audit/core/utils.cjs +137 -0
  280. package/scripts/audit/index.cjs +223 -0
  281. package/scripts/audit/reporters/console.cjs +151 -0
  282. package/scripts/audit/reporters/json.cjs +54 -0
  283. package/scripts/audit/reporters/markdown.cjs +124 -0
  284. package/scripts/audit-consuming-app.cjs +86 -0
  285. package/scripts/build-docs/build-decision.js +240 -0
  286. package/scripts/build-docs/cache-utils.js +105 -0
  287. package/scripts/build-docs/content-normalization.js +150 -0
  288. package/scripts/build-docs/file-utils.js +105 -0
  289. package/scripts/build-docs/git-utils.js +86 -0
  290. package/scripts/build-docs/hash-utils.js +116 -0
  291. package/scripts/build-docs/typedoc-runner.js +220 -0
  292. package/scripts/build-docs-incremental.js +77 -913
  293. package/scripts/install-cursor-rules.cjs +236 -0
  294. package/scripts/utils/command-runner.js +16 -11
  295. package/scripts/validate-formats.js +61 -56
  296. package/scripts/validate-master.js +74 -69
  297. package/scripts/validate-pre-publish.js +70 -65
  298. package/src/__tests__/helpers/test-providers.tsx +1 -1
  299. package/src/__tests__/helpers/test-utils.tsx +1 -1
  300. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  301. package/src/components/Alert/Alert.test.tsx +12 -18
  302. package/src/components/Alert/Alert.tsx +5 -7
  303. package/src/components/Avatar/Avatar.test.tsx +4 -4
  304. package/src/components/Badge/Badge.tsx +16 -4
  305. package/src/components/Button/Button.tsx +27 -4
  306. package/src/components/Calendar/Calendar.tsx +9 -3
  307. package/src/components/Card/Card.tsx +4 -0
  308. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  309. package/src/components/Checkbox/Checkbox.tsx +2 -2
  310. package/src/components/DataTable/DataTable.test.tsx +57 -93
  311. package/src/components/DataTable/DataTable.tsx +40 -6
  312. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  313. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +29 -7
  314. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
  315. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  316. package/src/components/DataTable/components/AccessDeniedPage.tsx +17 -26
  317. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  318. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  319. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  320. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  321. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  322. package/src/components/DataTable/components/DataTableCore.tsx +200 -561
  323. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  324. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  325. package/src/components/DataTable/components/DataTableModals.tsx +9 -1
  326. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  327. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  328. package/src/components/DataTable/components/EditFields.tsx +307 -0
  329. package/src/components/DataTable/components/EditableRow.tsx +9 -1
  330. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  331. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  332. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  333. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  334. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  335. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  336. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  337. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  338. package/src/components/DataTable/components/UnifiedTableBody.tsx +62 -852
  339. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  340. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  341. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
  342. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
  343. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
  344. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
  345. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
  346. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
  347. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
  348. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  349. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  350. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  351. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  352. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  353. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  354. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  355. package/src/components/DataTable/hooks/useColumnReordering.ts +14 -2
  356. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  357. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  358. package/src/components/DataTable/hooks/useDataTablePermissions.ts +124 -32
  359. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  360. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  361. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
  362. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  363. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  364. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  365. package/src/components/DataTable/styles.ts +6 -6
  366. package/src/components/DataTable/types.ts +6 -10
  367. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  368. package/src/components/DataTable/utils/debugTools.ts +18 -113
  369. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  370. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  371. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  372. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  373. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  374. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
  375. package/src/components/Dialog/Dialog.tsx +8 -7
  376. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  377. package/src/components/ErrorBoundary/ErrorBoundary.tsx +46 -6
  378. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  379. package/src/components/ErrorBoundary/index.ts +27 -2
  380. package/src/components/EventSelector/EventSelector.tsx +4 -1
  381. package/src/components/FileDisplay/FileDisplay.test.tsx +2 -2
  382. package/src/components/FileDisplay/FileDisplay.tsx +32 -18
  383. package/src/components/FileUpload/FileUpload.tsx +22 -2
  384. package/src/components/Footer/Footer.test.tsx +16 -16
  385. package/src/components/Footer/Footer.tsx +15 -12
  386. package/src/components/Form/Form.test.tsx +36 -15
  387. package/src/components/Form/Form.tsx +31 -26
  388. package/src/components/Header/Header.tsx +22 -11
  389. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
  390. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
  391. package/src/components/Input/Input.test.tsx +2 -2
  392. package/src/components/Input/Input.tsx +36 -34
  393. package/src/components/Label/Label.tsx +1 -1
  394. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  395. package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
  396. package/src/components/LoginForm/LoginForm.test.tsx +42 -42
  397. package/src/components/LoginForm/LoginForm.tsx +12 -8
  398. package/src/components/NavigationMenu/NavigationMenu.tsx +15 -514
  399. package/src/components/NavigationMenu/types.ts +56 -0
  400. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  401. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -0
  402. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
  403. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +54 -52
  404. package/src/components/PaceAppLayout/PaceAppLayout.tsx +33 -12
  405. package/src/components/PaceAppLayout/README.md +1 -1
  406. package/src/components/PaceAppLayout/test-setup.tsx +1 -2
  407. package/src/components/PaceLoginPage/PaceLoginPage.tsx +4 -1
  408. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
  409. package/src/components/PasswordChange/PasswordChangeForm.tsx +10 -1
  410. package/src/components/Progress/Progress.tsx +1 -1
  411. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  412. package/src/components/PublicLayout/PublicPageLayout.tsx +3 -6
  413. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  414. package/src/components/Select/Select.tsx +95 -438
  415. package/src/components/Select/context.ts +23 -0
  416. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  417. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  418. package/src/components/Select/hooks/useSelectState.ts +104 -0
  419. package/src/components/Select/index.ts +9 -1
  420. package/src/components/Select/types.ts +123 -0
  421. package/src/components/Select/utils/text.ts +26 -0
  422. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +5 -6
  423. package/src/components/Switch/Switch.tsx +4 -4
  424. package/src/components/Table/Table.tsx +1 -1
  425. package/src/components/Tabs/Tabs.tsx +1 -1
  426. package/src/components/Textarea/Textarea.tsx +27 -29
  427. package/src/components/Toast/Toast.tsx +5 -1
  428. package/src/components/Tooltip/Tooltip.tsx +3 -3
  429. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  430. package/src/components/UserMenu/UserMenu.tsx +22 -19
  431. package/src/components/index.ts +2 -2
  432. package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
  433. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  434. package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
  435. package/src/hooks/index.ts +1 -2
  436. package/src/hooks/public/usePublicEvent.ts +5 -1
  437. package/src/hooks/public/usePublicEventLogo.ts +5 -1
  438. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  439. package/src/hooks/public/usePublicRouteParams.ts +5 -1
  440. package/src/hooks/services/useAuth.ts +32 -0
  441. package/src/hooks/services/useCurrentEvent.ts +6 -0
  442. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  443. package/src/hooks/useDataTableState.ts +8 -18
  444. package/src/hooks/useDebounce.ts +9 -0
  445. package/src/hooks/useEventTheme.ts +6 -0
  446. package/src/hooks/useFileDisplay.ts +4 -0
  447. package/src/hooks/useFileReference.ts +25 -7
  448. package/src/hooks/useFileUrl.ts +11 -1
  449. package/src/hooks/useFocusManagement.ts +16 -2
  450. package/src/hooks/useFocusTrap.ts +7 -4
  451. package/src/hooks/useFormDialog.ts +8 -7
  452. package/src/hooks/useInactivityTracker.ts +4 -1
  453. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  454. package/src/hooks/useOrganisationPermissions.ts +4 -0
  455. package/src/hooks/useOrganisationSecurity.ts +4 -0
  456. package/src/hooks/usePerformanceMonitor.ts +4 -0
  457. package/src/hooks/usePermissionCache.ts +8 -1
  458. package/src/hooks/useQueryCache.ts +12 -1
  459. package/src/hooks/useSessionRestoration.ts +4 -0
  460. package/src/hooks/useStorage.ts +4 -0
  461. package/src/hooks/useToast.ts +3 -3
  462. package/src/index.ts +2 -1
  463. package/src/providers/__tests__/OrganisationProvider.test.tsx +115 -49
  464. package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
  465. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
  466. package/src/providers/services/AuthServiceProvider.tsx +18 -0
  467. package/src/providers/services/EventServiceProvider.tsx +18 -0
  468. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  469. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  470. package/src/providers/services/UnifiedAuthProvider.tsx +58 -22
  471. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +33 -7
  472. package/src/rbac/README.md +1 -1
  473. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +26 -26
  474. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  475. package/src/rbac/adapters.tsx +14 -5
  476. package/src/rbac/api.ts +100 -67
  477. package/src/rbac/components/EnhancedNavigationMenu.tsx +1 -1
  478. package/src/rbac/components/NavigationGuard.tsx +1 -1
  479. package/src/rbac/components/NavigationProvider.tsx +5 -2
  480. package/src/rbac/components/PagePermissionGuard.tsx +158 -18
  481. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  482. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  483. package/src/rbac/components/RoleBasedRouter.tsx +6 -2
  484. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  485. package/src/rbac/components/SecureDataProvider.tsx +21 -6
  486. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  487. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  488. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  489. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  490. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  491. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  492. package/src/rbac/engine.ts +38 -14
  493. package/src/rbac/hooks/permissions/index.ts +7 -0
  494. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  495. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  496. package/src/rbac/hooks/permissions/useCan.ts +347 -0
  497. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  498. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  499. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  500. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  501. package/src/rbac/hooks/useCan.test.ts +71 -64
  502. package/src/rbac/hooks/usePermissions.ts +14 -995
  503. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  504. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  505. package/src/rbac/hooks/useSecureSupabase.ts +33 -13
  506. package/src/rbac/permissions.ts +0 -30
  507. package/src/rbac/secureClient.ts +212 -61
  508. package/src/rbac/types.ts +8 -0
  509. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  510. package/src/theming/parseEventColours.ts +5 -19
  511. package/src/types/vitest-globals.d.ts +51 -26
  512. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  513. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  514. package/src/utils/__tests__/index.unit.test.ts +2 -2
  515. package/src/utils/audit/audit.ts +0 -3
  516. package/src/utils/core/cn.ts +1 -1
  517. package/src/utils/file-reference/index.ts +53 -1
  518. package/src/utils/formatting/formatting.ts +8 -18
  519. package/src/utils/index.ts +0 -1
  520. package/src/utils/security/secureDataAccess.test.ts +31 -20
  521. package/src/utils/security/secureDataAccess.ts +4 -3
  522. package/dist/chunk-6C4YBBJM.js +0 -628
  523. package/dist/chunk-6C4YBBJM.js.map +0 -1
  524. package/dist/chunk-7D4SUZUM.js 2.map +0 -1
  525. package/dist/chunk-7EQTDTTJ.js 2.map +0 -1
  526. package/dist/chunk-7EQTDTTJ.js.map +0 -1
  527. package/dist/chunk-7FLMSG37.js 2.map +0 -1
  528. package/dist/chunk-7FLMSG37.js.map +0 -1
  529. package/dist/chunk-BC4IJKSL.js.map +0 -1
  530. package/dist/chunk-E3SPN4VZ.js +0 -12917
  531. package/dist/chunk-E3SPN4VZ.js.map +0 -1
  532. package/dist/chunk-E66EQZE6 5.js +0 -37
  533. package/dist/chunk-E66EQZE6.js 2.map +0 -1
  534. package/dist/chunk-HWIIPPNI.js.map +0 -1
  535. package/dist/chunk-I7PSE6JW 5.js +0 -191
  536. package/dist/chunk-I7PSE6JW.js 2.map +0 -1
  537. package/dist/chunk-I7PSE6JW.js.map +0 -1
  538. package/dist/chunk-IIELH4DL.js.map +0 -1
  539. package/dist/chunk-KNC55RTG.js 5.map +0 -1
  540. package/dist/chunk-KNC55RTG.js.map +0 -1
  541. package/dist/chunk-KQCRWDSA.js 5.map +0 -1
  542. package/dist/chunk-LFNCN2SP.js +0 -412
  543. package/dist/chunk-LFNCN2SP.js 2.map +0 -1
  544. package/dist/chunk-LFNCN2SP.js.map +0 -1
  545. package/dist/chunk-LMC26NLJ 2.js +0 -84
  546. package/dist/chunk-NOAYCWCX.js +0 -4993
  547. package/dist/chunk-NOAYCWCX.js.map +0 -1
  548. package/dist/chunk-QWWZ5CAQ.js 3.map +0 -1
  549. package/dist/chunk-QWWZ5CAQ.js.map +0 -1
  550. package/dist/chunk-QXHPKYJV 3.js +0 -113
  551. package/dist/chunk-R77UEZ4E.js +0 -68
  552. package/dist/chunk-R77UEZ4E.js.map +0 -1
  553. package/dist/chunk-SQGMNID3.js.map +0 -1
  554. package/dist/chunk-VBXEHIUJ.js 6.map +0 -1
  555. package/dist/chunk-XNXXZ43G.js.map +0 -1
  556. package/dist/chunk-ZSAAAMVR 6.js +0 -25
  557. package/dist/components.js 5.map +0 -1
  558. package/dist/styles/index 2.js +0 -12
  559. package/dist/styles/index.js 5.map +0 -1
  560. package/dist/theming/runtime 5.js +0 -19
  561. package/dist/theming/runtime.js 5.map +0 -1
  562. package/docs/api/classes/ErrorBoundary.md +0 -144
  563. package/docs/migration/quick-migration-guide.md +0 -356
  564. package/docs/migration/service-architecture.md +0 -281
  565. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  566. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  567. package/src/hooks/useSecureDataAccess.ts +0 -666
  568. /package/dist/{DataTable-5FU7IESH.js.map → DataTable-TPTKCX4D.js.map} +0 -0
  569. /package/dist/{UnifiedAuthProvider-RGJTDE2C.js.map → UnifiedAuthProvider-CH6Z342H.js.map} +0 -0
  570. /package/dist/{api-N774RPUA.js.map → api-MVVQZLJI.js.map} +0 -0
  571. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  572. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  573. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  574. /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
  575. /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
  576. /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
  577. /package/examples/{rbac → RBAC}/index.ts +0 -0
@@ -0,0 +1,200 @@
1
+ ---
2
+ description: Define standard folder structure and file organization for consuming apps
3
+ globs: ["**/*.{ts,tsx,js,jsx,md}", "src/**"]
4
+ alwaysApply: false
5
+ paceCoreVersion: "0.6.x"
6
+ rulesVersion: "2025-01-28"
7
+ ---
8
+ # Project Structure Standard
9
+
10
+ This guide defines the standard folder structure and file organization for consuming apps in the PACE suite.
11
+
12
+ ## MUST: Follow Standard Directory Structure
13
+
14
+ **Consuming apps MUST follow this structure:**
15
+
16
+ ```
17
+ your-app/
18
+ ├── .cursor/
19
+ │ └── rules/ # Cursor rules (pace-core rules + local rules)
20
+ ├── src/
21
+ │ ├── components/ # App-specific components
22
+ │ ├── hooks/ # App-specific hooks
23
+ │ ├── services/ # App-specific services
24
+ │ ├── pages/ # Page components
25
+ │ ├── types/ # TypeScript type definitions
26
+ │ ├── utils/ # App-specific utilities
27
+ │ ├── App.tsx # Main app component
28
+ │ └── main.tsx # Entry point
29
+ ├── supabase/
30
+ │ ├── migrations/ # Database migrations
31
+ │ └── functions/ # Edge functions (if used)
32
+ ├── public/ # Static assets
33
+ ├── tests/ # Integration/E2E tests (optional)
34
+ ├── audit/ # Audit reports (generated)
35
+ ├── package.json
36
+ ├── tsconfig.json
37
+ ├── vite.config.ts
38
+ └── vitest.config.ts
39
+ ```
40
+
41
+ ## MUST: Organize Components by Feature
42
+
43
+ **Components SHOULD be organized by feature/domain, not by type:**
44
+
45
+ ```
46
+ src/
47
+ ├── components/
48
+ │ ├── events/ # Event-related components
49
+ │ │ ├── EventCard.tsx
50
+ │ │ └── EventList.tsx
51
+ │ ├── users/ # User-related components
52
+ │ │ ├── UserProfile.tsx
53
+ │ │ └── UserList.tsx
54
+ │ └── shared/ # Shared app-specific components
55
+ │ ├── Layout.tsx
56
+ │ └── Navigation.tsx
57
+ ```
58
+
59
+ **MUST NOT:**
60
+ - Organize by component type (`buttons/`, `inputs/`, etc.) - use pace-core instead
61
+ - Create duplicate components that pace-core provides
62
+
63
+ ## MUST: Colocate Tests
64
+
65
+ **Tests MUST be colocated with source files:**
66
+
67
+ ```
68
+ src/
69
+ ├── components/
70
+ │ └── EventCard/
71
+ │ ├── EventCard.tsx
72
+ │ └── EventCard.test.tsx
73
+ ├── hooks/
74
+ │ ├── useEventData.ts
75
+ │ └── useEventData.test.ts
76
+ └── utils/
77
+ ├── formatEvent.ts
78
+ └── formatEvent.test.ts
79
+ ```
80
+
81
+ ## MUST: Follow Naming Conventions
82
+
83
+ ### Files
84
+ - Components: `PascalCase.tsx` (e.g., `EventCard.tsx`)
85
+ - Hooks: `camelCase.ts` with `use` prefix (e.g., `useEventData.ts`)
86
+ - Utilities: `camelCase.ts` (e.g., `formatEvent.ts`)
87
+ - Types: `camelCase.ts` or `types.ts` (e.g., `eventTypes.ts`)
88
+ - Tests: `*.test.ts` or `*.test.tsx`
89
+ - Config: `kebab-case.config.js` (e.g., `vite.config.ts`)
90
+
91
+ ### Directories
92
+ - Use `kebab-case` for directories (e.g., `event-management/`)
93
+ - Match feature/domain names
94
+
95
+ ## MUST: Place Migrations Correctly
96
+
97
+ **Database migrations MUST be in `supabase/migrations/`:**
98
+ - Format: `YYYYMMDDHHMMSS_description.sql`
99
+ - Example: `20250115143022_add_user_preferences.sql`
100
+
101
+ ## SHOULD: Organize by Domain
102
+
103
+ **For larger apps, SHOULD organize by domain/feature:**
104
+
105
+ ```
106
+ src/
107
+ ├── domains/
108
+ │ ├── events/
109
+ │ │ ├── components/
110
+ │ │ ├── hooks/
111
+ │ │ ├── services/
112
+ │ │ └── types.ts
113
+ │ └── users/
114
+ │ ├── components/
115
+ │ ├── hooks/
116
+ │ ├── services/
117
+ │ └── types.ts
118
+ ├── shared/ # Shared across domains
119
+ │ ├── components/
120
+ │ ├── hooks/
121
+ │ └── utils/
122
+ └── App.tsx
123
+ ```
124
+
125
+ ## MUST: Keep Root Directory Clean
126
+
127
+ **Root directory SHOULD only contain:**
128
+ - Configuration files (`package.json`, `tsconfig.json`, etc.)
129
+ - Documentation (`README.md`, `CHANGELOG.md`)
130
+ - Build outputs (`.gitignore` them)
131
+ - `.cursor/` directory
132
+
133
+ **MUST NOT:**
134
+ - Place source files in root
135
+ - Place test files in root
136
+ - Place component files in root
137
+
138
+ ## MUST: Use Consistent Import Paths
139
+
140
+ **MUST use consistent import patterns:**
141
+
142
+ ```tsx
143
+ // ✅ CORRECT - Absolute imports from src
144
+ import { EventCard } from '@/components/events/EventCard';
145
+ import { useEventData } from '@/hooks/useEventData';
146
+ import { formatEvent } from '@/utils/formatEvent';
147
+
148
+ // ✅ CORRECT - pace-core imports
149
+ import { Button, Card } from '@jmruthers/pace-core';
150
+ import { useUnifiedAuth } from '@jmruthers/pace-core';
151
+
152
+ // ❌ WRONG - Relative imports for distant files
153
+ import { EventCard } from '../../../components/events/EventCard';
154
+ ```
155
+
156
+ **Configure path aliases in `tsconfig.json`:**
157
+ ```json
158
+ {
159
+ "compilerOptions": {
160
+ "paths": {
161
+ "@/*": ["./src/*"]
162
+ }
163
+ }
164
+ }
165
+ ```
166
+
167
+ ## MUST: Separate App Code from pace-core
168
+
169
+ **MUST NOT:**
170
+ - Modify pace-core code directly
171
+ - Create components that duplicate pace-core functionality
172
+ - Import from pace-core source (use published package)
173
+
174
+ **MUST:**
175
+ - Use pace-core as a dependency
176
+ - Import from `@jmruthers/pace-core`
177
+ - Create app-specific components only when pace-core doesn't provide them
178
+
179
+ ## SHOULD: Document Structure Decisions
180
+
181
+ **For non-standard structures, SHOULD document why:**
182
+ - Add `STRUCTURE.md` or section in `README.md`
183
+ - Explain deviations from standard
184
+ - Justify custom organization
185
+
186
+ ## File Organization Checklist
187
+
188
+ Before committing, verify:
189
+ - [ ] Components organized by feature, not type
190
+ - [ ] Tests colocated with source files
191
+ - [ ] Naming conventions followed
192
+ - [ ] Migrations in `supabase/migrations/`
193
+ - [ ] Root directory clean
194
+ - [ ] Import paths consistent
195
+ - [ ] No pace-core code modifications
196
+ - [ ] Structure documented if non-standard
197
+
198
+ ## Reference
199
+
200
+ See `project-structure.mdc` in pace-core for detailed structure patterns.
@@ -0,0 +1,222 @@
1
+ ---
2
+ description: Enforce SOLID architecture principles in consuming apps
3
+ globs: ["src/**/*.{ts,tsx}"]
4
+ alwaysApply: false
5
+ paceCoreVersion: "0.6.x"
6
+ rulesVersion: "2025-01-28"
7
+ ---
8
+ # SOLID Principles Guide
9
+
10
+ This guide enforces SOLID architecture principles to ensure maintainable, extensible, and testable code.
11
+
12
+ ## Single Responsibility Principle (SRP)
13
+
14
+ **A class or function SHOULD have only one reason to change.**
15
+
16
+ ### MUST: Single Responsibility
17
+
18
+ **Each function/component SHOULD do one thing:**
19
+
20
+ ```tsx
21
+ // ❌ WRONG: Multiple responsibilities (fetching, formatting, rendering in one component)
22
+ function UserProfile({ userId }) {
23
+ const [user, setUser] = useState(null);
24
+ const [events, setEvents] = useState([]);
25
+ useEffect(() => { fetchUser(userId).then(setUser); fetchEvents(userId).then(setEvents); }, [userId]);
26
+ return <div>...</div>;
27
+ }
28
+
29
+ // ✅ CORRECT: Separated responsibilities (hooks for data, components for UI)
30
+ function UserProfile({ userId }) {
31
+ const user = useUser(userId);
32
+ const events = useUserEvents(userId);
33
+ return <div><UserInfo user={user} /><UserEvents events={events} /></div>;
34
+ }
35
+ ```
36
+
37
+ ### MUST: Extract Complex Logic
38
+
39
+ **Complex logic SHOULD be extracted into hooks, services, or utilities:**
40
+
41
+ ```tsx
42
+ // ❌ WRONG: Business logic in component (filtering, sorting, formatting)
43
+ function EventList() {
44
+ const [events, setEvents] = useState([]);
45
+ const [filtered, setFiltered] = useState([]);
46
+ useEffect(() => { /* complex filtering/sorting logic */ }, [events]);
47
+ return <div>{filtered.map(...)}</div>;
48
+ }
49
+
50
+ // ✅ CORRECT: Logic extracted to hook
51
+ function useFilteredEvents() {
52
+ const events = useEvents();
53
+ return useMemo(() => events.filter(...).sort(...).map(...), [events]);
54
+ }
55
+ function EventList() {
56
+ const filteredEvents = useFilteredEvents();
57
+ return <div>{filteredEvents.map(...)}</div>;
58
+ }
59
+ ```
60
+
61
+ ## Open/Closed Principle (OCP)
62
+
63
+ **Software entities SHOULD be open for extension but closed for modification.**
64
+
65
+ ### SHOULD: Use Composition Over Modification
66
+
67
+ **Extend functionality through composition, not modification:**
68
+
69
+ ```tsx
70
+ // ❌ WRONG: Modifying base component behavior
71
+ function SpecialButton({ onClick, ...props }) {
72
+ const handleClick = (e) => { trackEvent('button-click'); onClick?.(e); };
73
+ return <BaseButton onClick={handleClick} {...props} />; // Modifies base
74
+ }
75
+
76
+ // ✅ CORRECT: Composition with pace-core (extend, don't modify)
77
+ import { Button } from '@jmruthers/pace-core';
78
+ function SpecialButton({ onClick, ...props }) {
79
+ const handleClick = (e) => { trackEvent('button-click'); onClick?.(e); };
80
+ return <Button onClick={handleClick} {...props} />;
81
+ }
82
+ ```
83
+
84
+ ### SHOULD: Use Configuration Over Code Changes
85
+
86
+ **Extend behavior through configuration:**
87
+
88
+ ```tsx
89
+ // ✅ CORRECT: Extend through configuration, not code changes
90
+ interface DataTableConfig { columns: Column[]; features: FeatureConfig; rbac: RBACConfig; }
91
+ function MyDataTable({ config }: { config: DataTableConfig }) {
92
+ return <DataTable {...config} />;
93
+ }
94
+ ```
95
+
96
+ ## Liskov Substitution Principle (LSP)
97
+
98
+ **Subtypes MUST be substitutable for their base types.**
99
+
100
+ ### MUST: Maintain Interface Contracts
101
+
102
+ **Derived components/hooks MUST maintain the same interface:**
103
+
104
+ ```tsx
105
+ // ✅ CORRECT: Derived hooks maintain same interface (substitutable)
106
+ interface BaseHook { data: Data | null; isLoading: boolean; error: Error | null; }
107
+ function useBaseData(): BaseHook { ... }
108
+ function useExtendedData(): BaseHook {
109
+ const base = useBaseData();
110
+ return { ...base }; // Maintains interface, extends behavior
111
+ }
112
+ ```
113
+
114
+ ## Interface Segregation Principle (ISP)
115
+
116
+ **Clients SHOULD NOT depend on interfaces they don't use.**
117
+
118
+ ### MUST: Create Focused Interfaces
119
+
120
+ **Interfaces SHOULD be small and focused:**
121
+
122
+ ```tsx
123
+ // ❌ WRONG: Large interface with many responsibilities
124
+ interface UserService {
125
+ getUser(id: string): Promise<User>;
126
+ createUser(data: UserData): Promise<User>;
127
+ updateUser(id: string, data: Partial<User>): Promise<User>;
128
+ deleteUser(id: string): Promise<void>;
129
+ getUserEvents(id: string): Promise<Event[]>;
130
+ getUserOrganisations(id: string): Promise<Organisation[]>;
131
+ }
132
+
133
+ // ✅ CORRECT: Segregated interfaces (focused, specific)
134
+ interface UserReader { getUser(id: string): Promise<User>; getUserEvents(id: string): Promise<Event[]>; }
135
+ interface UserWriter { createUser(data: UserData): Promise<User>; updateUser(id: string, data: Partial<User>): Promise<User>; deleteUser(id: string): Promise<void>; }
136
+ interface UserOrganisationService { getUserOrganisations(id: string): Promise<Organisation[]>; }
137
+ ```
138
+
139
+ ### SHOULD: Use Specific Props
140
+
141
+ **Component props SHOULD be specific, not generic:**
142
+
143
+ ```tsx
144
+ // ❌ WRONG: Generic props object (config: any)
145
+ function UserCard({ user, config }: { user: User; config: any }) { ... }
146
+
147
+ // ✅ CORRECT: Specific, focused props interface
148
+ interface UserCardProps { user: User; showEmail?: boolean; showAvatar?: boolean; onEdit?: (user: User) => void; }
149
+ function UserCard({ user, showEmail, showAvatar, onEdit }: UserCardProps) { ... }
150
+ ```
151
+
152
+ ## Dependency Inversion Principle (DIP)
153
+
154
+ **High-level modules SHOULD NOT depend on low-level modules. Both SHOULD depend on abstractions.**
155
+
156
+ ### MUST: Depend on Abstractions
157
+
158
+ **Depend on interfaces/types, not concrete implementations:**
159
+
160
+ ```tsx
161
+ // ❌ WRONG: Direct dependency on implementation (tight coupling)
162
+ function UserService() {
163
+ const supabase = useSecureSupabase();
164
+ async function getUser(id: string) {
165
+ const { data } = await supabase.from('users').select('*').eq('id', id).single();
166
+ return data;
167
+ }
168
+ return { getUser };
169
+ }
170
+
171
+ // ✅ CORRECT: Abstracted interface (depend on abstraction)
172
+ interface UserRepository { getUser(id: string): Promise<User | null>; }
173
+ function createUserRepository(supabase: SupabaseClient): UserRepository {
174
+ return { async getUser(id: string) { /* implementation */ } };
175
+ }
176
+ function useUserService() {
177
+ const supabase = useSecureSupabase();
178
+ const repository = useMemo(() => createUserRepository(supabase), [supabase]);
179
+ return { getUser: repository.getUser };
180
+ }
181
+ ```
182
+
183
+ ### SHOULD: Use Dependency Injection
184
+
185
+ **Inject dependencies rather than creating them:**
186
+
187
+ ```tsx
188
+ // ❌ WRONG: Hard-coded dependency
189
+ function EventService() { const api = new ApiClient('https://api.example.com'); }
190
+
191
+ // ✅ CORRECT: Injected dependency (dependency injection)
192
+ function EventService(api: ApiClient) { ... }
193
+ // Or with React context: const api = useApiClient(); useMemo(() => new EventService(api), [api]);
194
+ ```
195
+
196
+ ## SOLID Checklist
197
+
198
+ Before committing code, verify:
199
+ - [ ] Each function/component has single responsibility
200
+ - [ ] Complex logic extracted to hooks/services
201
+ - [ ] Extension through composition, not modification
202
+ - [ ] Interfaces are focused and specific
203
+ - [ ] Dependencies are abstracted
204
+ - [ ] No god objects or bloated components
205
+ - [ ] Code is testable and maintainable
206
+
207
+ ## Anti-Patterns to Avoid
208
+
209
+ 1. **God Objects** - Classes/components that do too much
210
+ 2. **Feature Envy** - Functions that use more of another object than their own
211
+ 3. **Data Clumps** - Groups of data that should be objects
212
+ 4. **Long Parameter Lists** - Use objects/interfaces instead
213
+ 5. **Divergent Change** - One class changed for multiple reasons
214
+ 6. **Shotgun Surgery** - One change requires many class modifications
215
+
216
+ ## Reference
217
+
218
+ - Single Responsibility: Each module has one reason to change
219
+ - Open/Closed: Open for extension, closed for modification
220
+ - Liskov Substitution: Subtypes must be substitutable
221
+ - Interface Segregation: Many specific interfaces, not one general
222
+ - Dependency Inversion: Depend on abstractions, not concretions
@@ -0,0 +1,268 @@
1
+ ---
2
+ description: Enforce testing framework consistency and standards for consuming apps
3
+ globs: ["**/*.{test,spec}.{ts,tsx}"]
4
+ alwaysApply: false
5
+ paceCoreVersion: "0.6.x"
6
+ rulesVersion: "2025-01-28"
7
+ ---
8
+ # Testing Standards Guide
9
+
10
+ This guide ensures consistent, high-quality testing across consuming apps in the PACE suite.
11
+
12
+ ## MUST: Meet Coverage Requirements
13
+
14
+ **MUST achieve minimum coverage:**
15
+ - ≥90% coverage for utils & hooks
16
+ - ≥70% coverage for components
17
+
18
+ **Verify coverage:**
19
+ ```bash
20
+ npm run test:coverage
21
+ ```
22
+
23
+ ## MUST: Use React Testing Library
24
+
25
+ **MUST use React Testing Library + userEvent for all component tests.**
26
+
27
+ ```tsx
28
+ // ✅ CORRECT: React Testing Library + userEvent
29
+ import { render, screen } from '@testing-library/react';
30
+ import userEvent from '@testing-library/user-event';
31
+ test('button clicks work', async () => {
32
+ const user = userEvent.setup();
33
+ const handleClick = vi.fn();
34
+ render(<Button onClick={handleClick}>Click me</Button>);
35
+ await user.click(screen.getByRole('button', { name: /click me/i }));
36
+ expect(handleClick).toHaveBeenCalledTimes(1);
37
+ });
38
+
39
+ // ❌ WRONG: Enzyme or other testing libraries
40
+ ```
41
+
42
+ ## MUST: Colocate Tests
43
+
44
+ **Tests MUST be colocated with source files:**
45
+
46
+ ```
47
+ src/
48
+ ├── components/
49
+ │ └── EventCard/
50
+ │ ├── EventCard.tsx
51
+ │ └── EventCard.test.tsx
52
+ ├── hooks/
53
+ │ ├── useEventData.ts
54
+ │ └── useEventData.test.ts
55
+ └── utils/
56
+ ├── formatEvent.ts
57
+ └── formatEvent.test.ts
58
+ ```
59
+
60
+ ## MUST: Use Vitest
61
+
62
+ **MUST use Vitest for all testing:**
63
+
64
+ ```typescript
65
+ // vitest.config.ts
66
+ import { defineConfig } from 'vitest/config';
67
+
68
+ export default defineConfig({
69
+ test: {
70
+ environment: 'jsdom',
71
+ setupFiles: ['./vitest.setup.ts'],
72
+ coverage: {
73
+ provider: 'v8',
74
+ reporter: ['text', 'json', 'html'],
75
+ thresholds: {
76
+ lines: 80,
77
+ functions: 80,
78
+ branches: 80,
79
+ statements: 80,
80
+ },
81
+ },
82
+ },
83
+ });
84
+ ```
85
+
86
+ ## MUST: Test User Behavior, Not Implementation
87
+
88
+ **Tests MUST focus on what users see and do:**
89
+
90
+ ```tsx
91
+ // ❌ WRONG: Testing implementation (component.state.count)
92
+ test('calls setState', () => { const component = render(<Counter />); expect(component.state.count).toBe(0); });
93
+
94
+ // ✅ CORRECT: Testing user behavior (what user sees and does)
95
+ test('displays count and increments on button click', async () => {
96
+ const user = userEvent.setup();
97
+ render(<Counter />);
98
+ expect(screen.getByText('Count: 0')).toBeInTheDocument();
99
+ await user.click(screen.getByRole('button', { name: /increment/i }));
100
+ expect(screen.getByText('Count: 1')).toBeInTheDocument();
101
+ });
102
+ ```
103
+
104
+ ## MUST: Use Accessible Queries
105
+
106
+ **MUST prefer accessible queries (byRole, byLabelText, etc.):**
107
+
108
+ ```tsx
109
+ // ✅ CORRECT: Accessible queries (byRole, byLabelText, byText)
110
+ screen.getByRole('button', { name: /submit/i });
111
+ screen.getByLabelText(/email address/i);
112
+
113
+ // ❌ AVOID: Non-accessible queries (getByTestId, getByClassName - use as last resort)
114
+ ```
115
+
116
+ ## SHOULD: Test Critical Paths
117
+
118
+ **SHOULD test:**
119
+ - User workflows and interactions
120
+ - Error handling and edge cases
121
+ - Form validation
122
+ - Permission checks (RBAC)
123
+ - Data loading states
124
+ - Error states
125
+
126
+ ## SHOULD: Use Descriptive Test Names
127
+
128
+ **Test names SHOULD describe behavior:**
129
+
130
+ ```tsx
131
+ // ❌ WRONG - Vague
132
+ test('button works', () => { ... });
133
+
134
+ // ✅ CORRECT - Descriptive
135
+ test('increments counter when increment button is clicked', () => { ... });
136
+ test('displays error message when API call fails', () => { ... });
137
+ ```
138
+
139
+ ## SHOULD: Group Related Tests
140
+
141
+ **SHOULD use `describe` blocks to group related tests:**
142
+
143
+ ```tsx
144
+ describe('EventCard', () => {
145
+ describe('rendering', () => {
146
+ test('displays event title', () => { ... });
147
+ test('displays event date', () => { ... });
148
+ });
149
+
150
+ describe('interactions', () => {
151
+ test('calls onEdit when edit button clicked', () => { ... });
152
+ test('calls onDelete when delete button clicked', () => { ... });
153
+ });
154
+ });
155
+ ```
156
+
157
+ ## MUST: Avoid Unnecessary Mocks
158
+
159
+ **MUST NOT mock unless necessary:**
160
+
161
+ ```tsx
162
+ // ❌ WRONG: Unnecessary mock (global.fetch = mockFetch)
163
+ // ✅ CORRECT: Use real implementation or MSW
164
+ import { server } from './mocks/server';
165
+ server.use(rest.get('/api/events', (req, res, ctx) => res(ctx.json([{ id: '1', name: 'Event' }]))));
166
+ ```
167
+
168
+ ## MUST: Test Async Code Properly
169
+
170
+ **MUST handle async operations correctly:**
171
+
172
+ ```tsx
173
+ // ✅ CORRECT: Async testing with waitFor
174
+ test('loads and displays events', async () => {
175
+ render(<EventList />);
176
+ expect(screen.getByText(/loading/i)).toBeInTheDocument();
177
+ await waitFor(() => expect(screen.getByText('Event 1')).toBeInTheDocument());
178
+ expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
179
+ });
180
+ ```
181
+
182
+ ## MUST: Clean Up After Tests
183
+
184
+ **MUST clean up resources:**
185
+
186
+ ```tsx
187
+ // ✅ CORRECT: Cleanup after tests
188
+ afterEach(() => { cleanup(); vi.clearAllMocks(); });
189
+ ```
190
+
191
+ ## SHOULD: Use Test Utilities
192
+
193
+ **SHOULD create reusable test utilities:**
194
+
195
+ ```tsx
196
+ // ✅ CORRECT: Reusable test utilities
197
+ export function renderWithProviders(ui: React.ReactElement) {
198
+ return render(<UnifiedAuthProvider supabaseClient={mockSupabase} appName="Test App">{ui}</UnifiedAuthProvider>);
199
+ }
200
+ // Usage: renderWithProviders(<MyComponent />);
201
+ ```
202
+
203
+ ## MUST: Include Timeout Parameters
204
+
205
+ **Tests MUST include timeout parameters to prevent hanging:**
206
+
207
+ ```tsx
208
+ // ✅ CORRECT: Include timeout parameters to prevent hanging
209
+ test('async operation completes', async () => {
210
+ await waitFor(() => expect(screen.getByText('Loaded')).toBeInTheDocument(), { timeout: 5000 });
211
+ }, { timeout: 10000 });
212
+ ```
213
+
214
+ ## Testing Checklist
215
+
216
+ Before committing tests, verify:
217
+ - [ ] Coverage meets requirements (≥90% utils, ≥70% components)
218
+ - [ ] Using React Testing Library + userEvent
219
+ - [ ] Tests are colocated with source files
220
+ - [ ] Testing user behavior, not implementation
221
+ - [ ] Using accessible queries (byRole, byLabelText)
222
+ - [ ] Test names are descriptive
223
+ - [ ] Related tests grouped with describe
224
+ - [ ] No unnecessary mocks
225
+ - [ ] Async code tested properly
226
+ - [ ] Cleanup after tests
227
+ - [ ] Timeout parameters included
228
+
229
+ ## Test Structure Template
230
+
231
+ ```tsx
232
+ import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';
233
+ import { render, screen, waitFor } from '@testing-library/react';
234
+ import userEvent from '@testing-library/user-event';
235
+ import { ComponentName } from './ComponentName';
236
+
237
+ describe('ComponentName', () => {
238
+ beforeEach(() => {
239
+ // Setup
240
+ });
241
+
242
+ afterEach(() => {
243
+ // Cleanup
244
+ vi.clearAllMocks();
245
+ });
246
+
247
+ describe('rendering', () => {
248
+ test('renders correctly', () => {
249
+ render(<ComponentName />);
250
+ // Assertions
251
+ });
252
+ });
253
+
254
+ describe('interactions', () => {
255
+ test('handles user interaction', async () => {
256
+ const user = userEvent.setup();
257
+ render(<ComponentName />);
258
+ // Test interaction
259
+ });
260
+ });
261
+ });
262
+ ```
263
+
264
+ ## Reference
265
+
266
+ - React Testing Library: https://testing-library.com/react
267
+ - Vitest: https://vitest.dev
268
+ - Testing Standards: See `06-testing-and-docs-standard.md` in pace-core docs