@jmruthers/pace-core 0.6.6 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +12 -13
  2. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  3. package/audit-tool/audits/02-project-structure.cjs +255 -0
  4. package/audit-tool/audits/03-architecture.cjs +196 -0
  5. package/audit-tool/audits/04-code-quality.cjs +149 -0
  6. package/audit-tool/audits/05-styling.cjs +224 -0
  7. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  8. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  9. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  10. package/audit-tool/audits/09-operations.cjs +208 -0
  11. package/audit-tool/index.cjs +291 -0
  12. package/audit-tool/utils/code-utils.cjs +218 -0
  13. package/audit-tool/utils/file-utils.cjs +230 -0
  14. package/audit-tool/utils/report-utils.cjs +241 -0
  15. package/cursor-rules/00-standards-overview.mdc +156 -0
  16. package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
  17. package/cursor-rules/02-project-structure.mdc +37 -5
  18. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
  19. package/cursor-rules/04-code-quality.mdc +419 -0
  20. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
  21. package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
  22. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  23. package/cursor-rules/08-testing-documentation.mdc +324 -0
  24. package/cursor-rules/09-operations.mdc +365 -0
  25. package/dist/DataTable-7PMH7XN7.js +15 -0
  26. package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  27. package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +26 -16
  28. package/dist/{chunk-FENMYN2U.js → chunk-5X4QLXRG.js} +1 -3
  29. package/dist/{chunk-4T7OBVTU.js → chunk-6F3IILHI.js} +1 -1
  30. package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
  31. package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
  32. package/dist/{chunk-7TYHROIV.js → chunk-BM4CQ5P3.js} +50 -8
  33. package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
  34. package/dist/{chunk-OHIK3MIO.js → chunk-GHYHJTYV.js} +2 -2
  35. package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
  36. package/dist/{chunk-LAZMKTTF.js → chunk-JGWDVX64.js} +281 -347
  37. package/dist/{chunk-MAGBIDNS.js → chunk-L4XMVJKY.js} +2 -2
  38. package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
  39. package/dist/{chunk-ZS5VO5JB.js → chunk-Q7Q7V5NV.js} +406 -451
  40. package/dist/{chunk-3O3WHILE.js → chunk-VBCS3DUA.js} +236 -60
  41. package/dist/{chunk-BVP2BCJF.js → chunk-ZKAWKYT4.js} +8 -8
  42. package/dist/components.d.ts +5 -4
  43. package/dist/components.js +27 -32
  44. package/dist/eslint-rules/index.cjs +22 -9
  45. package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
  46. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  47. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  48. package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +26 -10
  49. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  50. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  51. package/dist/hooks.d.ts +5 -5
  52. package/dist/hooks.js +6 -6
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.js +18 -17
  55. package/dist/rbac/index.js +6 -6
  56. package/dist/theming/runtime.d.ts +14 -1
  57. package/dist/theming/runtime.js +1 -1
  58. package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
  59. package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
  60. package/dist/utils.d.ts +2 -2
  61. package/dist/utils.js +8 -8
  62. package/docs/README.md +1 -1
  63. package/docs/api/modules.md +47 -31
  64. package/docs/api-reference/components.md +18 -20
  65. package/docs/api-reference/hooks.md +80 -80
  66. package/docs/api-reference/types.md +1 -1
  67. package/docs/api-reference/utilities.md +1 -1
  68. package/docs/architecture/README.md +1 -1
  69. package/docs/core-concepts/events.md +3 -3
  70. package/docs/core-concepts/organisations.md +6 -6
  71. package/docs/core-concepts/permissions.md +6 -6
  72. package/docs/documentation-index.md +12 -18
  73. package/docs/getting-started/documentation-index.md +1 -1
  74. package/docs/getting-started/examples/README.md +4 -4
  75. package/docs/getting-started/examples/full-featured-app.md +1 -1
  76. package/docs/getting-started/faq.md +2 -2
  77. package/docs/getting-started/quick-reference.md +4 -4
  78. package/docs/implementation-guides/authentication.md +15 -15
  79. package/docs/implementation-guides/component-styling.md +1 -1
  80. package/docs/implementation-guides/data-tables.md +126 -33
  81. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  82. package/docs/implementation-guides/dynamic-colors.md +3 -3
  83. package/docs/implementation-guides/file-upload-storage.md +2 -2
  84. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  85. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  86. package/docs/implementation-guides/large-datasets.md +3 -2
  87. package/docs/implementation-guides/organisation-security.md +2 -2
  88. package/docs/implementation-guides/performance.md +2 -2
  89. package/docs/implementation-guides/permission-enforcement.md +1 -1
  90. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  91. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  92. package/docs/rbac/README.md +5 -5
  93. package/docs/rbac/advanced-patterns.md +6 -6
  94. package/docs/rbac/api-reference.md +20 -20
  95. package/docs/rbac/event-based-apps.md +3 -3
  96. package/docs/rbac/examples.md +41 -41
  97. package/docs/rbac/getting-started.md +37 -37
  98. package/docs/rbac/performance.md +1 -1
  99. package/docs/rbac/quick-start.md +52 -52
  100. package/docs/rbac/secure-client-protection.md +1 -1
  101. package/docs/rbac/troubleshooting.md +1 -1
  102. package/docs/security/README.md +5 -5
  103. package/docs/standards/0-standards-overview.md +220 -0
  104. package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +204 -185
  105. package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
  106. package/docs/standards/3-architecture-standards.md +606 -0
  107. package/docs/standards/4-code-quality-standards.md +728 -0
  108. package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
  109. package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
  110. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  111. package/docs/standards/8-testing-documentation-standards.md +401 -0
  112. package/docs/standards/9-operations-standards.md +1102 -0
  113. package/docs/standards/README.md +203 -104
  114. package/docs/troubleshooting/README.md +4 -4
  115. package/docs/troubleshooting/common-issues.md +2 -2
  116. package/docs/troubleshooting/debugging.md +9 -9
  117. package/docs/troubleshooting/migration.md +4 -4
  118. package/eslint-config-pace-core.cjs +21 -10
  119. package/package.json +6 -5
  120. package/scripts/install-cursor-rules.cjs +11 -243
  121. package/scripts/install-eslint-config.cjs +284 -0
  122. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
  123. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  124. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +10 -10
  125. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  126. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  127. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  128. package/src/__tests__/templates/component.test.template.tsx +18 -15
  129. package/src/components/Calendar/Calendar.tsx +201 -47
  130. package/src/components/ContextSelector/ContextSelector.tsx +137 -153
  131. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  132. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  133. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  134. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  135. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  136. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  137. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  138. package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
  139. package/src/components/DataTable/components/EditableRow.tsx +5 -7
  140. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  141. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  142. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  143. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  144. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  145. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  146. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  147. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  148. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  149. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  150. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  151. package/src/components/DataTable/components/index.ts +2 -1
  152. package/src/components/DataTable/types.ts +0 -18
  153. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  154. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  155. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  156. package/src/components/DateTimeField/DateTimeField.tsx +7 -8
  157. package/src/components/Dialog/Dialog.test.tsx +1 -0
  158. package/src/components/Dialog/Dialog.tsx +25 -8
  159. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  160. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  161. package/src/components/FileUpload/FileUpload.tsx +112 -130
  162. package/src/components/Progress/Progress.tsx +2 -4
  163. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  164. package/src/components/Select/Select.tsx +86 -77
  165. package/src/components/Select/types.ts +3 -0
  166. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  167. package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
  168. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  169. package/src/hooks/public/usePublicEvent.ts +5 -5
  170. package/src/hooks/public/usePublicEventLogo.ts +5 -5
  171. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  172. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  173. package/src/hooks/useAppConfig.ts +2 -2
  174. package/src/hooks/useEventTheme.test.ts +7 -7
  175. package/src/hooks/useEventTheme.ts +1 -4
  176. package/src/hooks/useFileDisplay.ts +2 -2
  177. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  178. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  179. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  180. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  181. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  182. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  183. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  184. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  185. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
  186. package/src/styles/core.css +7 -0
  187. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  188. package/src/theming/parseEventColours.ts +22 -10
  189. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  190. package/src/utils/storage/README.md +1 -1
  191. package/cursor-rules/01-standards-compliance.mdc +0 -285
  192. package/cursor-rules/04-testing-standards.mdc +0 -270
  193. package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
  194. package/cursor-rules/06-code-quality.mdc +0 -311
  195. package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
  196. package/cursor-rules/10-error-handling-patterns.mdc +0 -179
  197. package/cursor-rules/11-performance-optimization.mdc +0 -169
  198. package/cursor-rules/12-ci-cd-integration.mdc +0 -150
  199. package/dist/DataTable-LRJL4IRV.js +0 -15
  200. package/dist/eslint-rules/rules/compliance.cjs +0 -348
  201. package/dist/eslint-rules/rules/components.cjs +0 -113
  202. package/dist/eslint-rules/rules/imports.cjs +0 -102
  203. package/docs/best-practices/README.md +0 -472
  204. package/docs/best-practices/accessibility.md +0 -604
  205. package/docs/best-practices/common-patterns.md +0 -516
  206. package/docs/best-practices/deployment.md +0 -1103
  207. package/docs/best-practices/performance.md +0 -1328
  208. package/docs/best-practices/security.md +0 -940
  209. package/docs/best-practices/testing.md +0 -1034
  210. package/docs/rbac/compliance/compliance-guide.md +0 -544
  211. package/docs/standards/01-standards-compliance.md +0 -188
  212. package/docs/standards/03-solid-principles.md +0 -39
  213. package/docs/standards/04-testing-standards.md +0 -36
  214. package/docs/standards/05-bug-reports-and-features.md +0 -27
  215. package/docs/standards/06-code-quality.md +0 -34
  216. package/docs/standards/07-tech-stack-compliance.md +0 -30
  217. package/docs/standards/10-error-handling-patterns.md +0 -401
  218. package/docs/standards/11-performance-optimization.md +0 -348
  219. package/docs/standards/12-ci-cd-integration.md +0 -370
  220. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
  221. package/scripts/audit/audit-compliance.cjs +0 -1295
  222. package/scripts/audit/audit-components.cjs +0 -260
  223. package/scripts/audit/audit-rbac.cjs +0 -954
  224. package/scripts/audit/audit-standards.cjs +0 -1268
  225. package/scripts/audit/index.cjs +0 -1927
  226. package/src/components/DataTable/components/DataTableBody.tsx +0 -478
  227. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  228. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  229. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  230. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  231. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  232. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  233. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  234. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  235. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  236. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  237. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  238. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  239. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  240. package/src/components/DataTable/utils/debugTools.ts +0 -514
  241. package/src/eslint-rules/index.cjs +0 -22
  242. package/src/eslint-rules/rules/components.cjs +0 -113
  243. package/src/eslint-rules/rules/imports.cjs +0 -102
  244. package/src/eslint-rules/rules/rbac.cjs +0 -790
  245. package/src/eslint-rules/utils/helpers.cjs +0 -42
  246. package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
