@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.
- package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +12 -13
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
- package/cursor-rules/02-project-structure.mdc +37 -5
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
- package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +26 -16
- package/dist/{chunk-FENMYN2U.js → chunk-5X4QLXRG.js} +1 -3
- package/dist/{chunk-4T7OBVTU.js → chunk-6F3IILHI.js} +1 -1
- package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
- package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
- package/dist/{chunk-7TYHROIV.js → chunk-BM4CQ5P3.js} +50 -8
- package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
- package/dist/{chunk-OHIK3MIO.js → chunk-GHYHJTYV.js} +2 -2
- package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
- package/dist/{chunk-LAZMKTTF.js → chunk-JGWDVX64.js} +281 -347
- package/dist/{chunk-MAGBIDNS.js → chunk-L4XMVJKY.js} +2 -2
- package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
- package/dist/{chunk-ZS5VO5JB.js → chunk-Q7Q7V5NV.js} +406 -451
- package/dist/{chunk-3O3WHILE.js → chunk-VBCS3DUA.js} +236 -60
- package/dist/{chunk-BVP2BCJF.js → chunk-ZKAWKYT4.js} +8 -8
- package/dist/components.d.ts +5 -4
- package/dist/components.js +27 -32
- package/dist/eslint-rules/index.cjs +22 -9
- package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +26 -10
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +18 -17
- package/dist/rbac/index.js +6 -6
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +1 -1
- package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
- package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +8 -8
- package/docs/README.md +1 -1
- package/docs/api/modules.md +47 -31
- package/docs/api-reference/components.md +18 -20
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +1 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/README.md +5 -5
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -1
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +204 -185
- package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
- package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +203 -104
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/eslint-config-pace-core.cjs +21 -10
- package/package.json +6 -5
- package/scripts/install-cursor-rules.cjs +11 -243
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +10 -10
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +137 -153
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
- package/src/components/DataTable/components/EditableRow.tsx +5 -7
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/types.ts +0 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +7 -8
- package/src/components/Dialog/Dialog.test.tsx +1 -0
- package/src/components/Dialog/Dialog.tsx +25 -8
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +86 -77
- package/src/components/Select/types.ts +3 -0
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/public/usePublicEvent.ts +5 -5
- package/src/hooks/public/usePublicEventLogo.ts +5 -5
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +2 -2
- package/src/hooks/useEventTheme.test.ts +7 -7
- package/src/hooks/useEventTheme.ts +1 -4
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/storage/README.md +1 -1
- package/cursor-rules/01-standards-compliance.mdc +0 -285
- package/cursor-rules/04-testing-standards.mdc +0 -270
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
- package/cursor-rules/06-code-quality.mdc +0 -311
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
- package/cursor-rules/10-error-handling-patterns.mdc +0 -179
- package/cursor-rules/11-performance-optimization.mdc +0 -169
- package/cursor-rules/12-ci-cd-integration.mdc +0 -150
- package/dist/DataTable-LRJL4IRV.js +0 -15
- package/dist/eslint-rules/rules/compliance.cjs +0 -348
- package/dist/eslint-rules/rules/components.cjs +0 -113
- package/dist/eslint-rules/rules/imports.cjs +0 -102
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -604
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-standards-compliance.md +0 -188
- package/docs/standards/03-solid-principles.md +0 -39
- package/docs/standards/04-testing-standards.md +0 -36
- package/docs/standards/05-bug-reports-and-features.md +0 -27
- package/docs/standards/06-code-quality.md +0 -34
- package/docs/standards/07-tech-stack-compliance.md +0 -30
- package/docs/standards/10-error-handling-patterns.md +0 -401
- package/docs/standards/11-performance-optimization.md +0 -348
- package/docs/standards/12-ci-cd-integration.md +0 -370
- package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
- package/scripts/audit/audit-compliance.cjs +0 -1295
- package/scripts/audit/audit-components.cjs +0 -260
- package/scripts/audit/audit-rbac.cjs +0 -954
- package/scripts/audit/audit-standards.cjs +0 -1268
- package/scripts/audit/index.cjs +0 -1927
- package/src/components/DataTable/components/DataTableBody.tsx +0 -478
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/index.cjs +0 -22
- package/src/eslint-rules/rules/components.cjs +0 -113
- package/src/eslint-rules/rules/imports.cjs +0 -102
- package/src/eslint-rules/rules/rbac.cjs +0 -790
- package/src/eslint-rules/utils/helpers.cjs +0 -42
- 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(() => <
|
|
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(() => <
|
|
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: () => <
|
|
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')).
|
|
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')).
|
|
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: () => <
|
|
53
|
+
default: () => <section data-testid="lazy-component">Lazy Component</section>
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
const customFallback = <
|
|
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')).
|
|
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')).
|
|
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: () => <
|
|
77
|
+
default: () => <section data-testid="lazy-component">Lazy Component</section>
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
const ErrorBoundary = ({ children }: { children: React.ReactNode }) => (
|
|
81
|
-
<
|
|
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')).
|
|
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')).
|
|
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')).
|
|
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 <
|
|
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')).
|
|
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')).
|
|
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: () => <
|
|
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
|
-
<
|
|
171
|
+
<section data-testid="lazy-component">
|
|
172
172
|
{title}: {count}
|
|
173
|
-
</
|
|
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
|
-
<
|
|
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
|
-
<
|
|
202
|
+
<section>
|
|
203
203
|
<LazyTestComponent id="1" />
|
|
204
204
|
<LazyTestComponent id="2" />
|
|
205
|
-
</
|
|
205
|
+
</section>
|
|
206
206
|
);
|
|
207
207
|
|
|
208
208
|
await waitFor(() => {
|
|
209
|
-
expect(screen.getByTestId('lazy-component-1')).
|
|
210
|
-
expect(screen.getByTestId('lazy-component-2')).
|
|
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')).
|
|
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')).
|
|
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')).
|
|
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: () => <
|
|
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
|
-
<
|
|
274
|
+
<section data-testid="wrapper">
|
|
272
275
|
<LazyTestComponent />
|
|
273
|
-
</
|
|
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')).
|
|
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')).
|
|
286
|
+
expect(screen.getByTestId('lazy-component')).toBeDefined();
|
|
284
287
|
});
|
|
285
288
|
|
|
286
289
|
// Wrapper should still be present
|
|
287
|
-
expect(screen.getByTestId('wrapper')).
|
|
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: () => <
|
|
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')).
|
|
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
|
-
<
|
|
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
|