@jmruthers/pace-core 0.6.5 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- 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/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- 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/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- 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/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- 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/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- 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/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- 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 +5 -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/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- 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 -35
- 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/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- 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 +185 -57
- 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/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- 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/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- 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/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- 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/RowComponent.tsx +12 -0
- 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/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -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 +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- 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/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- 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/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- 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-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- 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/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce tech stack compliance, API/RPC naming conventions, and Vite configuration patterns
|
|
3
|
+
globs: ["src/**/*.{ts,tsx,js,jsx,css}", "*.config.{ts,js}", "supabase/migrations/**/*.sql"]
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
paceCoreVersion: "0.6.x"
|
|
6
|
+
rulesVersion: "2025-01-28"
|
|
7
|
+
---
|
|
8
|
+
# API & Tech Stack Standards Guide
|
|
9
|
+
|
|
10
|
+
**📚 Human-Readable Standard**: See [7-api-tech-stack-standards.md](../../packages/core/docs/standards/7-api-tech-stack-standards.md) for complete documentation.
|
|
11
|
+
|
|
12
|
+
This guide ensures consuming apps use the correct versions and patterns for all technologies in the PACE stack, and follow API/RPC naming conventions.
|
|
13
|
+
|
|
14
|
+
## AI Agent Instructions
|
|
15
|
+
|
|
16
|
+
**When writing or modifying code, ALWAYS:**
|
|
17
|
+
1. **Use Tailwind v4 CSS-first** - Use `@import 'tailwindcss'` and `@theme`, never `@tailwind` directives
|
|
18
|
+
2. **Use theme variables** - Never use bracket syntax like `bg-[oklch(...)]`, always use theme variables (`bg-main-500`)
|
|
19
|
+
3. **Use custom color namespaces** - Always use `main-*`, `sec-*`, `acc-*`, never standard Tailwind colors
|
|
20
|
+
4. **Follow RPC naming** - Read operations: `data_*`, write operations: `app_*`, verbs: `create`, `read`, `update`, `delete`, `list`, `get`
|
|
21
|
+
5. **Return ApiResult** - All RPCs must return ApiResult shape with proper error handling
|
|
22
|
+
6. **Use TanStack Query** - Always use TanStack Query for server state, never `useState + useEffect`
|
|
23
|
+
7. **Use React Hook Form + Zod** - Always use `useZodForm` from pace-core for forms
|
|
24
|
+
|
|
25
|
+
**Decision Tree: RPC Naming**
|
|
26
|
+
```
|
|
27
|
+
1. What operation is this?
|
|
28
|
+
├─ Read (SELECT) → data_<domain>_<verb>
|
|
29
|
+
├─ Write (INSERT/UPDATE/DELETE) → app_<domain>_<verb>
|
|
30
|
+
└─ Bulk operation → app_<domain>_<verb>_bulk
|
|
31
|
+
|
|
32
|
+
2. What verb should I use?
|
|
33
|
+
├─ Get single item → get
|
|
34
|
+
├─ Get multiple items → list
|
|
35
|
+
├─ Create → create
|
|
36
|
+
├─ Update → update
|
|
37
|
+
├─ Delete → delete
|
|
38
|
+
└─ Read (generic) → read
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Decision Tree: Styling**
|
|
42
|
+
```
|
|
43
|
+
1. What am I styling?
|
|
44
|
+
├─ Component → Use pace-core component (already styled)
|
|
45
|
+
├─ Layout → Use Tailwind utilities (grid, flex, gap)
|
|
46
|
+
└─ Custom → Use theme variables (main-*, sec-*, acc-*)
|
|
47
|
+
|
|
48
|
+
2. Do I need a color?
|
|
49
|
+
├─ YES → Use theme variable (bg-main-500, text-sec-700)
|
|
50
|
+
└─ NO → Use semantic class (bg-background, text-foreground)
|
|
51
|
+
|
|
52
|
+
3. Am I using bracket syntax?
|
|
53
|
+
├─ YES → WRONG - Use theme variable instead
|
|
54
|
+
└─ NO → Continue
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Tailwind CSS v4
|
|
58
|
+
|
|
59
|
+
### MUST: Use Tailwind v4 CSS-First Approach
|
|
60
|
+
|
|
61
|
+
**MUST use Tailwind v4 CSS-first syntax, NOT v3 patterns:**
|
|
62
|
+
|
|
63
|
+
```css
|
|
64
|
+
/* ✅ CORRECT: Tailwind v4 CSS-first (@import 'tailwindcss'; @theme { ... }) */
|
|
65
|
+
/* ❌ WRONG: Tailwind v3 (@tailwind base/components/utilities directives) */
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### MUST NOT: Use Bracket Syntax
|
|
69
|
+
|
|
70
|
+
**MUST NOT use bracket syntax like `bg-[oklch(...)]`. Map everything through theme variables:**
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// ❌ WRONG: Bracket syntax (bg-[oklch(...)])
|
|
74
|
+
// ✅ CORRECT: Theme variable (bg-main-500)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### MUST: Use Custom Color Namespaces
|
|
78
|
+
|
|
79
|
+
**MUST use custom color namespaces:**
|
|
80
|
+
- `main-*` for primary colors (green, emerald, teal, cyan, sky, blue)
|
|
81
|
+
- `sec-*` for secondary colors (indigo, violet, purple, fuchsia, slate, gray, zinc, neutral, stone)
|
|
82
|
+
- `acc-*` for accent colors (red, orange, amber, yellow, lime, pink, rose)
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// ✅ CORRECT: Custom namespaces (main-*, sec-*, acc-*)
|
|
86
|
+
// ❌ WRONG: Standard Tailwind colors (blue-*, gray-*, red-*)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### MUST: Use Semantic Classes
|
|
90
|
+
|
|
91
|
+
**MUST use semantic classes mapped in index.css:**
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
// ✅ CORRECT - Semantic classes
|
|
95
|
+
<div className="bg-background text-foreground">
|
|
96
|
+
|
|
97
|
+
// ❌ WRONG - Direct color classes (unless necessary)
|
|
98
|
+
<div className="bg-main-50 text-main-950">
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## React 19+
|
|
102
|
+
|
|
103
|
+
### MUST: Use React 19+ Features
|
|
104
|
+
|
|
105
|
+
**MUST use React 19+ patterns:**
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// ✅ CORRECT: React 19+ features (Suspense, useTransition, etc.)
|
|
109
|
+
import { Suspense, useTransition } from 'react';
|
|
110
|
+
function App() {
|
|
111
|
+
const [isPending, startTransition] = useTransition();
|
|
112
|
+
return <Suspense fallback={<Loading />}><Component /></Suspense>;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### MUST: Use Functional Components
|
|
117
|
+
|
|
118
|
+
**MUST use functional components with hooks exclusively:**
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
// ✅ CORRECT: Functional components with hooks
|
|
122
|
+
function MyComponent() { const [state, setState] = useState(); return <div>...</div>; }
|
|
123
|
+
|
|
124
|
+
// ❌ WRONG: Class components
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Supabase
|
|
128
|
+
|
|
129
|
+
### MUST: Use Secure Supabase Client
|
|
130
|
+
|
|
131
|
+
**MUST use `useSecureSupabase()` for all database operations:**
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
// ✅ CORRECT: useSecureSupabase() from '@jmruthers/pace-core/rbac'
|
|
135
|
+
// ❌ WRONG: createClient() from '@supabase/supabase-js' (base client)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### MUST: Enforce RLS
|
|
139
|
+
|
|
140
|
+
**MUST ensure RLS is enabled on all tables. Never bypass RLS.**
|
|
141
|
+
|
|
142
|
+
### SHOULD: Use RPC Functions
|
|
143
|
+
|
|
144
|
+
**SHOULD use RPC functions for complex queries:**
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
// ✅ CORRECT: RPC functions for complex queries
|
|
148
|
+
const { data } = await secureSupabase.rpc('data_events_list', { organisation_id: orgId });
|
|
149
|
+
|
|
150
|
+
// ❌ AVOID: Complex client-side queries with many joins
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## TanStack Query
|
|
154
|
+
|
|
155
|
+
### MUST: Use TanStack Query for Server State
|
|
156
|
+
|
|
157
|
+
**MUST use TanStack Query for all server state management:**
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
// ✅ CORRECT: TanStack Query for server state
|
|
161
|
+
import { useQuery, useMutation } from '@tanstack/react-query';
|
|
162
|
+
const { data, isLoading } = useQuery({ queryKey: ['events', orgId], queryFn: () => fetchEvents(orgId) });
|
|
163
|
+
|
|
164
|
+
// ❌ WRONG: useState + useEffect for server state
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### SHOULD: Configure Query Client
|
|
168
|
+
|
|
169
|
+
**SHOULD configure QueryClient with appropriate defaults:**
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
// ✅ CORRECT: Configure QueryClient with appropriate defaults (staleTime, cacheTime, retry)
|
|
173
|
+
const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 5 * 60 * 1000, cacheTime: 10 * 60 * 1000, retry: 1 } } });
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## React Hook Form + Zod
|
|
177
|
+
|
|
178
|
+
### MUST: Use React Hook Form with Zod
|
|
179
|
+
|
|
180
|
+
**MUST use React Hook Form with Zod for all forms:**
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
// ✅ CORRECT: React Hook Form + Zod (useZodForm from pace-core)
|
|
184
|
+
import { useZodForm } from '@jmruthers/pace-core';
|
|
185
|
+
const schema = z.object({ email: z.string().email(), name: z.string().min(1) });
|
|
186
|
+
const form = useZodForm(schema);
|
|
187
|
+
|
|
188
|
+
// ❌ WRONG: Manual form handling (useState for form state)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Vite Configuration
|
|
192
|
+
|
|
193
|
+
### MUST: Use Vite for Build Tooling
|
|
194
|
+
|
|
195
|
+
**MUST use Vite for all build tooling:**
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// ✅ CORRECT: Vite for build tooling
|
|
199
|
+
import { defineConfig } from 'vite';
|
|
200
|
+
import react from '@vitejs/plugin-react';
|
|
201
|
+
export default defineConfig({ plugins: [react()] });
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### MUST: Configure Vite for pace-core
|
|
205
|
+
|
|
206
|
+
**⚠️ CRITICAL: Vite configuration prevents React context mismatches!**
|
|
207
|
+
|
|
208
|
+
**MUST** configure Vite to exclude `@jmruthers/pace-core` and `react-router-dom` from pre-bundling:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// vite.config.ts
|
|
212
|
+
import { defineConfig } from 'vite';
|
|
213
|
+
import react from '@vitejs/plugin-react';
|
|
214
|
+
import path from 'path';
|
|
215
|
+
|
|
216
|
+
export default defineConfig({
|
|
217
|
+
plugins: [react()],
|
|
218
|
+
resolve: {
|
|
219
|
+
alias: {
|
|
220
|
+
'@': path.resolve(__dirname, './src'),
|
|
221
|
+
},
|
|
222
|
+
// CRITICAL: Dedupe React dependencies
|
|
223
|
+
dedupe: ['react', 'react-dom', 'react-router-dom'],
|
|
224
|
+
},
|
|
225
|
+
optimizeDeps: {
|
|
226
|
+
include: [
|
|
227
|
+
'react',
|
|
228
|
+
'react-dom',
|
|
229
|
+
'react/jsx-runtime',
|
|
230
|
+
],
|
|
231
|
+
// CRITICAL: Exclude pace-core to prevent React context mismatches
|
|
232
|
+
exclude: ['@jmruthers/pace-core', 'react-router-dom'],
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Why this matters:**
|
|
238
|
+
- Pre-bundling `@jmruthers/pace-core` creates separate React instances
|
|
239
|
+
- This causes "useUnifiedAuth must be used within a UnifiedAuthProvider" errors
|
|
240
|
+
- Excluding it ensures pace-core uses the same React instance as your app
|
|
241
|
+
- `react-router-dom` must also be excluded and deduped to prevent Router context errors
|
|
242
|
+
|
|
243
|
+
### MUST: Use Environment Variables Correctly
|
|
244
|
+
|
|
245
|
+
**MUST use `import.meta.env` for environment variables:**
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
// ✅ CORRECT: import.meta.env.VITE_API_URL (Vite env vars)
|
|
249
|
+
// ❌ WRONG: process.env.VITE_API_URL (Node.js env vars)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## API & RPC Patterns
|
|
253
|
+
|
|
254
|
+
### MUST: Follow RPC Naming Convention
|
|
255
|
+
|
|
256
|
+
**RPCs MUST follow pattern: `<family>_<domain>_<verb>`**
|
|
257
|
+
|
|
258
|
+
- `data_*` prefix for read operations: `data_events_list`, `data_file_reference_list`
|
|
259
|
+
- `app_*` prefix for write operations: `app_event_create`, `app_event_update`
|
|
260
|
+
- CRUD verbs only: `create`, `read`, `update`, `delete`, `list`, `get`
|
|
261
|
+
- Bulk operations: `_bulk` suffix (e.g., `app_event_create_bulk`)
|
|
262
|
+
|
|
263
|
+
```sql
|
|
264
|
+
-- ✅ CORRECT: data_events_list, app_event_create, app_event_create_bulk
|
|
265
|
+
-- ❌ WRONG: getEvents, create_event (wrong naming pattern)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### MUST: Use ApiResult Shape
|
|
269
|
+
|
|
270
|
+
**All RPCs MUST return ApiResult shape:**
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
type ApiResult<T> = { ok: true; data: T } | { ok: false; error: ApiError };
|
|
274
|
+
type ApiError = { code: string; message: string; details?: object };
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
// ✅ CORRECT: Handle ApiResult
|
|
279
|
+
const result = await supabase.rpc('app_events_create', { name, date });
|
|
280
|
+
if (!result.ok) {
|
|
281
|
+
// Handle error
|
|
282
|
+
return { ok: false, error: result.error };
|
|
283
|
+
}
|
|
284
|
+
return { ok: true, data: result.data };
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### MUST: Enforce RLS in RPCs
|
|
288
|
+
|
|
289
|
+
**RPCs MUST enforce RLS and tenant boundaries.** Never bypass RLS.
|
|
290
|
+
|
|
291
|
+
### SHOULD: Make Write RPCs Idempotent
|
|
292
|
+
|
|
293
|
+
**Write RPCs SHOULD be idempotent when possible:**
|
|
294
|
+
|
|
295
|
+
```sql
|
|
296
|
+
-- ✅ CORRECT: Idempotent create (ON CONFLICT DO NOTHING)
|
|
297
|
+
INSERT INTO events (id, name, date)
|
|
298
|
+
VALUES (p_event_id, p_name, p_date)
|
|
299
|
+
ON CONFLICT (id) DO NOTHING;
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## TypeScript
|
|
303
|
+
|
|
304
|
+
**Note**: TypeScript configuration details are handled by ESLint and the standards. See [7-api-tech-stack-standards.md](../../packages/core/docs/standards/7-api-tech-stack-standards.md) for complete TypeScript setup.
|
|
305
|
+
|
|
306
|
+
**MUST:**
|
|
307
|
+
- Use TypeScript 5+ with strict mode
|
|
308
|
+
- Follow TypeScript patterns from [4-code-quality-standards.md](../../packages/core/docs/standards/4-code-quality-standards.md)
|
|
309
|
+
|
|
310
|
+
## Version Requirements
|
|
311
|
+
|
|
312
|
+
### MUST: Use Required Versions
|
|
313
|
+
|
|
314
|
+
**MUST use compatible versions:**
|
|
315
|
+
|
|
316
|
+
- React: `^19.0.0`
|
|
317
|
+
- TypeScript: `^5.0.0`
|
|
318
|
+
- Tailwind CSS: `^4.0.0`
|
|
319
|
+
- Vite: `^6.0.0`
|
|
320
|
+
- Supabase: `^2.49.0+`
|
|
321
|
+
|
|
322
|
+
**Check `package.json` for exact versions required by pace-core.**
|
|
323
|
+
|
|
324
|
+
## Common Mistakes to Avoid
|
|
325
|
+
|
|
326
|
+
**When writing code, NEVER:**
|
|
327
|
+
1. **Use Tailwind v3 patterns** - Always use v4 CSS-first syntax
|
|
328
|
+
```css
|
|
329
|
+
/* ❌ WRONG */
|
|
330
|
+
@tailwind base;
|
|
331
|
+
@tailwind components;
|
|
332
|
+
@tailwind utilities;
|
|
333
|
+
|
|
334
|
+
/* ✅ CORRECT */
|
|
335
|
+
@import "tailwindcss";
|
|
336
|
+
@theme { /* ... */ }
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
2. **Use bracket syntax for colors** - Always use theme variables
|
|
340
|
+
```tsx
|
|
341
|
+
// ❌ WRONG
|
|
342
|
+
<div className="bg-[oklch(0.5 0.2 250)]">
|
|
343
|
+
|
|
344
|
+
// ✅ CORRECT
|
|
345
|
+
<div className="bg-main-500">
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
3. **Use standard Tailwind colors** - Always use custom namespaces (main-*, sec-*, acc-*)
|
|
349
|
+
4. **Use useState + useEffect for server state** - Always use TanStack Query
|
|
350
|
+
5. **Create RPCs without ApiResult** - Always return ApiResult shape
|
|
351
|
+
6. **Use wrong RPC naming** - Always follow `data_*` or `app_*` pattern
|
|
352
|
+
|
|
353
|
+
## Tech Stack Checklist
|
|
354
|
+
|
|
355
|
+
Before committing, verify:
|
|
356
|
+
- [ ] Tailwind v4 CSS-first syntax (no @tailwind directives)
|
|
357
|
+
- [ ] No bracket syntax for colors (use theme variables)
|
|
358
|
+
- [ ] Custom color namespaces (main-*, sec-*, acc-*)
|
|
359
|
+
- [ ] React 19+ functional components
|
|
360
|
+
- [ ] Secure Supabase client (useSecureSupabase)
|
|
361
|
+
- [ ] TanStack Query for server state
|
|
362
|
+
- [ ] React Hook Form + Zod for forms
|
|
363
|
+
- [ ] Vite configured correctly (optimizeDeps.exclude, resolve.dedupe)
|
|
364
|
+
- [ ] TypeScript 5+ with strict mode
|
|
365
|
+
- [ ] All versions compatible with pace-core
|
|
366
|
+
- [ ] RPCs follow naming convention (data_* or app_*)
|
|
367
|
+
- [ ] RPCs return ApiResult shape
|
|
368
|
+
- [ ] RPCs enforce RLS
|
|
369
|
+
|
|
370
|
+
## Reference
|
|
371
|
+
|
|
372
|
+
- Tailwind v4: https://tailwindcss.com/blog/tailwindcss-v4
|
|
373
|
+
- React 19: https://react.dev/blog/2024/04/25/react-19-upgrade-guide
|
|
374
|
+
- Supabase: https://supabase.com/docs
|
|
375
|
+
- TanStack Query: https://tanstack.com/query
|
|
376
|
+
- React Hook Form: https://react-hook-form.com
|
|
377
|
+
- Vite: https://vitejs.dev
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce testing standards, documentation requirements, and issue reporting templates
|
|
3
|
+
globs: ["**/*.{test,spec}.{ts,tsx}", "**/*.md", "**/*.mdx"]
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
paceCoreVersion: "0.6.x"
|
|
6
|
+
rulesVersion: "2025-01-28"
|
|
7
|
+
---
|
|
8
|
+
# Testing & Documentation Standards Guide
|
|
9
|
+
|
|
10
|
+
**📚 Human-Readable Standard**: See [8-testing-documentation-standards.md](../../packages/core/docs/standards/8-testing-documentation-standards.md) for complete documentation including coverage requirements, test timeouts, and documentation templates.
|
|
11
|
+
|
|
12
|
+
This guide ensures consistent, high-quality testing and documentation across consuming apps in the PACE suite.
|
|
13
|
+
|
|
14
|
+
## AI Agent Instructions
|
|
15
|
+
|
|
16
|
+
**When writing or modifying tests, ALWAYS:**
|
|
17
|
+
1. **Use React Testing Library** - Always use `@testing-library/react` and `userEvent`, never Enzyme or other libraries
|
|
18
|
+
2. **Test user behavior** - Test what users see and do, not implementation details
|
|
19
|
+
3. **Use accessible queries** - Prefer `getByRole`, `getByLabelText` over `getByTestId`
|
|
20
|
+
4. **Include timeouts** - Always include timeout parameters to prevent tests from hanging
|
|
21
|
+
5. **Colocate tests** - Place test files next to source files (`Component.test.tsx` next to `Component.tsx`)
|
|
22
|
+
6. **Use descriptive names** - Test names should clearly describe the behavior being tested
|
|
23
|
+
7. **Group related tests** - Use `describe` blocks to organize related tests
|
|
24
|
+
|
|
25
|
+
**Decision Tree: Writing Tests**
|
|
26
|
+
```
|
|
27
|
+
1. What am I testing?
|
|
28
|
+
├─ Component → Use React Testing Library + userEvent
|
|
29
|
+
├─ Hook → Test hook in isolation with renderHook
|
|
30
|
+
├─ Utility → Test pure function directly
|
|
31
|
+
└─ Integration → Test user workflows end-to-end
|
|
32
|
+
|
|
33
|
+
2. How do I query elements?
|
|
34
|
+
├─ Interactive element → getByRole (preferred)
|
|
35
|
+
├─ Form field → getByLabelText (preferred)
|
|
36
|
+
├─ Text content → getByText
|
|
37
|
+
└─ Last resort → getByTestId (avoid if possible)
|
|
38
|
+
|
|
39
|
+
3. Is this async?
|
|
40
|
+
├─ YES → Use waitFor with timeout
|
|
41
|
+
└─ NO → Direct assertions
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Testing Patterns
|
|
45
|
+
|
|
46
|
+
### MUST: Use React Testing Library
|
|
47
|
+
|
|
48
|
+
**MUST use React Testing Library + userEvent for all component tests:**
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// ✅ CORRECT: React Testing Library + userEvent
|
|
52
|
+
import { render, screen } from '@testing-library/react';
|
|
53
|
+
import userEvent from '@testing-library/user-event';
|
|
54
|
+
|
|
55
|
+
test('button clicks work', async () => {
|
|
56
|
+
const user = userEvent.setup();
|
|
57
|
+
const handleClick = vi.fn();
|
|
58
|
+
render(<Button onClick={handleClick}>Click me</Button>);
|
|
59
|
+
await user.click(screen.getByRole('button', { name: /click me/i }));
|
|
60
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### MUST: Colocate Tests
|
|
65
|
+
|
|
66
|
+
**Tests MUST be colocated with source files:**
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
src/
|
|
70
|
+
├── components/
|
|
71
|
+
│ └── EventCard/
|
|
72
|
+
│ ├── EventCard.tsx
|
|
73
|
+
│ └── EventCard.test.tsx
|
|
74
|
+
├── hooks/
|
|
75
|
+
│ ├── useEventData.ts
|
|
76
|
+
│ └── useEventData.test.ts
|
|
77
|
+
└── utils/
|
|
78
|
+
├── formatEvent.ts
|
|
79
|
+
└── formatEvent.test.ts
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### MUST: Test User Behavior, Not Implementation
|
|
83
|
+
|
|
84
|
+
**Tests MUST focus on what users see and do:**
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// ❌ WRONG: Testing implementation
|
|
88
|
+
test('calls setState', () => {
|
|
89
|
+
const component = render(<Counter />);
|
|
90
|
+
expect(component.state.count).toBe(0);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// ✅ CORRECT: Testing user behavior
|
|
94
|
+
test('displays count and increments on button click', async () => {
|
|
95
|
+
const user = userEvent.setup();
|
|
96
|
+
render(<Counter />);
|
|
97
|
+
expect(screen.getByText('Count: 0')).toBeInTheDocument();
|
|
98
|
+
await user.click(screen.getByRole('button', { name: /increment/i }));
|
|
99
|
+
expect(screen.getByText('Count: 1')).toBeInTheDocument();
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### MUST: Use Accessible Queries
|
|
104
|
+
|
|
105
|
+
**MUST prefer accessible queries (byRole, byLabelText, etc.):**
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// ✅ CORRECT: Accessible queries
|
|
109
|
+
screen.getByRole('button', { name: /submit/i });
|
|
110
|
+
screen.getByLabelText(/email address/i);
|
|
111
|
+
|
|
112
|
+
// ❌ AVOID: Non-accessible queries (use as last resort)
|
|
113
|
+
screen.getByTestId('submit-button');
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### MUST: Include Timeout Parameters
|
|
117
|
+
|
|
118
|
+
**Tests MUST include timeout parameters to prevent hanging:**
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
// ✅ CORRECT: Include timeout parameters
|
|
122
|
+
test('async operation completes', async () => {
|
|
123
|
+
await waitFor(
|
|
124
|
+
() => expect(screen.getByText('Loaded')).toBeInTheDocument(),
|
|
125
|
+
{ timeout: 5000 }
|
|
126
|
+
);
|
|
127
|
+
}, { timeout: 10000 });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Configure timeouts in `vitest.config.ts`:**
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
export default defineConfig({
|
|
134
|
+
test: {
|
|
135
|
+
testTimeout: 10000, // Default 10 seconds for all tests
|
|
136
|
+
hookTimeout: 10000,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### SHOULD: Test Critical Paths
|
|
142
|
+
|
|
143
|
+
**SHOULD test:**
|
|
144
|
+
- User workflows and interactions
|
|
145
|
+
- Error handling and edge cases
|
|
146
|
+
- Form validation
|
|
147
|
+
- Permission checks (RBAC)
|
|
148
|
+
- Data loading states
|
|
149
|
+
- Error states
|
|
150
|
+
|
|
151
|
+
### SHOULD: Use Descriptive Test Names
|
|
152
|
+
|
|
153
|
+
**Test names SHOULD describe behavior:**
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
// ❌ WRONG - Vague
|
|
157
|
+
test('button works', () => { ... });
|
|
158
|
+
|
|
159
|
+
// ✅ CORRECT - Descriptive
|
|
160
|
+
test('increments counter when increment button is clicked', () => { ... });
|
|
161
|
+
test('displays error message when API call fails', () => { ... });
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### SHOULD: Group Related Tests
|
|
165
|
+
|
|
166
|
+
**SHOULD use `describe` blocks to group related tests:**
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
describe('EventCard', () => {
|
|
170
|
+
describe('rendering', () => {
|
|
171
|
+
test('displays event title', () => { ... });
|
|
172
|
+
test('displays event date', () => { ... });
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('interactions', () => {
|
|
176
|
+
test('calls onEdit when edit button clicked', () => { ... });
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Coverage Requirements
|
|
182
|
+
|
|
183
|
+
**Note**: Coverage threshold enforcement is handled by CI/ESLint. See [8-testing-documentation-standards.md](../../packages/core/docs/standards/8-testing-documentation-standards.md) for complete coverage requirements.
|
|
184
|
+
|
|
185
|
+
**MUST achieve:**
|
|
186
|
+
- ≥90% coverage for utils & hooks
|
|
187
|
+
- ≥70% coverage for components
|
|
188
|
+
|
|
189
|
+
**MUST configure test runner to enforce thresholds:**
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// vitest.config.ts
|
|
193
|
+
export default defineConfig({
|
|
194
|
+
test: {
|
|
195
|
+
coverage: {
|
|
196
|
+
thresholds: {
|
|
197
|
+
lines: 80,
|
|
198
|
+
functions: 80,
|
|
199
|
+
branches: 80,
|
|
200
|
+
statements: 80,
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Documentation Requirements
|
|
208
|
+
|
|
209
|
+
### MUST: Document Public APIs
|
|
210
|
+
|
|
211
|
+
**MUST document all public functions, components, and hooks:**
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
/**
|
|
215
|
+
* Fetches event data for a given event ID.
|
|
216
|
+
*
|
|
217
|
+
* @param eventId - The unique identifier for the event
|
|
218
|
+
* @returns Event data or null if not found
|
|
219
|
+
* @throws {Error} If eventId is invalid
|
|
220
|
+
*/
|
|
221
|
+
export async function fetchEvent(eventId: string): Promise<Event | null> {
|
|
222
|
+
// Implementation
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### MUST: Include Usage Examples
|
|
227
|
+
|
|
228
|
+
**MUST include usage examples in documentation:**
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
/**
|
|
232
|
+
* Example usage:
|
|
233
|
+
* ```tsx
|
|
234
|
+
* const { event, isLoading } = useEventData('event-123');
|
|
235
|
+
* if (isLoading) return <Loading />;
|
|
236
|
+
* return <EventCard event={event} />;
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### SHOULD: Document Complex Logic
|
|
242
|
+
|
|
243
|
+
**SHOULD document complex logic and business rules:**
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
// Calculate event duration, accounting for timezone differences
|
|
247
|
+
// Events can span multiple days, so we need to handle day boundaries
|
|
248
|
+
function calculateDuration(start: Date, end: Date): number {
|
|
249
|
+
// Implementation
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Bug Reports & Feature Requests
|
|
254
|
+
|
|
255
|
+
**Note**: Complete templates are in [8-testing-documentation-standards.md](../../packages/core/docs/standards/8-testing-documentation-standards.md). Use these patterns when creating issues.
|
|
256
|
+
|
|
257
|
+
### Bug Report Checklist
|
|
258
|
+
|
|
259
|
+
Before filing a bug report:
|
|
260
|
+
- [ ] Issue hasn't been reported already
|
|
261
|
+
- [ ] Using latest pace-core version
|
|
262
|
+
- [ ] Issue is in pace-core (not your app)
|
|
263
|
+
- [ ] Checked documentation
|
|
264
|
+
- [ ] Have minimal reproduction
|
|
265
|
+
- [ ] Included all required information
|
|
266
|
+
|
|
267
|
+
### Feature Request Checklist
|
|
268
|
+
|
|
269
|
+
Before filing a feature request:
|
|
270
|
+
- [ ] Feature doesn't already exist
|
|
271
|
+
- [ ] Checked if workaround exists
|
|
272
|
+
- [ ] Clear problem statement
|
|
273
|
+
- [ ] Proposed solution described
|
|
274
|
+
- [ ] Real-world use case provided
|
|
275
|
+
- [ ] Alternatives considered
|
|
276
|
+
|
|
277
|
+
## Common Mistakes to Avoid
|
|
278
|
+
|
|
279
|
+
**When writing tests, NEVER:**
|
|
280
|
+
1. **Test implementation details** - Always test user behavior
|
|
281
|
+
```tsx
|
|
282
|
+
// ❌ WRONG
|
|
283
|
+
test('calls setState', () => {
|
|
284
|
+
const component = render(<Counter />);
|
|
285
|
+
expect(component.state.count).toBe(0);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// ✅ CORRECT
|
|
289
|
+
test('displays count and increments on button click', async () => {
|
|
290
|
+
const user = userEvent.setup();
|
|
291
|
+
render(<Counter />);
|
|
292
|
+
expect(screen.getByText('Count: 0')).toBeInTheDocument();
|
|
293
|
+
await user.click(screen.getByRole('button', { name: /increment/i }));
|
|
294
|
+
expect(screen.getByText('Count: 1')).toBeInTheDocument();
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
2. **Use getByTestId as first choice** - Always prefer accessible queries (getByRole, getByLabelText)
|
|
299
|
+
3. **Skip timeouts** - Always include timeout parameters to prevent hanging
|
|
300
|
+
4. **Place tests in separate directory** - Always colocate tests with source files
|
|
301
|
+
5. **Use vague test names** - Always use descriptive names that explain behavior
|
|
302
|
+
|
|
303
|
+
## Testing Checklist
|
|
304
|
+
|
|
305
|
+
Before committing tests, verify:
|
|
306
|
+
- [ ] Coverage meets requirements (≥90% utils, ≥70% components)
|
|
307
|
+
- [ ] Using React Testing Library + userEvent
|
|
308
|
+
- [ ] Tests are colocated with source files
|
|
309
|
+
- [ ] Testing user behavior, not implementation
|
|
310
|
+
- [ ] Using accessible queries (byRole, byLabelText)
|
|
311
|
+
- [ ] Test names are descriptive
|
|
312
|
+
- [ ] Related tests grouped with describe
|
|
313
|
+
- [ ] No unnecessary mocks
|
|
314
|
+
- [ ] Async code tested properly
|
|
315
|
+
- [ ] Cleanup after tests
|
|
316
|
+
- [ ] Timeout parameters included
|
|
317
|
+
|
|
318
|
+
## Reference
|
|
319
|
+
|
|
320
|
+
**Note**: Coverage threshold enforcement and detailed test configuration are handled by CI/ESLint. See [8-testing-documentation-standards.md](../../packages/core/docs/standards/8-testing-documentation-standards.md) for complete enforcement details.
|
|
321
|
+
|
|
322
|
+
- React Testing Library: https://testing-library.com/react
|
|
323
|
+
- Vitest: https://vitest.dev
|
|
324
|
+
- Complete templates: [8-testing-documentation-standards.md](../../packages/core/docs/standards/8-testing-documentation-standards.md)
|