@@ -15,19 +15,19 @@ import { renderWithProviders } from '../../__tests__/helpers/test-utils';
15
15
 
16
16
  // Mock the DataTable component
17
17
  vi.mock('../../components/DataTable', () => ({
18
- DataTable: vi.fn(() => <div data-testid="data-table">DataTable Component</div>)
18
+ DataTable: vi.fn(() => <section data-testid="data-table">DataTable Component</section>)
19
19
  }));
20
20
 
21
21
  // Mock the LoadingSpinner component
22
22
  vi.mock('../../components/LoadingSpinner/LoadingSpinner', () => ({
23
- LoadingSpinner: vi.fn(() => <div data-testid="loading-spinner">Loading...</div>)
23
+ LoadingSpinner: vi.fn(() => <p data-testid="loading-spinner">Loading...</p>)
24
24
  }));
25
25
 
26
26
  describe('LazyLoad Utility', () => {
27
27
  describe('createLazyComponent', () => {
28
28
  it('should create a lazy component with default fallback', async () => {
29
29
  const mockImportFn = vi.fn().mockResolvedValue({
30
- default: () => <div data-testid="lazy-component">Lazy Component</div>
30
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
31
31
  });
32
32
 
33
33
  const LazyTestComponent = createLazyComponent(
@@ -38,11 +38,11 @@ describe('LazyLoad Utility', () => {
38
38
  renderWithProviders(<LazyTestComponent />);
39
39
 
40
40
  // Should show loading spinner initially
41
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
41
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
42
42
 
43
43
  // Wait for the component to load
44
44
  await waitFor(() => {
45
- expect(screen.getByTestId('lazy-component')).toBeInTheDocument();
45
+ expect(screen.getByTestId('lazy-component')).toBeDefined();
46
46
  });
47
47
 
48
48
  expect(mockImportFn).toHaveBeenCalledTimes(1);
@@ -50,10 +50,10 @@ describe('LazyLoad Utility', () => {
50
50
 
51
51
  it('should create a lazy component with custom fallback', async () => {
52
52
  const mockImportFn = vi.fn().mockResolvedValue({
53
- default: () => <div data-testid="lazy-component">Lazy Component</div>
53
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
54
54
  });
55
55
 
56
- const customFallback = <div data-testid="custom-fallback">Custom Loading...</div>;
56
+ const customFallback = <p data-testid="custom-fallback">Custom Loading...</p>;
57
57
 
58
58
  const LazyTestComponent = createLazyComponent(
59
59
  mockImportFn,
@@ -64,21 +64,21 @@ describe('LazyLoad Utility', () => {
64
64
  renderWithProviders(<LazyTestComponent />);
65
65
 
66
66
  // Should show custom fallback initially
67
- expect(screen.getByTestId('custom-fallback')).toBeInTheDocument();
67
+ expect(screen.getByTestId('custom-fallback')).toBeDefined();
68
68
 
69
69
  // Wait for the component to load
70
70
  await waitFor(() => {
71
- expect(screen.getByTestId('lazy-component')).toBeInTheDocument();
71
+ expect(screen.getByTestId('lazy-component')).toBeDefined();
72
72
  });
73
73
  });
74
74
 
75
75
  it('should create a lazy component with error boundary', async () => {
76
76
  const mockImportFn = vi.fn().mockResolvedValue({
77
- default: () => <div data-testid="lazy-component">Lazy Component</div>
77
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
78
78
  });
79
79
 
80
80
  const ErrorBoundary = ({ children }: { children: React.ReactNode }) => (
81
- <div data-testid="error-boundary">{children}</div>
81
+ <section data-testid="error-boundary">{children}</section>
82
82
  );
83
83
 
84
84
  const LazyTestComponent = createLazyComponent(
@@ -90,15 +90,15 @@ describe('LazyLoad Utility', () => {
90
90
  renderWithProviders(<LazyTestComponent />);
91
91
 
92
92
  // Should show loading spinner initially
93
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
93
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
94
94
 
95
95
  // Wait for the component to load
96
96
  await waitFor(() => {
97
- expect(screen.getByTestId('lazy-component')).toBeInTheDocument();
97
+ expect(screen.getByTestId('lazy-component')).toBeDefined();
98
98
  });
99
99
 
100
100
  // Error boundary should wrap the component
101
- expect(screen.getByTestId('error-boundary')).toBeInTheDocument();
101
+ expect(screen.getByTestId('error-boundary')).toBeDefined();
102
102
  });
103
103
 
104
104
  it('should handle import errors gracefully', async () => {
@@ -121,7 +121,7 @@ describe('LazyLoad Utility', () => {
121
121
 
122
122
  render() {
123
123
  if (this.state.hasError) {
124
- return <div data-testid="error-display">Error occurred</div>;
124
+ return <p data-testid="error-display">Error occurred</p>;
125
125
  }
126
126
  return this.props.children;
127
127
  }
@@ -139,11 +139,11 @@ describe('LazyLoad Utility', () => {
139
139
  renderWithProviders(<LazyTestComponent />);
140
140
 
141
141
  // Should show loading spinner initially
142
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
142
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
143
143
 
144
144
  // Wait for error to be caught and displayed
145
145
  await waitFor(() => {
146
- expect(screen.getByTestId('error-display')).toBeInTheDocument();
146
+ expect(screen.getByTestId('error-display')).toBeDefined();
147
147
  }, { timeout: 2000 });
148
148
 
149
149
  // The import function should have been called
@@ -154,7 +154,7 @@ describe('LazyLoad Utility', () => {
154
154
 
155
155
  it('should set display name correctly', async () => {
156
156
  const mockImportFn = vi.fn().mockResolvedValue({
157
- default: () => <div data-testid="lazy-component">Lazy Component</div>
157
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
158
158
  });
159
159
 
160
160
  const LazyTestComponent = createLazyComponent(
@@ -168,9 +168,9 @@ describe('LazyLoad Utility', () => {
168
168
  it('should pass props to the lazy component', async () => {
169
169
  const mockImportFn = vi.fn().mockResolvedValue({
170
170
  default: ({ title, count }: { title: string; count: number }) => (
171
- <div data-testid="lazy-component">
171
+ <section data-testid="lazy-component">
172
172
  {title}: {count}
173
- </div>
173
+ </section>
174
174
  )
175
175
  });
176
176
 
@@ -189,7 +189,7 @@ describe('LazyLoad Utility', () => {
189
189
  it('should handle multiple instances of the same lazy component', async () => {
190
190
  const mockImportFn = vi.fn().mockResolvedValue({
191
191
  default: ({ id }: { id: string }) => (
192
- <div data-testid={`lazy-component-${id}`}>Component {id}</div>
192
+ <section data-testid={`lazy-component-${id}`}>Component {id}</section>
193
193
  )
194
194
  });
195
195
 
@@ -199,15 +199,15 @@ describe('LazyLoad Utility', () => {
199
199
  );
200
200
 
201
201
  renderWithProviders(
202
- <div>
202
+ <section>
203
203
  <LazyTestComponent id="1" />
204
204
  <LazyTestComponent id="2" />
205
- </div>
205
+ </section>
206
206
  );
207
207
 
208
208
  await waitFor(() => {
209
- expect(screen.getByTestId('lazy-component-1')).toBeInTheDocument();
210
- expect(screen.getByTestId('lazy-component-2')).toBeInTheDocument();
209
+ expect(screen.getByTestId('lazy-component-1')).toBeDefined();
210
+ expect(screen.getByTestId('lazy-component-2')).toBeDefined();
211
211
  });
212
212
 
213
213
  // Import function should only be called once due to React.lazy caching
@@ -219,37 +219,40 @@ describe('LazyLoad Utility', () => {
219
219
  it('should render the DataTable component when loaded', async () => {
220
220
  const mockProps = {
221
221
  data: [{ id: 1, name: 'Test' }],
222
- columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }]
222
+ columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }],
223
+ rbac: { pageName: 'test-page' }
223
224
  };
224
225
 
225
226
  renderWithProviders(<LazyDataTable {...mockProps} />);
226
227
 
227
228
  // Should show loading spinner initially
228
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
229
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
229
230
 
230
231
  // Wait for the DataTable to load
231
232
  await waitFor(() => {
232
- expect(screen.getByTestId('data-table')).toBeInTheDocument();
233
+ expect(screen.getByTestId('data-table')).toBeDefined();
233
234
  });
234
235
  });
235
236
 
236
237
  it('should pass props to the DataTable component', async () => {
237
238
  const mockProps = {
238
239
  data: [{ id: 1, name: 'Test' }],
239
- columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }]
240
+ columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }],
241
+ rbac: { pageName: 'test-page' }
240
242
  };
241
243
 
242
244
  renderWithProviders(<LazyDataTable {...mockProps} />);
243
245
 
244
246
  await waitFor(() => {
245
- expect(screen.getByTestId('data-table')).toBeInTheDocument();
247
+ expect(screen.getByTestId('data-table')).toBeDefined();
246
248
  });
247
249
  });
248
250
 
249
251
  it('should render without errors', () => {
250
252
  const mockProps = {
251
253
  data: [{ id: 1, name: 'Test' }],
252
- columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }]
254
+ columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }],
255
+ rbac: { pageName: 'test-page' }
253
256
  };
254
257
 
255
258
  expect(() => renderWithProviders(<LazyDataTable {...mockProps} />)).not.toThrow();
@@ -259,7 +262,7 @@ describe('LazyLoad Utility', () => {
259
262
  describe('Component Integration', () => {
260
263
  it('should work with React Suspense boundaries', async () => {
261
264
  const mockImportFn = vi.fn().mockResolvedValue({
262
- default: () => <div data-testid="lazy-component">Lazy Component</div>
265
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
263
266
  });
264
267
 
265
268
  const LazyTestComponent = createLazyComponent(
@@ -268,23 +271,23 @@ describe('LazyLoad Utility', () => {
268
271
  );
269
272
 
270
273
  const TestWrapper = () => (
271
- <div data-testid="wrapper">
274
+ <section data-testid="wrapper">
272
275
  <LazyTestComponent />
273
- </div>
276
+ </section>
274
277
  );
275
278
 
276
279
  renderWithProviders(<TestWrapper />);
277
280
 
278
281
  // Should show loading spinner initially
279
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
282
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
280
283
 
281
284
  // Wait for the component to load
282
285
  await waitFor(() => {
283
- expect(screen.getByTestId('lazy-component')).toBeInTheDocument();
286
+ expect(screen.getByTestId('lazy-component')).toBeDefined();
284
287
  });
285
288
 
286
289
  // Wrapper should still be present
287
- expect(screen.getByTestId('wrapper')).toBeInTheDocument();
290
+ expect(screen.getByTestId('wrapper')).toBeDefined();
288
291
  });
289
292
 
290
293
  it('should handle unmounting before load completes', async () => {
@@ -292,7 +295,7 @@ describe('LazyLoad Utility', () => {
292
295
  new Promise(resolve => {
293
296
  setTimeout(() => {
294
297
  resolve({
295
- default: () => <div data-testid="lazy-component">Lazy Component</div>
298
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
296
299
  });
297
300
  }, 100);
298
301
  })
@@ -306,7 +309,7 @@ describe('LazyLoad Utility', () => {
306
309
  const { unmount } = renderWithProviders(<LazyTestComponent />);
307
310
 
308
311
  // Should show loading spinner initially
309
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
312
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
310
313
 
311
314
  // Unmount before load completes
312
315
  unmount();
@@ -67,7 +67,7 @@ Enhanced file upload component with progress tracking, previews, and validation.
67
67
  onProgress={(progress) => {}} // Progress callback
68
68
  >
69
69
  {/* Optional custom upload UI */}
70
- <div>Custom upload area</div>
70
+ <section>Custom upload area</section>
71
71
  </FileUpload>
72
72
  ```
73
73
 
@@ -1,285 +0,0 @@
1
- ---
2
- description: Enforce compliance with all pace-core standards across architecture, API, components, code style, security, testing, and RBAC/RLS
3
- globs: ["src/**/*.{ts,tsx,js,jsx}", "supabase/migrations/**/*.sql"]
4
- alwaysApply: false
5
- paceCoreVersion: "0.6.x"
6
- rulesVersion: "2025-01-28"
7
- ---
8
- # Standards Compliance Guide
9
-
10
- This guide ensures consuming apps comply with all pace-core standards. Follow these standards to maintain quality, security, and consistency.
11
-
12
- ## MUST: Include Complete Cursor Ruleset
13
-
14
- Consuming apps **MUST** include the complete pace-core ruleset in the repository so audits are deterministic and repeatable.
15
-
16
- - **MUST** include these files under `.cursor/rules/` (exact filenames):
17
- - `00-pace-core-compliance.mdc`
18
- - `01-standards-compliance.mdc`
19
- - `02-project-structure.mdc`
20
- - `03-solid-principles.mdc`
21
- - `06-code-quality.mdc`
22
- - `07-tech-stack-compliance.mdc`
23
- - `08-markup-quality.mdc`
24
- - `09-rbac-compliance.mdc`
25
- - `10-error-handling-patterns.mdc`
26
- - `11-performance-optimization.mdc`
27
- - **MUST NOT** rename or partially copy rules files.
28
- - If a rule does not apply to a given app, document the exception and the reason, but keep the rule file present.
29
-
30
-
31
- ## Architecture Standard
32
-
33
- ### MUST: Follow Architecture Principles
34
-
35
- **MUST adhere to:**
36
- - Composition over complexity
37
- - Separation of concerns
38
- - Domain-agnostic design
39
- - Extensible, stable APIs
40
- - Secure by default
41
- - Performance-conscious
42
-
43
- ### MUST: Use Helper Functions in RLS Policies
44
-
45
- **RLS policies MUST use helper functions, NEVER subqueries.**
46
-
47
- ```sql
48
- -- ❌ WRONG: Subquery in RLS policy (causes N+1 queries)
49
- CREATE POLICY rbac_select_users ON users FOR SELECT USING (
50
- organisation_id IN (SELECT organisation_id FROM organisation_memberships WHERE user_id = auth.uid())
51
- );
52
-
53
- -- ✅ CORRECT: Helper function with STABLE SECURITY DEFINER
54
- CREATE OR REPLACE FUNCTION get_user_organisation_ids() RETURNS uuid[] LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO public AS $$
55
- BEGIN RETURN ARRAY(SELECT organisation_id FROM organisation_memberships WHERE user_id = get_effective_user_id()); END;
56
- $$;
57
- CREATE POLICY rbac_select_users ON users FOR SELECT USING (organisation_id = ANY(get_user_organisation_ids()));
58
- ```
59
-
60
- ### MUST: Test Database Migrations
61
-
62
- **MUST verify migrations don't cause query timeouts or performance degradation.**
63
-
64
- ## API & RPC Standard
65
-
66
- ### MUST: Follow RPC Naming Convention
67
-
68
- **RPCs MUST follow pattern: `<family>_<domain>_<verb>`**
69
-
70
- - `data_*` prefix for read operations: `data_cake_dishes_list`, `data_file_reference_list`
71
- - `app_*` prefix for write operations: `app_cake_dish_create`, `app_cake_dish_update`
72
- - CRUD verbs only: `create`, `read`, `update`, `delete`, `list`, `get`
73
- - Bulk operations: `_bulk` suffix (e.g., `app_cake_dish_create_bulk`)
74
-
75
- ```sql
76
- -- ✅ CORRECT: data_cake_dishes_list, app_cake_dish_create, app_cake_dish_create_bulk
77
- -- ❌ WRONG: getDishes, create_dish (wrong naming pattern)
78
- ```
79
-
80
- ### MUST: Use ApiResult Shape
81
-
82
- **All RPCs MUST return ApiResult shape:**
83
-
84
- ```typescript
85
- type ApiResult<T> = { ok: true; data: T } | { ok: false; error: ApiError };
86
- type ApiError = { code: string; message: string; details?: object };
87
- ```
88
-
89
- ### MUST: Enforce RLS in RPCs
90
-
91
- **RPCs MUST enforce RLS and tenant boundaries.** Never bypass RLS.
92
-
93
- ### SHOULD: Make Write RPCs Idempotent
94
-
95
- **Write RPCs SHOULD be idempotent when possible.**
96
-
97
- ## Component Standard
98
-
99
- ### MUST: Follow Component Principles
100
-
101
- **Components MUST:**
102
- - Be stateless when possible
103
- - Use composable structure
104
- - Be accessible by default
105
- - Be fully typed
106
- - Have small surface area
107
-
108
- ### MUST NOT: Add Domain Logic to Components
109
-
110
- **Components MUST NOT:**
111
- - Include domain-specific logic
112
- - Fetch data directly (use hooks/services)
113
- - Include business workflows
114
-
115
- ### MUST: Ensure Accessibility
116
-
117
- **Components MUST:**
118
- - Be keyboard operable
119
- - Have correct ARIA roles
120
- - Have visible focus states
121
- - Avoid inaccessible interactions
122
-
123
- ## Code Style Standard
124
-
125
- ### MUST: Follow TypeScript Rules
126
-
127
- **MUST:**
128
- - Use strict mode (`strict: true` in tsconfig)
129
- - Prefer discriminated unions
130
- - Use ReadonlyArray where possible
131
- - Avoid boolean mode flags (use unions instead)
132
-
133
- **MUST NOT:**
134
- - Use `any` (use `unknown` if type is truly unknown)
135
- - Use implicit any
136
- - Use unnecessary type assertions
137
-
138
- ### MUST: Follow Naming Conventions
139
-
140
- - Hooks: `useSomething`
141
- - Providers: `SomethingProvider`
142
- - Utilities: `camelCase`
143
- - Components: `PascalCase`
144
-
145
- ### SHOULD: Use Preferred Patterns
146
-
147
- **SHOULD:**
148
- - Use pure functions
149
- - Prefer composition over inheritance
150
- - Use early returns
151
- - Extract large functions into small helpers
152
-
153
- ## Security Standard
154
-
155
- ### MUST: Never Bypass RLS
156
-
157
- **MUST enforce RLS on all tables.** Never bypass RLS policies.
158
-
159
- ### MUST: Validate All Inputs
160
-
161
- **MUST validate all inputs using Zod schemas or similar.**
162
-
163
- ### MUST: Sanitize Logs
164
-
165
- **MUST NOT log:**
166
- - Passwords
167
- - Tokens
168
- - Sensitive data (PII)
169
-
170
- **MAY log:**
171
- - IDs
172
- - Non-PII metadata
173
-
174
- ### MUST: Use Safe Error Messaging
175
-
176
- **MUST NOT expose internal details in error messages.**
177
-
178
- ### MUST: Use Helper Functions in RLS
179
-
180
- **RLS policies MUST use STABLE SECURITY DEFINER helper functions:**
181
- - `STABLE` - Results consistent within transaction
182
- - `SECURITY DEFINER` - Bypass RLS to avoid recursion
183
- - `SET search_path TO 'public'` - Prevent search path injection
184
-
185
- ## Testing Standard
186
-
187
- ### MUST: Meet Coverage Requirements
188
-
189
- **MUST achieve:**
190
- - ≥90% coverage for utils & hooks
191
- - ≥70% coverage for components
192
-
193
-
194
- ### MUST: Enforce Coverage Thresholds in Tooling
195
-
196
- Coverage requirements must be **machine-enforced**, not aspirational:
197
-
198
- - **MUST** provide a script: `npm run test:coverage`
199
- - **MUST** configure the test runner (Vitest/Jest) to enforce the thresholds:
200
- - ≥90% for utils & hooks
201
- - ≥70% for components
202
- - **MUST** fail the command when thresholds are not met (CI or local execution).
203
-
204
- **Verification:**
205
- - `npm run test:coverage` exits non-zero when below threshold.
206
- - A coverage summary artifact is produced (e.g., `coverage/coverage-summary.json` or equivalent).
207
-
208
- ### MUST: Use React Testing Library
209
-
210
- **MUST use React Testing Library + userEvent for component tests.**
211
-
212
- ### SHOULD: Colocate Tests
213
-
214
- **Tests SHOULD be colocated: `*.test.ts` or `*.test.tsx`**
215
-
216
- ### SHOULD: Test Critical Paths
217
-
218
- **SHOULD test:**
219
- - Key user interactions
220
- - Error handling
221
- - Edge cases
222
- - Critical business logic
223
-
224
- ## RBAC & RLS Standard
225
-
226
- ### MUST: Use Helper Functions
227
-
228
- **All RLS policies MUST use helper functions with:**
229
- - `STABLE` attribute
230
- - `SECURITY DEFINER` attribute
231
- - `SET search_path TO 'public'`
232
-
233
- ### MUST: Follow Policy Naming
234
-
235
- **RLS policies MUST follow pattern: `rbac_{operation}_{table_name}_{scope}`**
236
-
237
- Example: `rbac_select_users_organisation`
238
-
239
- ### MUST: Include Organisation Context
240
-
241
- **RLS policies MUST include `organisation_id` for multi-tenant isolation.**
242
-
243
- ### MUST: Include Super Admin Checks
244
-
245
- **RLS policies SHOULD include super admin checks where appropriate.**
246
-
247
- ## Standards Precedence
248
-
249
- When standards conflict, follow this order:
250
- 1. Security Standard (highest priority)
251
- 2. API & RPC Standard
252
- 3. Component Standard
253
- 4. Code Style Standard
254
- 5. Testing Standard
255
- 6. Documentation Standard
256
-
257
- ## Compliance Checklist
258
-
259
- Before committing code, verify:
260
- - [ ] RLS policies use helper functions (no subqueries)
261
- - [ ] RPCs follow naming convention
262
- - [ ] Components are accessible and typed
263
- - [ ] No `any` types used
264
- - [ ] Inputs are validated
265
- - [ ] Tests meet coverage requirements
266
- - [ ] No sensitive data in logs
267
- - [ ] Error messages are safe
268
-
269
- ## Reference
270
-
271
- **📚 Human-Readable Standard**: See [01-standards-compliance.md](../../packages/core/docs/standards/01-standards-compliance.md) for complete documentation.
272
-
273
- **Related Standards** (all have corresponding cursor rules):
274
- - **00-pace-core-compliance.mdc** - pace-core usage patterns
275
- - **02-project-structure.mdc** - Project structure and organization
276
- - **03-solid-principles.mdc** - SOLID architecture principles
277
- - **04-testing-standards.mdc** - Testing framework standards
278
- - **05-bug-reports-and-features.mdc** - Issue reporting templates
279
- - **06-code-quality.mdc** - Code quality and TypeScript standards
280
- - **07-tech-stack-compliance.mdc** - Tech stack and API/RPC standards
281
- - **08-markup-quality.mdc** - Markup and styling standards
282
- - **09-rbac-compliance.mdc** - RBAC and RLS standards
283
- - **10-error-handling-patterns.mdc** - Error handling patterns
284
- - **11-performance-optimization.mdc** - Performance optimization
285
- - **12-ci-cd-integration.mdc** - CI/CD integration patterns