@jmruthers/pace-core 0.6.4 → 0.6.6
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/core-usage-manifest.json +93 -0
- package/cursor-rules/00-pace-core-compliance.mdc +128 -26
- package/cursor-rules/01-standards-compliance.mdc +49 -8
- package/cursor-rules/02-project-structure.mdc +6 -0
- package/cursor-rules/03-solid-principles.mdc +2 -0
- package/cursor-rules/04-testing-standards.mdc +2 -0
- package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
- package/cursor-rules/06-code-quality.mdc +2 -0
- package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
- package/cursor-rules/08-markup-quality.mdc +52 -27
- package/cursor-rules/09-rbac-compliance.mdc +462 -0
- package/cursor-rules/10-error-handling-patterns.mdc +179 -0
- package/cursor-rules/11-performance-optimization.mdc +169 -0
- package/cursor-rules/12-ci-cd-integration.mdc +150 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
- package/dist/DataTable-LRJL4IRV.js +15 -0
- package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
- package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
- package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/chunk-4T7OBVTU.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-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
- package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
- package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
- package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/chunk-OHIK3MIO.js +994 -0
- package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
- package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
- package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
- package/dist/components.d.ts +6 -6
- package/dist/components.js +57 -267
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +22 -0
- package/dist/eslint-rules/rules/compliance.cjs +348 -0
- package/dist/eslint-rules/rules/components.cjs +113 -0
- package/dist/eslint-rules/rules/imports.cjs +102 -0
- package/dist/eslint-rules/rules/rbac.cjs +790 -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 +5 -5
- package/dist/hooks.js +62 -270
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +36 -26
- package/dist/index.js +87 -690
- 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 +124 -594
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- 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-B-K_5VnO.d.ts} +4 -0
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +16 -6
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +454 -930
- package/docs/api-reference/components.md +3 -1
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/best-practices/accessibility.md +6 -3
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/permission-enforcement.md +4 -0
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +12 -3
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/secure-client-protection.md +0 -34
- package/docs/standards/00-pace-core-compliance.md +967 -0
- package/docs/standards/01-standards-compliance.md +188 -0
- package/docs/standards/02-project-structure.md +985 -0
- package/docs/standards/03-solid-principles.md +39 -0
- package/docs/standards/04-testing-standards.md +36 -0
- package/docs/standards/05-bug-reports-and-features.md +27 -0
- package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
- package/docs/standards/07-tech-stack-compliance.md +30 -0
- package/docs/standards/08-markup-quality.md +345 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
- package/docs/standards/10-error-handling-patterns.md +401 -0
- package/docs/standards/11-performance-optimization.md +348 -0
- package/docs/standards/12-ci-cd-integration.md +370 -0
- package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
- package/docs/standards/README.md +62 -33
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +20 -4
- package/package.json +31 -21
- package/scripts/audit/audit-compliance.cjs +1295 -0
- package/scripts/audit/audit-components.cjs +260 -0
- package/scripts/audit/audit-dependencies.cjs +395 -0
- package/scripts/audit/audit-rbac.cjs +954 -0
- package/scripts/audit/audit-standards.cjs +1268 -0
- package/scripts/audit/index.cjs +1898 -194
- package/scripts/install-cursor-rules.cjs +259 -8
- package/scripts/validate-master.js +1 -1
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
- 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-utils.test.tsx +3 -3
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/ContextSelector/ContextSelector.tsx +42 -39
- package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
- package/src/components/DataTable/components/DataTableBody.tsx +55 -31
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +7 -2
- package/src/components/DataTable/components/ImportModal.tsx +4 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/core/DataTableContext.tsx +1 -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 -0
- package/src/components/DateTimeField/DateTimeField.tsx +20 -20
- package/src/components/DateTimeField/README.md +5 -2
- package/src/components/Dialog/Dialog.test.tsx +361 -318
- package/src/components/Dialog/Dialog.tsx +1154 -323
- package/src/components/Dialog/index.ts +3 -3
- package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
- package/src/components/FileDisplay/FileDisplay.tsx +28 -22
- package/src/components/Form/Form.test.tsx +9 -10
- package/src/components/Form/Form.tsx +369 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
- package/src/components/LoginForm/LoginForm.tsx +2 -2
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
- package/src/components/PaceAppLayout/README.md +10 -9
- package/src/components/PaceAppLayout/test-setup.tsx +40 -31
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
- package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
- package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
- package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
- package/src/components/Select/Select.tsx +23 -21
- package/src/components/Select/types.ts +1 -1
- package/src/components/UserMenu/UserMenu.test.tsx +38 -6
- package/src/components/UserMenu/UserMenu.tsx +39 -34
- package/src/components/index.ts +3 -4
- package/src/eslint-rules/index.cjs +22 -0
- package/src/eslint-rules/rules/compliance.cjs +348 -0
- package/src/eslint-rules/rules/components.cjs +113 -0
- package/src/eslint-rules/rules/imports.cjs +102 -0
- package/src/eslint-rules/rules/rbac.cjs +790 -0
- package/src/eslint-rules/utils/helpers.cjs +42 -0
- package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- 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 +62 -190
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +19 -9
- package/src/hooks/useAppConfig.ts +26 -24
- package/src/hooks/useEventTheme.test.ts +211 -233
- package/src/hooks/useEventTheme.ts +19 -28
- package/src/hooks/useEvents.ts +11 -7
- package/src/hooks/useKeyboardShortcuts.ts +1 -1
- package/src/hooks/useOrganisationPermissions.ts +9 -11
- package/src/hooks/useOrganisations.ts +13 -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 +16 -1
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
- package/src/rbac/README.md +20 -20
- 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/useRBAC.test.ts +21 -3
- package/src/rbac/hooks/useRBAC.ts +4 -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 +241 -60
- package/src/rbac/hooks/useResourcePermissions.ts +182 -63
- 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/permissions.ts +17 -17
- package/src/rbac/utils/contextValidator.ts +45 -7
- package/src/services/AuthService.ts +132 -23
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +155 -58
- 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 +4 -0
- package/src/types/database.generated.ts +4733 -3809
- 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/formatting/formatTime.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/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/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-E7YQZD7D.js +0 -175
- package/dist/DataTable-E7YQZD7D.js.map +0 -1
- package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
- package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
- package/dist/api-6LVZTHDS.js +0 -52
- package/dist/api-6LVZTHDS.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-36LVWXB2.js +0 -227
- package/dist/chunk-36LVWXB2.js.map +0 -1
- package/dist/chunk-3LPHPB62.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-5EC5MEWX.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6SOIHG6Z.js.map +0 -1
- package/dist/chunk-7JPAB3T5.js.map +0 -1
- package/dist/chunk-ATKZM7RX.js +0 -2053
- package/dist/chunk-ATKZM7RX.js.map +0 -1
- package/dist/chunk-AVMLPIM7.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.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-I6DAQMWX.js.map +0 -1
- package/dist/chunk-J36DSWQK.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-NN6WWZ5U.js.map +0 -1
- package/dist/chunk-OEWDTMG7.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-YKRAFF5K.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-OOPCLPZW.js +0 -9
- package/dist/contextValidator-OOPCLPZW.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/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/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/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/eslint-rules/pace-core-compliance.cjs +0 -510
- 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,348 @@
|
|
|
1
|
+
# Performance Optimization Guide
|
|
2
|
+
|
|
3
|
+
**🤖 Cursor Rule**: See [11-performance-optimization.mdc](../../cursor-rules/11-performance-optimization.mdc) for AI-optimized directives that automatically enforce performance best practices.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This standard defines performance optimization patterns and best practices to ensure:
|
|
8
|
+
- **Fast page loads** and responsive user interfaces
|
|
9
|
+
- **Efficient database queries** with proper RLS optimization
|
|
10
|
+
- **Optimized React rendering** with proper memoization
|
|
11
|
+
- **Effective caching strategies** for server state
|
|
12
|
+
- **Minimal bundle sizes** and code splitting
|
|
13
|
+
|
|
14
|
+
## Principles
|
|
15
|
+
|
|
16
|
+
1. **Measure before optimizing** - Profile and identify bottlenecks
|
|
17
|
+
2. **Optimize critical paths first** - Focus on user-facing performance
|
|
18
|
+
3. **Use appropriate caching** - Balance freshness with performance
|
|
19
|
+
4. **Minimize re-renders** - Use React optimization techniques
|
|
20
|
+
5. **Optimize database queries** - Use helper functions, avoid N+1 queries
|
|
21
|
+
|
|
22
|
+
## React Performance
|
|
23
|
+
|
|
24
|
+
### Memoization
|
|
25
|
+
|
|
26
|
+
**Use `useMemo` for expensive computations:**
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
// ✅ CORRECT - Memoize expensive computation
|
|
30
|
+
const expensiveValue = useMemo(() => {
|
|
31
|
+
return computeExpensiveValue(data);
|
|
32
|
+
}, [data]);
|
|
33
|
+
|
|
34
|
+
// ❌ WRONG - Recomputes on every render
|
|
35
|
+
const expensiveValue = computeExpensiveValue(data);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Use `useCallback` for stable function references:**
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
// ✅ CORRECT - Stable callback reference
|
|
42
|
+
const handleClick = useCallback(() => {
|
|
43
|
+
doSomething(id);
|
|
44
|
+
}, [id]);
|
|
45
|
+
|
|
46
|
+
// ❌ WRONG - New function on every render
|
|
47
|
+
const handleClick = () => {
|
|
48
|
+
doSomething(id);
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Use `React.memo` for expensive components:**
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// ✅ CORRECT - Memoize component
|
|
56
|
+
const ExpensiveComponent = React.memo(({ data }) => {
|
|
57
|
+
return <div>{/* expensive rendering */}</div>;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// ❌ WRONG - Re-renders unnecessarily
|
|
61
|
+
function ExpensiveComponent({ data }) {
|
|
62
|
+
return <div>{/* expensive rendering */}</div>;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Avoiding Unnecessary Re-renders
|
|
67
|
+
|
|
68
|
+
**Don't create new objects/arrays in render:**
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
// ❌ WRONG - New object on every render
|
|
72
|
+
function Component({ items }) {
|
|
73
|
+
const config = { items, enabled: true };
|
|
74
|
+
return <Child config={config} />;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ✅ CORRECT - Memoize object
|
|
78
|
+
function Component({ items }) {
|
|
79
|
+
const config = useMemo(() => ({ items, enabled: true }), [items]);
|
|
80
|
+
return <Child config={config} />;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Code Splitting
|
|
85
|
+
|
|
86
|
+
**Lazy load heavy components:**
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
// ✅ CORRECT - Lazy load
|
|
90
|
+
import { lazy, Suspense } from 'react';
|
|
91
|
+
const HeavyComponent = lazy(() => import('./HeavyComponent'));
|
|
92
|
+
|
|
93
|
+
function App() {
|
|
94
|
+
return (
|
|
95
|
+
<Suspense fallback={<Loading />}>
|
|
96
|
+
<HeavyComponent />
|
|
97
|
+
</Suspense>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Database Performance
|
|
103
|
+
|
|
104
|
+
### RLS Policy Optimization
|
|
105
|
+
|
|
106
|
+
**MUST use helper functions (STABLE SECURITY DEFINER):**
|
|
107
|
+
|
|
108
|
+
```sql
|
|
109
|
+
-- ✅ CORRECT - Helper function (evaluated once)
|
|
110
|
+
CREATE POLICY "rbac_select_users" ON users FOR SELECT USING (
|
|
111
|
+
check_user_organisation_access(organisation_id)
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
-- ❌ WRONG - Subquery (evaluated per row)
|
|
115
|
+
CREATE POLICY "rbac_select_users" ON users FOR SELECT USING (
|
|
116
|
+
organisation_id IN (SELECT organisation_id FROM organisation_memberships WHERE user_id = auth.uid())
|
|
117
|
+
);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**MUST avoid InitPlan nodes:**
|
|
121
|
+
|
|
122
|
+
```sql
|
|
123
|
+
-- ❌ WRONG - Causes InitPlan (severe performance degradation)
|
|
124
|
+
CREATE POLICY "bad_policy" ON table_name FOR SELECT USING (
|
|
125
|
+
user_id = auth.uid() -- Called for every row!
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
-- ✅ CORRECT - Helper function
|
|
129
|
+
CREATE POLICY "good_policy" ON table_name FOR SELECT USING (
|
|
130
|
+
get_effective_user_id() = user_id -- Evaluated once
|
|
131
|
+
);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Query Optimization
|
|
135
|
+
|
|
136
|
+
**Use indexes for frequently queried columns:**
|
|
137
|
+
|
|
138
|
+
```sql
|
|
139
|
+
-- ✅ CORRECT - Index on frequently queried column
|
|
140
|
+
CREATE INDEX idx_users_organisation_id ON users(organisation_id);
|
|
141
|
+
CREATE INDEX idx_events_organisation_id_event_id ON events(organisation_id, event_id);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Avoid N+1 queries:**
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
// ❌ WRONG - N+1 queries
|
|
148
|
+
const events = await fetchEvents();
|
|
149
|
+
for (const event of events) {
|
|
150
|
+
const users = await fetchEventUsers(event.id); // N queries!
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ✅ CORRECT - Single query with join
|
|
154
|
+
const eventsWithUsers = await fetchEventsWithUsers(); // 1 query
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Use RPC functions for complex queries:**
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
// ✅ CORRECT - RPC for complex query
|
|
161
|
+
const { data } = await supabase.rpc('data_events_list', {
|
|
162
|
+
organisation_id: orgId
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// ❌ AVOID - Complex client-side query
|
|
166
|
+
const { data } = await supabase
|
|
167
|
+
.from('events')
|
|
168
|
+
.select('*, users(*), organisations(*)')
|
|
169
|
+
.eq('organisation_id', orgId);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Caching Strategies
|
|
173
|
+
|
|
174
|
+
### TanStack Query Configuration
|
|
175
|
+
|
|
176
|
+
**Configure appropriate cache times:**
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
// ✅ CORRECT - Configure cache
|
|
180
|
+
const queryClient = new QueryClient({
|
|
181
|
+
defaultOptions: {
|
|
182
|
+
queries: {
|
|
183
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
184
|
+
cacheTime: 10 * 60 * 1000, // 10 minutes
|
|
185
|
+
retry: 1,
|
|
186
|
+
refetchOnWindowFocus: false, // Prevent unnecessary refetches
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Use query keys effectively:**
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
// ✅ CORRECT - Specific query keys
|
|
196
|
+
const { data } = useQuery({
|
|
197
|
+
queryKey: ['events', organisationId, eventId],
|
|
198
|
+
queryFn: () => fetchEvent(organisationId, eventId),
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// ❌ WRONG - Too generic
|
|
202
|
+
const { data } = useQuery({
|
|
203
|
+
queryKey: ['events'],
|
|
204
|
+
queryFn: () => fetchEvent(organisationId, eventId),
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### React Query Optimizations
|
|
209
|
+
|
|
210
|
+
**Use `keepPreviousData` for pagination:**
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
// ✅ CORRECT - Keep previous data during pagination
|
|
214
|
+
const { data } = useQuery({
|
|
215
|
+
queryKey: ['events', page],
|
|
216
|
+
queryFn: () => fetchEvents(page),
|
|
217
|
+
keepPreviousData: true,
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Use `select` to transform data efficiently:**
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
// ✅ CORRECT - Transform in select (only runs when data changes)
|
|
225
|
+
const { data: eventCount } = useQuery({
|
|
226
|
+
queryKey: ['events'],
|
|
227
|
+
queryFn: fetchEvents,
|
|
228
|
+
select: (data) => data.length,
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Bundle Size Optimization
|
|
233
|
+
|
|
234
|
+
### Tree Shaking
|
|
235
|
+
|
|
236
|
+
**Use named imports:**
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
// ✅ CORRECT - Tree-shakeable
|
|
240
|
+
import { Button, Card } from '@jmruthers/pace-core';
|
|
241
|
+
|
|
242
|
+
// ❌ WRONG - Imports entire library
|
|
243
|
+
import * as PaceCore from '@jmruthers/pace-core';
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Dynamic Imports
|
|
247
|
+
|
|
248
|
+
**Lazy load heavy dependencies:**
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
// ✅ CORRECT - Dynamic import
|
|
252
|
+
const HeavyLibrary = lazy(() => import('heavy-library'));
|
|
253
|
+
|
|
254
|
+
// ❌ WRONG - Eager import
|
|
255
|
+
import HeavyLibrary from 'heavy-library';
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Performance Monitoring
|
|
259
|
+
|
|
260
|
+
### Measuring Performance
|
|
261
|
+
|
|
262
|
+
**Use React DevTools Profiler:**
|
|
263
|
+
|
|
264
|
+
1. Open React DevTools
|
|
265
|
+
2. Go to Profiler tab
|
|
266
|
+
3. Record a session
|
|
267
|
+
4. Identify slow components
|
|
268
|
+
5. Optimize based on findings
|
|
269
|
+
|
|
270
|
+
**Use browser DevTools:**
|
|
271
|
+
|
|
272
|
+
1. Open Performance tab
|
|
273
|
+
2. Record page load
|
|
274
|
+
3. Identify bottlenecks
|
|
275
|
+
4. Optimize critical rendering path
|
|
276
|
+
|
|
277
|
+
### Performance Metrics
|
|
278
|
+
|
|
279
|
+
**Track these metrics:**
|
|
280
|
+
|
|
281
|
+
- **Time to First Byte (TTFB)** - < 200ms
|
|
282
|
+
- **First Contentful Paint (FCP)** - < 1.8s
|
|
283
|
+
- **Largest Contentful Paint (LCP)** - < 2.5s
|
|
284
|
+
- **Time to Interactive (TTI)** - < 3.8s
|
|
285
|
+
- **Cumulative Layout Shift (CLS)** - < 0.1
|
|
286
|
+
|
|
287
|
+
## Performance Checklist
|
|
288
|
+
|
|
289
|
+
Before committing performance-sensitive code, verify:
|
|
290
|
+
|
|
291
|
+
- [ ] Expensive computations memoized with `useMemo`
|
|
292
|
+
- [ ] Callbacks stable with `useCallback`
|
|
293
|
+
- [ ] Components memoized with `React.memo` when appropriate
|
|
294
|
+
- [ ] No new objects/arrays created in render
|
|
295
|
+
- [ ] Heavy components lazy loaded
|
|
296
|
+
- [ ] RLS policies use helper functions (no subqueries)
|
|
297
|
+
- [ ] Queries use indexes appropriately
|
|
298
|
+
- [ ] No N+1 query patterns
|
|
299
|
+
- [ ] TanStack Query configured with appropriate cache times
|
|
300
|
+
- [ ] Bundle size optimized (tree shaking, code splitting)
|
|
301
|
+
- [ ] Performance metrics measured and acceptable
|
|
302
|
+
|
|
303
|
+
## Common Performance Pitfalls
|
|
304
|
+
|
|
305
|
+
### ❌ Don't: Create New Objects in Render
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
// ❌ WRONG
|
|
309
|
+
function Component({ items }) {
|
|
310
|
+
return <Child config={{ items, enabled: true }} />; // New object every render
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### ❌ Don't: Use Inline Functions
|
|
315
|
+
|
|
316
|
+
```tsx
|
|
317
|
+
// ❌ WRONG
|
|
318
|
+
<Button onClick={() => handleClick(id)}>Click</Button> // New function every render
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### ❌ Don't: Over-Memoize
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
// ❌ WRONG - Memoizing simple computation
|
|
325
|
+
const simpleValue = useMemo(() => items.length, [items]); // Unnecessary
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### ❌ Don't: Use Subqueries in RLS
|
|
329
|
+
|
|
330
|
+
```sql
|
|
331
|
+
-- ❌ WRONG - N+1 performance issue
|
|
332
|
+
CREATE POLICY "bad" ON table FOR SELECT USING (
|
|
333
|
+
organisation_id IN (SELECT ... FROM ... WHERE user_id = auth.uid())
|
|
334
|
+
);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Related Documentation
|
|
338
|
+
|
|
339
|
+
- [RLS Standard](./09-rbac-compliance.md) - RLS performance requirements
|
|
340
|
+
- [Code Quality Standard](./06-code-quality.md) - React performance patterns
|
|
341
|
+
- [Tech Stack Standard](./07-tech-stack-compliance.md) - TanStack Query configuration
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
**Last Updated:** 2025-01-28
|
|
346
|
+
**Version:** 1.0.0
|
|
347
|
+
**Applies to:** All pace-core and consuming apps
|
|
348
|
+
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# CI/CD Integration Guide
|
|
2
|
+
|
|
3
|
+
**🤖 Cursor Rule**: See [12-ci-cd-integration.mdc](../../cursor-rules/12-ci-cd-integration.mdc) for AI-optimized directives that automatically enforce CI/CD best practices.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This standard defines CI/CD integration patterns and best practices to ensure:
|
|
8
|
+
- **Automated quality checks** on every commit
|
|
9
|
+
- **Consistent deployment processes** across environments
|
|
10
|
+
- **Proper testing** before deployment
|
|
11
|
+
- **Security scanning** and compliance checks
|
|
12
|
+
- **Efficient build and deployment** pipelines
|
|
13
|
+
|
|
14
|
+
## Principles
|
|
15
|
+
|
|
16
|
+
1. **Automate everything** - Manual steps are error-prone
|
|
17
|
+
2. **Fail fast** - Catch issues early in the pipeline
|
|
18
|
+
3. **Test before deploy** - Never deploy untested code
|
|
19
|
+
4. **Security first** - Scan for vulnerabilities
|
|
20
|
+
5. **Consistent environments** - Dev, staging, production parity
|
|
21
|
+
|
|
22
|
+
## CI/CD Pipeline Structure
|
|
23
|
+
|
|
24
|
+
### Standard Pipeline Stages
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
1. Lint & Format Check
|
|
28
|
+
2. Type Check
|
|
29
|
+
3. Unit Tests
|
|
30
|
+
4. Integration Tests
|
|
31
|
+
5. Build
|
|
32
|
+
6. Security Scan
|
|
33
|
+
7. Deploy (staging/production)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## GitHub Actions Example
|
|
37
|
+
|
|
38
|
+
### Basic Workflow
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
# .github/workflows/ci.yml
|
|
42
|
+
name: CI
|
|
43
|
+
|
|
44
|
+
on:
|
|
45
|
+
push:
|
|
46
|
+
branches: [main, develop]
|
|
47
|
+
pull_request:
|
|
48
|
+
branches: [main, develop]
|
|
49
|
+
|
|
50
|
+
jobs:
|
|
51
|
+
quality-checks:
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
|
|
56
|
+
- name: Setup Node.js
|
|
57
|
+
uses: actions/setup-node@v4
|
|
58
|
+
with:
|
|
59
|
+
node-version: '20'
|
|
60
|
+
cache: 'npm'
|
|
61
|
+
|
|
62
|
+
- name: Install dependencies
|
|
63
|
+
run: npm ci
|
|
64
|
+
|
|
65
|
+
- name: Lint
|
|
66
|
+
run: npm run lint
|
|
67
|
+
|
|
68
|
+
- name: Type check
|
|
69
|
+
run: npm run type-check
|
|
70
|
+
|
|
71
|
+
- name: Format check
|
|
72
|
+
run: npm run format:check
|
|
73
|
+
|
|
74
|
+
- name: Run tests
|
|
75
|
+
run: npm run test
|
|
76
|
+
|
|
77
|
+
- name: Build
|
|
78
|
+
run: npm run build
|
|
79
|
+
|
|
80
|
+
- name: Security scan
|
|
81
|
+
run: npm audit --audit-level=moderate
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Advanced Workflow with Deployment
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
# .github/workflows/deploy.yml
|
|
88
|
+
name: Deploy
|
|
89
|
+
|
|
90
|
+
on:
|
|
91
|
+
push:
|
|
92
|
+
branches: [main]
|
|
93
|
+
workflow_dispatch:
|
|
94
|
+
|
|
95
|
+
jobs:
|
|
96
|
+
test:
|
|
97
|
+
runs-on: ubuntu-latest
|
|
98
|
+
steps:
|
|
99
|
+
- uses: actions/checkout@v4
|
|
100
|
+
- uses: actions/setup-node@v4
|
|
101
|
+
with:
|
|
102
|
+
node-version: '20'
|
|
103
|
+
cache: 'npm'
|
|
104
|
+
- run: npm ci
|
|
105
|
+
- run: npm run test
|
|
106
|
+
- run: npm run build
|
|
107
|
+
|
|
108
|
+
deploy-staging:
|
|
109
|
+
needs: test
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
environment: staging
|
|
112
|
+
steps:
|
|
113
|
+
- uses: actions/checkout@v4
|
|
114
|
+
- uses: actions/setup-node@v4
|
|
115
|
+
with:
|
|
116
|
+
node-version: '20'
|
|
117
|
+
- run: npm ci
|
|
118
|
+
- run: npm run build
|
|
119
|
+
- name: Deploy to Staging
|
|
120
|
+
run: |
|
|
121
|
+
# Your deployment script
|
|
122
|
+
echo "Deploying to staging..."
|
|
123
|
+
|
|
124
|
+
deploy-production:
|
|
125
|
+
needs: test
|
|
126
|
+
runs-on: ubuntu-latest
|
|
127
|
+
environment: production
|
|
128
|
+
if: github.ref == 'refs/heads/main'
|
|
129
|
+
steps:
|
|
130
|
+
- uses: actions/checkout@v4
|
|
131
|
+
- uses: actions/setup-node@v4
|
|
132
|
+
with:
|
|
133
|
+
node-version: '20'
|
|
134
|
+
- run: npm ci
|
|
135
|
+
- run: npm run build
|
|
136
|
+
- name: Deploy to Production
|
|
137
|
+
run: |
|
|
138
|
+
# Your deployment script
|
|
139
|
+
echo "Deploying to production..."
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Required CI Checks
|
|
143
|
+
|
|
144
|
+
### MUST: Run These Checks
|
|
145
|
+
|
|
146
|
+
**Every CI pipeline MUST include:**
|
|
147
|
+
|
|
148
|
+
1. **Linting** - ESLint with pace-core rules
|
|
149
|
+
```yaml
|
|
150
|
+
- name: Lint
|
|
151
|
+
run: npm run lint
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
2. **Type Checking** - TypeScript compilation
|
|
155
|
+
```yaml
|
|
156
|
+
- name: Type check
|
|
157
|
+
run: npx tsc --noEmit
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
3. **Testing** - Unit and integration tests
|
|
161
|
+
```yaml
|
|
162
|
+
- name: Run tests
|
|
163
|
+
run: npm run test
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
4. **Build** - Verify build succeeds
|
|
167
|
+
```yaml
|
|
168
|
+
- name: Build
|
|
169
|
+
run: npm run build
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
### SHOULD: Run These Checks
|
|
174
|
+
|
|
175
|
+
**Recommended additional checks:**
|
|
176
|
+
|
|
177
|
+
1. **Format Check** - Prettier or similar
|
|
178
|
+
```yaml
|
|
179
|
+
- name: Format check
|
|
180
|
+
run: npm run format:check
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
2. **Security Scan** - npm audit or Snyk
|
|
184
|
+
```yaml
|
|
185
|
+
- name: Security scan
|
|
186
|
+
run: npm audit --audit-level=moderate
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
3. **Coverage Check** - Test coverage thresholds
|
|
190
|
+
```yaml
|
|
191
|
+
- name: Coverage check
|
|
192
|
+
run: npm run test:coverage
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Package.json Scripts
|
|
196
|
+
|
|
197
|
+
### Required Scripts
|
|
198
|
+
|
|
199
|
+
**MUST have these scripts in `package.json`:**
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"scripts": {
|
|
204
|
+
"lint": "eslint .",
|
|
205
|
+
"lint:fix": "eslint . --fix",
|
|
206
|
+
"type-check": "tsc --noEmit",
|
|
207
|
+
"test": "vitest run",
|
|
208
|
+
"test:watch": "vitest",
|
|
209
|
+
"test:coverage": "vitest run --coverage",
|
|
210
|
+
"build": "vite build",
|
|
211
|
+
"format": "prettier --write .",
|
|
212
|
+
"format:check": "prettier --check ."
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Environment Variables
|
|
218
|
+
|
|
219
|
+
### CI/CD Secrets
|
|
220
|
+
|
|
221
|
+
**Store sensitive values as secrets:**
|
|
222
|
+
|
|
223
|
+
```yaml
|
|
224
|
+
# .github/workflows/deploy.yml
|
|
225
|
+
env:
|
|
226
|
+
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
|
|
227
|
+
SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
|
|
228
|
+
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
|
|
229
|
+
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Never commit secrets to repository:**
|
|
233
|
+
- Use GitHub Secrets
|
|
234
|
+
- Use environment-specific config files
|
|
235
|
+
- Use `.env.example` for documentation
|
|
236
|
+
|
|
237
|
+
## Database Migrations in CI/CD
|
|
238
|
+
|
|
239
|
+
### Migration Strategy
|
|
240
|
+
|
|
241
|
+
**For Supabase migrations:**
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
- name: Run migrations
|
|
245
|
+
run: |
|
|
246
|
+
npx supabase db push
|
|
247
|
+
# Or use Supabase CLI
|
|
248
|
+
supabase migration up
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Best Practices:**
|
|
252
|
+
- Run migrations in staging first
|
|
253
|
+
- Test migrations in CI
|
|
254
|
+
- Never run destructive migrations automatically
|
|
255
|
+
- Use migration review process
|
|
256
|
+
|
|
257
|
+
## Deployment Strategies
|
|
258
|
+
|
|
259
|
+
### Staging Deployment
|
|
260
|
+
|
|
261
|
+
**Deploy to staging on every merge to `develop`:**
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
deploy-staging:
|
|
265
|
+
if: github.ref == 'refs/heads/develop'
|
|
266
|
+
environment: staging
|
|
267
|
+
steps:
|
|
268
|
+
- name: Deploy to Staging
|
|
269
|
+
run: |
|
|
270
|
+
# Deploy to staging environment
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Production Deployment
|
|
274
|
+
|
|
275
|
+
**Deploy to production only from `main` branch:**
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
deploy-production:
|
|
279
|
+
if: github.ref == 'refs/heads/main'
|
|
280
|
+
environment: production
|
|
281
|
+
steps:
|
|
282
|
+
- name: Deploy to Production
|
|
283
|
+
run: |
|
|
284
|
+
# Deploy to production environment
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Manual Deployment
|
|
288
|
+
|
|
289
|
+
**Allow manual deployment via workflow_dispatch:**
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
on:
|
|
293
|
+
workflow_dispatch:
|
|
294
|
+
inputs:
|
|
295
|
+
environment:
|
|
296
|
+
description: 'Environment to deploy to'
|
|
297
|
+
required: true
|
|
298
|
+
type: choice
|
|
299
|
+
options:
|
|
300
|
+
- staging
|
|
301
|
+
- production
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## CI/CD Checklist
|
|
305
|
+
|
|
306
|
+
Before setting up CI/CD, verify:
|
|
307
|
+
|
|
308
|
+
- [ ] Lint check configured
|
|
309
|
+
- [ ] Type check configured
|
|
310
|
+
- [ ] Tests run in CI
|
|
311
|
+
- [ ] Build succeeds in CI
|
|
312
|
+
- [ ] Security scan configured
|
|
313
|
+
- [ ] Environment variables set as secrets
|
|
314
|
+
- [ ] Staging deployment configured
|
|
315
|
+
- [ ] Production deployment configured
|
|
316
|
+
- [ ] Migration strategy defined
|
|
317
|
+
- [ ] Rollback plan documented
|
|
318
|
+
|
|
319
|
+
## Common CI/CD Issues
|
|
320
|
+
|
|
321
|
+
### Issue: Tests Fail in CI but Pass Locally
|
|
322
|
+
|
|
323
|
+
**Causes:**
|
|
324
|
+
- Environment differences
|
|
325
|
+
- Missing environment variables
|
|
326
|
+
- Timezone issues
|
|
327
|
+
- File path differences
|
|
328
|
+
|
|
329
|
+
**Solutions:**
|
|
330
|
+
- Use same Node.js version
|
|
331
|
+
- Set all required environment variables
|
|
332
|
+
- Use consistent timezone (UTC)
|
|
333
|
+
- Use absolute paths or path aliases
|
|
334
|
+
|
|
335
|
+
### Issue: Build Fails in CI
|
|
336
|
+
|
|
337
|
+
**Causes:**
|
|
338
|
+
- Missing dependencies
|
|
339
|
+
- Different Node.js version
|
|
340
|
+
- Platform-specific code
|
|
341
|
+
|
|
342
|
+
**Solutions:**
|
|
343
|
+
- Use `npm ci` (not `npm install`)
|
|
344
|
+
- Pin Node.js version
|
|
345
|
+
- Test on same platform as CI
|
|
346
|
+
|
|
347
|
+
### Issue: Slow CI Pipeline
|
|
348
|
+
|
|
349
|
+
**Causes:**
|
|
350
|
+
- Running unnecessary checks
|
|
351
|
+
- Not caching dependencies
|
|
352
|
+
- Sequential jobs
|
|
353
|
+
|
|
354
|
+
**Solutions:**
|
|
355
|
+
- Cache node_modules
|
|
356
|
+
- Run jobs in parallel
|
|
357
|
+
- Only run necessary checks per branch
|
|
358
|
+
|
|
359
|
+
## Related Documentation
|
|
360
|
+
|
|
361
|
+
- [Testing Standard](./04-testing-standards.md) - Test configuration
|
|
362
|
+
- [Code Quality Standard](./06-code-quality.md) - Linting and formatting
|
|
363
|
+
- [pace-core Compliance](./00-pace-core-compliance.md) - Compliance checks
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
**Last Updated:** 2025-01-28
|
|
368
|
+
**Version:** 1.0.0
|
|
369
|
+
**Applies to:** All consuming apps using `@jmruthers/pace-core`
|
|
370
|
+
|