@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
|
@@ -1,1103 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
lastUpdated: 2025-11-18T17:00:00+11:00
|
|
3
|
-
version: 0.5.181
|
|
4
|
-
reviewedBy: documentation-standards-audit
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Deployment Best Practices
|
|
8
|
-
|
|
9
|
-
Proper deployment is crucial for production success. This guide provides comprehensive deployment strategies and best practices for `@jmruthers/pace-core` applications.
|
|
10
|
-
|
|
11
|
-
## Overview
|
|
12
|
-
|
|
13
|
-
Deployment in `@jmruthers/pace-core` covers multiple environments:
|
|
14
|
-
|
|
15
|
-
- **Development**: Local development and testing
|
|
16
|
-
- **Staging**: Pre-production testing and validation
|
|
17
|
-
- **Production**: Live application with high availability
|
|
18
|
-
- **CI/CD**: Automated build and deployment pipelines
|
|
19
|
-
|
|
20
|
-
## Environment Configuration
|
|
21
|
-
|
|
22
|
-
### 1. Environment Variables
|
|
23
|
-
|
|
24
|
-
```typescript
|
|
25
|
-
// .env.local (development)
|
|
26
|
-
VITE_SUPABASE_URL=http://localhost:54321
|
|
27
|
-
// Accepts both legacy anon keys and modern publishable keys (sb_publishable_...)
|
|
28
|
-
VITE_SUPABASE_PUBLISHABLE_KEY=your-local-publishable-key
|
|
29
|
-
VITE_APP_ENV=development
|
|
30
|
-
VITE_DEBUG=true
|
|
31
|
-
|
|
32
|
-
// .env.staging
|
|
33
|
-
VITE_SUPABASE_URL=https://your-project.supabase.co
|
|
34
|
-
// Accepts both legacy anon keys and modern publishable keys (sb_publishable_...)
|
|
35
|
-
VITE_SUPABASE_PUBLISHABLE_KEY=your-staging-publishable-key
|
|
36
|
-
VITE_APP_ENV=staging
|
|
37
|
-
VITE_DEBUG=false
|
|
38
|
-
|
|
39
|
-
// .env.production
|
|
40
|
-
VITE_SUPABASE_URL=https://your-project.supabase.co
|
|
41
|
-
// Accepts both legacy anon keys and modern publishable keys (sb_publishable_...)
|
|
42
|
-
VITE_SUPABASE_PUBLISHABLE_KEY=your-production-publishable-key
|
|
43
|
-
VITE_APP_ENV=production
|
|
44
|
-
VITE_DEBUG=false
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### 2. Environment-Specific Configuration
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
// config/environment.ts
|
|
51
|
-
export const getEnvironmentConfig = () => {
|
|
52
|
-
const env = import.meta.env.VITE_APP_ENV || 'development';
|
|
53
|
-
|
|
54
|
-
const configs = {
|
|
55
|
-
development: {
|
|
56
|
-
apiUrl: 'http://localhost:54321',
|
|
57
|
-
debug: true,
|
|
58
|
-
logLevel: 'debug',
|
|
59
|
-
features: {
|
|
60
|
-
analytics: false,
|
|
61
|
-
monitoring: false,
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
staging: {
|
|
65
|
-
apiUrl: 'https://your-staging-project.supabase.co',
|
|
66
|
-
debug: false,
|
|
67
|
-
logLevel: 'info',
|
|
68
|
-
features: {
|
|
69
|
-
analytics: true,
|
|
70
|
-
monitoring: true,
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
production: {
|
|
74
|
-
apiUrl: 'https://your-production-project.supabase.co',
|
|
75
|
-
debug: false,
|
|
76
|
-
logLevel: 'warn',
|
|
77
|
-
features: {
|
|
78
|
-
analytics: true,
|
|
79
|
-
monitoring: true,
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
return configs[env] || configs.development;
|
|
85
|
-
};
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 3. Feature Flags
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
// utils/featureFlags.ts
|
|
92
|
-
export const FEATURE_FLAGS = {
|
|
93
|
-
NEW_UI: process.env.VITE_FEATURE_NEW_UI === 'true',
|
|
94
|
-
BETA_FEATURES: process.env.VITE_FEATURE_BETA === 'true',
|
|
95
|
-
ANALYTICS: process.env.VITE_FEATURE_ANALYTICS === 'true',
|
|
96
|
-
DEBUG_MODE: process.env.VITE_DEBUG === 'true',
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export const isFeatureEnabled = (feature: keyof typeof FEATURE_FLAGS) => {
|
|
100
|
-
return FEATURE_FLAGS[feature];
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
// Usage in components
|
|
104
|
-
function MyComponent() {
|
|
105
|
-
if (isFeatureEnabled('NEW_UI')) {
|
|
106
|
-
return <NewUIComponent />;
|
|
107
|
-
}
|
|
108
|
-
return <LegacyComponent />;
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Build Optimization
|
|
113
|
-
|
|
114
|
-
### 1. Production Build Configuration
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
// vite.config.ts
|
|
118
|
-
import { defineConfig } from 'vite';
|
|
119
|
-
import react from '@vitejs/plugin-react';
|
|
120
|
-
import { resolve } from 'path';
|
|
121
|
-
|
|
122
|
-
export default defineConfig({
|
|
123
|
-
plugins: [react()],
|
|
124
|
-
build: {
|
|
125
|
-
target: 'es2015',
|
|
126
|
-
outDir: 'dist',
|
|
127
|
-
sourcemap: false, // Disable in production
|
|
128
|
-
minify: 'terser',
|
|
129
|
-
rollupOptions: {
|
|
130
|
-
output: {
|
|
131
|
-
manualChunks: {
|
|
132
|
-
vendor: ['react', 'react-dom'],
|
|
133
|
-
paceCore: ['@jmruthers/pace-core'],
|
|
134
|
-
supabase: ['@supabase/supabase-js'],
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
terserOptions: {
|
|
139
|
-
compress: {
|
|
140
|
-
drop_console: true, // Remove console.log in production
|
|
141
|
-
drop_debugger: true,
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
define: {
|
|
146
|
-
__DEV__: JSON.stringify(process.env.NODE_ENV === 'development'),
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### 2. Bundle Analysis
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
// scripts/analyze-bundle.js
|
|
155
|
-
import { build } from 'vite';
|
|
156
|
-
import { visualizer } from 'rollup-plugin-visualizer';
|
|
157
|
-
|
|
158
|
-
export default defineConfig({
|
|
159
|
-
plugins: [
|
|
160
|
-
visualizer({
|
|
161
|
-
filename: 'dist/stats.html',
|
|
162
|
-
open: true,
|
|
163
|
-
gzipSize: true,
|
|
164
|
-
brotliSize: true,
|
|
165
|
-
}),
|
|
166
|
-
],
|
|
167
|
-
build: {
|
|
168
|
-
rollupOptions: {
|
|
169
|
-
output: {
|
|
170
|
-
manualChunks: {
|
|
171
|
-
vendor: ['react', 'react-dom'],
|
|
172
|
-
paceCore: ['@jmruthers/pace-core'],
|
|
173
|
-
supabase: ['@supabase/supabase-js'],
|
|
174
|
-
utils: ['lodash', 'date-fns'],
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### 3. Code Splitting
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
// Lazy load components based on routes
|
|
186
|
-
import { lazy, Suspense } from 'react';
|
|
187
|
-
|
|
188
|
-
const AdminDashboard = lazy(() => import('./AdminDashboard'));
|
|
189
|
-
const UserDashboard = lazy(() => import('./UserDashboard'));
|
|
190
|
-
const Analytics = lazy(() => import('./Analytics'));
|
|
191
|
-
|
|
192
|
-
import { useCan } from '@jmruthers/pace-core/rbac';
|
|
193
|
-
|
|
194
|
-
function App() {
|
|
195
|
-
const { user, selectedOrganisationId } = useUnifiedAuth();
|
|
196
|
-
const { can: canViewAdmin } = useCan(
|
|
197
|
-
user?.id || '',
|
|
198
|
-
{ organisationId: selectedOrganisationId || '', eventId: undefined, appId: undefined },
|
|
199
|
-
'read:page.admin'
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
return (
|
|
203
|
-
<Suspense fallback={<LoadingSpinner />}>
|
|
204
|
-
{canViewAdmin ? (
|
|
205
|
-
<AdminDashboard />
|
|
206
|
-
) : (
|
|
207
|
-
<UserDashboard />
|
|
208
|
-
)}
|
|
209
|
-
{canViewAdmin && (
|
|
210
|
-
<Suspense fallback={<div>Loading analytics...</div>}>
|
|
211
|
-
<Analytics />
|
|
212
|
-
</Suspense>
|
|
213
|
-
)}
|
|
214
|
-
</Suspense>
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## CI/CD Pipeline
|
|
220
|
-
|
|
221
|
-
### 1. GitHub Actions Workflow
|
|
222
|
-
|
|
223
|
-
```yaml
|
|
224
|
-
# .github/workflows/deploy.yml
|
|
225
|
-
name: Deploy
|
|
226
|
-
|
|
227
|
-
on:
|
|
228
|
-
push:
|
|
229
|
-
branches: [main, develop]
|
|
230
|
-
pull_request:
|
|
231
|
-
branches: [main]
|
|
232
|
-
|
|
233
|
-
jobs:
|
|
234
|
-
test:
|
|
235
|
-
runs-on: ubuntu-latest
|
|
236
|
-
steps:
|
|
237
|
-
- uses: actions/checkout@v3
|
|
238
|
-
|
|
239
|
-
- name: Setup Node.js
|
|
240
|
-
uses: actions/setup-node@v3
|
|
241
|
-
with:
|
|
242
|
-
node-version: '18'
|
|
243
|
-
cache: 'npm'
|
|
244
|
-
|
|
245
|
-
- name: Install dependencies
|
|
246
|
-
run: npm ci
|
|
247
|
-
|
|
248
|
-
- name: Run tests
|
|
249
|
-
run: npm test
|
|
250
|
-
|
|
251
|
-
- name: Run type check
|
|
252
|
-
run: npm run type-check
|
|
253
|
-
|
|
254
|
-
- name: Run linting
|
|
255
|
-
run: npm run lint
|
|
256
|
-
|
|
257
|
-
build:
|
|
258
|
-
needs: test
|
|
259
|
-
runs-on: ubuntu-latest
|
|
260
|
-
if: github.ref == 'refs/heads/main'
|
|
261
|
-
steps:
|
|
262
|
-
- uses: actions/checkout@v3
|
|
263
|
-
|
|
264
|
-
- name: Setup Node.js
|
|
265
|
-
uses: actions/setup-node@v3
|
|
266
|
-
with:
|
|
267
|
-
node-version: '18'
|
|
268
|
-
cache: 'npm'
|
|
269
|
-
|
|
270
|
-
- name: Install dependencies
|
|
271
|
-
run: npm ci
|
|
272
|
-
|
|
273
|
-
- name: Build application
|
|
274
|
-
run: npm run build
|
|
275
|
-
env:
|
|
276
|
-
VITE_SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
|
|
277
|
-
VITE_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.SUPABASE_PUBLISHABLE_KEY }}
|
|
278
|
-
VITE_APP_ENV: production
|
|
279
|
-
|
|
280
|
-
- name: Upload build artifacts
|
|
281
|
-
uses: actions/upload-artifact@v3
|
|
282
|
-
with:
|
|
283
|
-
name: build-files
|
|
284
|
-
path: dist/
|
|
285
|
-
|
|
286
|
-
deploy-staging:
|
|
287
|
-
needs: build
|
|
288
|
-
runs-on: ubuntu-latest
|
|
289
|
-
if: github.ref == 'refs/heads/develop'
|
|
290
|
-
steps:
|
|
291
|
-
- uses: actions/checkout@v3
|
|
292
|
-
|
|
293
|
-
- name: Download build artifacts
|
|
294
|
-
uses: actions/download-artifact@v3
|
|
295
|
-
with:
|
|
296
|
-
name: build-files
|
|
297
|
-
path: dist/
|
|
298
|
-
|
|
299
|
-
- name: Deploy to staging
|
|
300
|
-
run: |
|
|
301
|
-
# Deploy to staging environment
|
|
302
|
-
# This could be Vercel, Netlify, AWS, etc.
|
|
303
|
-
echo "Deploying to staging..."
|
|
304
|
-
|
|
305
|
-
deploy-production:
|
|
306
|
-
needs: build
|
|
307
|
-
runs-on: ubuntu-latest
|
|
308
|
-
if: github.ref == 'refs/heads/main'
|
|
309
|
-
environment: production
|
|
310
|
-
steps:
|
|
311
|
-
- uses: actions/checkout@v3
|
|
312
|
-
|
|
313
|
-
- name: Download build artifacts
|
|
314
|
-
uses: actions/download-artifact@v3
|
|
315
|
-
with:
|
|
316
|
-
name: build-files
|
|
317
|
-
path: dist/
|
|
318
|
-
|
|
319
|
-
- name: Deploy to production
|
|
320
|
-
run: |
|
|
321
|
-
# Deploy to production environment
|
|
322
|
-
echo "Deploying to production..."
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### 2. Environment-Specific Deployments
|
|
326
|
-
|
|
327
|
-
```yaml
|
|
328
|
-
# .github/workflows/deploy-staging.yml
|
|
329
|
-
name: Deploy to Staging
|
|
330
|
-
|
|
331
|
-
on:
|
|
332
|
-
push:
|
|
333
|
-
branches: [develop]
|
|
334
|
-
|
|
335
|
-
jobs:
|
|
336
|
-
deploy:
|
|
337
|
-
runs-on: ubuntu-latest
|
|
338
|
-
steps:
|
|
339
|
-
- uses: actions/checkout@v3
|
|
340
|
-
|
|
341
|
-
- name: Setup Node.js
|
|
342
|
-
uses: actions/setup-node@v3
|
|
343
|
-
with:
|
|
344
|
-
node-version: '18'
|
|
345
|
-
cache: 'npm'
|
|
346
|
-
|
|
347
|
-
- name: Install dependencies
|
|
348
|
-
run: npm ci
|
|
349
|
-
|
|
350
|
-
- name: Run tests
|
|
351
|
-
run: npm test
|
|
352
|
-
|
|
353
|
-
- name: Build for staging
|
|
354
|
-
run: npm run build:staging
|
|
355
|
-
env:
|
|
356
|
-
VITE_SUPABASE_URL: ${{ secrets.STAGING_SUPABASE_URL }}
|
|
357
|
-
VITE_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.STAGING_SUPABASE_PUBLISHABLE_KEY }}
|
|
358
|
-
VITE_APP_ENV: staging
|
|
359
|
-
|
|
360
|
-
- name: Deploy to Vercel (Staging)
|
|
361
|
-
uses: amondnet/vercel-action@v25
|
|
362
|
-
with:
|
|
363
|
-
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
364
|
-
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
365
|
-
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
366
|
-
vercel-args: '--prod'
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### 3. Automated Testing in CI
|
|
370
|
-
|
|
371
|
-
```yaml
|
|
372
|
-
# .github/workflows/test.yml
|
|
373
|
-
name: Test
|
|
374
|
-
|
|
375
|
-
on:
|
|
376
|
-
push:
|
|
377
|
-
branches: [main, develop]
|
|
378
|
-
pull_request:
|
|
379
|
-
branches: [main]
|
|
380
|
-
|
|
381
|
-
jobs:
|
|
382
|
-
test:
|
|
383
|
-
runs-on: ubuntu-latest
|
|
384
|
-
strategy:
|
|
385
|
-
matrix:
|
|
386
|
-
node-version: [16, 18, 20]
|
|
387
|
-
|
|
388
|
-
steps:
|
|
389
|
-
- uses: actions/checkout@v3
|
|
390
|
-
|
|
391
|
-
- name: Setup Node.js ${{ matrix.node-version }}
|
|
392
|
-
uses: actions/setup-node@v3
|
|
393
|
-
with:
|
|
394
|
-
node-version: ${{ matrix.node-version }}
|
|
395
|
-
cache: 'npm'
|
|
396
|
-
|
|
397
|
-
- name: Install dependencies
|
|
398
|
-
run: npm ci
|
|
399
|
-
|
|
400
|
-
- name: Run unit tests
|
|
401
|
-
run: npm run test:unit
|
|
402
|
-
|
|
403
|
-
- name: Run integration tests
|
|
404
|
-
run: npm run test:integration
|
|
405
|
-
|
|
406
|
-
- name: Run E2E tests
|
|
407
|
-
run: npm run test:e2e
|
|
408
|
-
|
|
409
|
-
- name: Upload coverage
|
|
410
|
-
uses: codecov/codecov-action@v3
|
|
411
|
-
with:
|
|
412
|
-
file: ./coverage/lcov.info
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
## Deployment Platforms
|
|
416
|
-
|
|
417
|
-
### 1. Vercel Deployment
|
|
418
|
-
|
|
419
|
-
```json
|
|
420
|
-
// vercel.json
|
|
421
|
-
{
|
|
422
|
-
"version": 2,
|
|
423
|
-
"builds": [
|
|
424
|
-
{
|
|
425
|
-
"src": "package.json",
|
|
426
|
-
"use": "@vercel/static-build",
|
|
427
|
-
"config": {
|
|
428
|
-
"distDir": "dist"
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
],
|
|
432
|
-
"routes": [
|
|
433
|
-
{
|
|
434
|
-
"src": "/api/(.*)",
|
|
435
|
-
"dest": "/api/$1"
|
|
436
|
-
},
|
|
437
|
-
{
|
|
438
|
-
"src": "/(.*)",
|
|
439
|
-
"dest": "/index.html"
|
|
440
|
-
}
|
|
441
|
-
],
|
|
442
|
-
"env": {
|
|
443
|
-
"VITE_SUPABASE_URL": "@supabase-url",
|
|
444
|
-
"VITE_SUPABASE_PUBLISHABLE_KEY": "@supabase-publishable-key"
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### 2. Netlify Deployment
|
|
450
|
-
|
|
451
|
-
```toml
|
|
452
|
-
# netlify.toml
|
|
453
|
-
[build]
|
|
454
|
-
command = "npm run build"
|
|
455
|
-
publish = "dist"
|
|
456
|
-
|
|
457
|
-
[build.environment]
|
|
458
|
-
VITE_SUPABASE_URL = "https://your-project.supabase.co"
|
|
459
|
-
VITE_APP_ENV = "production"
|
|
460
|
-
|
|
461
|
-
[[redirects]]
|
|
462
|
-
from = "/*"
|
|
463
|
-
to = "/index.html"
|
|
464
|
-
status = 200
|
|
465
|
-
|
|
466
|
-
[[headers]]
|
|
467
|
-
for = "/*"
|
|
468
|
-
[headers.values]
|
|
469
|
-
X-Frame-Options = "DENY"
|
|
470
|
-
X-XSS-Protection = "1; mode=block"
|
|
471
|
-
X-Content-Type-Options = "nosniff"
|
|
472
|
-
Referrer-Policy = "strict-origin-when-cross-origin"
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
### 3. AWS S3 + CloudFront
|
|
476
|
-
|
|
477
|
-
```typescript
|
|
478
|
-
// scripts/deploy-aws.js
|
|
479
|
-
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
|
|
480
|
-
import { CloudFrontClient, CreateInvalidationCommand } from '@aws-sdk/client-cloudfront';
|
|
481
|
-
import { readdir, readFile } from 'fs/promises';
|
|
482
|
-
import { join } from 'path';
|
|
483
|
-
|
|
484
|
-
const s3Client = new S3Client({ region: 'us-east-1' });
|
|
485
|
-
const cloudFrontClient = new CloudFrontClient({ region: 'us-east-1' });
|
|
486
|
-
|
|
487
|
-
async function deployToS3() {
|
|
488
|
-
const bucketName = process.env.AWS_S3_BUCKET;
|
|
489
|
-
const distributionId = process.env.AWS_CLOUDFRONT_DISTRIBUTION_ID;
|
|
490
|
-
|
|
491
|
-
// Upload build files to S3
|
|
492
|
-
const buildDir = join(process.cwd(), 'dist');
|
|
493
|
-
const files = await readdir(buildDir, { recursive: true });
|
|
494
|
-
|
|
495
|
-
for (const file of files) {
|
|
496
|
-
const filePath = join(buildDir, file);
|
|
497
|
-
const fileContent = await readFile(filePath);
|
|
498
|
-
|
|
499
|
-
await s3Client.send(new PutObjectCommand({
|
|
500
|
-
Bucket: bucketName,
|
|
501
|
-
Key: file,
|
|
502
|
-
Body: fileContent,
|
|
503
|
-
ContentType: getContentType(file),
|
|
504
|
-
CacheControl: getCacheControl(file),
|
|
505
|
-
}));
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// Invalidate CloudFront cache
|
|
509
|
-
await cloudFrontClient.send(new CreateInvalidationCommand({
|
|
510
|
-
DistributionId: distributionId,
|
|
511
|
-
InvalidationBatch: {
|
|
512
|
-
Paths: {
|
|
513
|
-
Quantity: 1,
|
|
514
|
-
Items: ['/*'],
|
|
515
|
-
},
|
|
516
|
-
CallerReference: Date.now().toString(),
|
|
517
|
-
},
|
|
518
|
-
}));
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
function getContentType(filename) {
|
|
522
|
-
if (filename.endsWith('.html')) return 'text/html';
|
|
523
|
-
if (filename.endsWith('.css')) return 'text/css';
|
|
524
|
-
if (filename.endsWith('.js')) return 'application/javascript';
|
|
525
|
-
if (filename.endsWith('.json')) return 'application/json';
|
|
526
|
-
return 'application/octet-stream';
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
function getCacheControl(filename) {
|
|
530
|
-
if (filename.endsWith('.html')) return 'no-cache';
|
|
531
|
-
if (filename.endsWith('.css') || filename.endsWith('.js')) return 'public, max-age=31536000';
|
|
532
|
-
return 'public, max-age=86400';
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
deployToS3().catch(console.error);
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
## Security Deployment
|
|
539
|
-
|
|
540
|
-
### 1. Security Headers
|
|
541
|
-
|
|
542
|
-
```typescript
|
|
543
|
-
// server/security-headers.js
|
|
544
|
-
export const securityHeaders = {
|
|
545
|
-
'Content-Security-Policy': [
|
|
546
|
-
"default-src 'self'",
|
|
547
|
-
"script-src 'self' 'unsafe-inline' 'unsafe-eval'",
|
|
548
|
-
"style-src 'self' 'unsafe-inline'",
|
|
549
|
-
"img-src 'self' data: https:",
|
|
550
|
-
"font-src 'self'",
|
|
551
|
-
"connect-src 'self' https://*.supabase.co",
|
|
552
|
-
"frame-ancestors 'none'",
|
|
553
|
-
].join('; '),
|
|
554
|
-
|
|
555
|
-
'X-Frame-Options': 'DENY',
|
|
556
|
-
'X-Content-Type-Options': 'nosniff',
|
|
557
|
-
'X-XSS-Protection': '1; mode=block',
|
|
558
|
-
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
|
559
|
-
'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',
|
|
560
|
-
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
|
|
561
|
-
};
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
### 2. Environment Variable Security
|
|
565
|
-
|
|
566
|
-
```bash
|
|
567
|
-
# .env.example (template for required variables)
|
|
568
|
-
VITE_SUPABASE_URL=
|
|
569
|
-
VITE_SUPABASE_PUBLISHABLE_KEY=
|
|
570
|
-
VITE_APP_ENV=development
|
|
571
|
-
VITE_DEBUG=false
|
|
572
|
-
|
|
573
|
-
# .env.production (actual production values - never commit)
|
|
574
|
-
VITE_SUPABASE_URL=https://your-project.supabase.co
|
|
575
|
-
VITE_SUPABASE_PUBLISHABLE_KEY=your-production-publishable-key
|
|
576
|
-
VITE_APP_ENV=production
|
|
577
|
-
VITE_DEBUG=false
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
### 3. SSL/TLS Configuration
|
|
581
|
-
|
|
582
|
-
```nginx
|
|
583
|
-
# nginx.conf
|
|
584
|
-
server {
|
|
585
|
-
listen 443 ssl http2;
|
|
586
|
-
server_name your-domain.com;
|
|
587
|
-
|
|
588
|
-
ssl_certificate /path/to/certificate.crt;
|
|
589
|
-
ssl_certificate_key /path/to/private.key;
|
|
590
|
-
|
|
591
|
-
ssl_protocols TLSv1.2 TLSv1.3;
|
|
592
|
-
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
|
|
593
|
-
ssl_prefer_server_ciphers off;
|
|
594
|
-
|
|
595
|
-
ssl_session_cache shared:SSL:10m;
|
|
596
|
-
ssl_session_timeout 10m;
|
|
597
|
-
|
|
598
|
-
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
599
|
-
add_header X-Frame-Options DENY always;
|
|
600
|
-
add_header X-Content-Type-Options nosniff always;
|
|
601
|
-
add_header X-XSS-Protection "1; mode=block" always;
|
|
602
|
-
|
|
603
|
-
location / {
|
|
604
|
-
root /var/www/html;
|
|
605
|
-
try_files $uri $uri/ /index.html;
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
## Monitoring and Logging
|
|
611
|
-
|
|
612
|
-
### 1. Application Monitoring
|
|
613
|
-
|
|
614
|
-
```typescript
|
|
615
|
-
// utils/monitoring.ts
|
|
616
|
-
export class ApplicationMonitor {
|
|
617
|
-
private static instance: ApplicationMonitor;
|
|
618
|
-
private metrics: Map<string, number> = new Map();
|
|
619
|
-
private errors: Error[] = [];
|
|
620
|
-
|
|
621
|
-
static getInstance(): ApplicationMonitor {
|
|
622
|
-
if (!ApplicationMonitor.instance) {
|
|
623
|
-
ApplicationMonitor.instance = new ApplicationMonitor();
|
|
624
|
-
}
|
|
625
|
-
return ApplicationMonitor.instance;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
trackEvent(eventName: string, properties?: Record<string, any>) {
|
|
629
|
-
// Send to analytics service
|
|
630
|
-
if (typeof gtag !== 'undefined') {
|
|
631
|
-
gtag('event', eventName, properties);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
// Track custom metrics
|
|
635
|
-
this.metrics.set(eventName, (this.metrics.get(eventName) || 0) + 1);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
trackError(error: Error, context?: Record<string, any>) {
|
|
639
|
-
this.errors.push(error);
|
|
640
|
-
|
|
641
|
-
// Send to error tracking service
|
|
642
|
-
if (typeof Sentry !== 'undefined') {
|
|
643
|
-
Sentry.captureException(error, {
|
|
644
|
-
extra: context,
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
trackPerformance(metric: string, value: number) {
|
|
650
|
-
// Send to performance monitoring service
|
|
651
|
-
if (typeof gtag !== 'undefined') {
|
|
652
|
-
gtag('event', 'timing_complete', {
|
|
653
|
-
name: metric,
|
|
654
|
-
value: value,
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
getMetrics() {
|
|
660
|
-
return Object.fromEntries(this.metrics);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
getErrors() {
|
|
664
|
-
return this.errors;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
// Usage
|
|
669
|
-
const monitor = ApplicationMonitor.getInstance();
|
|
670
|
-
monitor.trackEvent('user_login');
|
|
671
|
-
monitor.trackError(new Error('API call failed'), { endpoint: '/api/events' });
|
|
672
|
-
monitor.trackPerformance('page_load', 1200);
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
### 2. Health Checks
|
|
676
|
-
|
|
677
|
-
```typescript
|
|
678
|
-
// api/health.ts
|
|
679
|
-
export const healthCheck = async (req: Request, res: Response) => {
|
|
680
|
-
try {
|
|
681
|
-
// Check database connection
|
|
682
|
-
const { data, error } = await supabase
|
|
683
|
-
.from('health_check')
|
|
684
|
-
.select('*')
|
|
685
|
-
.limit(1);
|
|
686
|
-
|
|
687
|
-
if (error) {
|
|
688
|
-
return res.status(503).json({
|
|
689
|
-
status: 'unhealthy',
|
|
690
|
-
database: 'down',
|
|
691
|
-
timestamp: new Date().toISOString(),
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
// Check external services
|
|
696
|
-
const externalServices = await Promise.allSettled([
|
|
697
|
-
fetch('https://api.supabase.co/health'),
|
|
698
|
-
fetch('https://your-analytics-service.com/health'),
|
|
699
|
-
]);
|
|
700
|
-
|
|
701
|
-
const healthy = externalServices.every(result =>
|
|
702
|
-
result.status === 'fulfilled' && result.value.ok
|
|
703
|
-
);
|
|
704
|
-
|
|
705
|
-
return res.status(healthy ? 200 : 503).json({
|
|
706
|
-
status: healthy ? 'healthy' : 'degraded',
|
|
707
|
-
database: 'up',
|
|
708
|
-
external_services: externalServices.map(result =>
|
|
709
|
-
result.status === 'fulfilled' && result.value.ok ? 'up' : 'down'
|
|
710
|
-
),
|
|
711
|
-
timestamp: new Date().toISOString(),
|
|
712
|
-
});
|
|
713
|
-
} catch (error) {
|
|
714
|
-
return res.status(503).json({
|
|
715
|
-
status: 'unhealthy',
|
|
716
|
-
error: error.message,
|
|
717
|
-
timestamp: new Date().toISOString(),
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
};
|
|
721
|
-
```
|
|
722
|
-
|
|
723
|
-
### 3. Logging Configuration
|
|
724
|
-
|
|
725
|
-
```typescript
|
|
726
|
-
// utils/logger.ts
|
|
727
|
-
export enum LogLevel {
|
|
728
|
-
DEBUG = 0,
|
|
729
|
-
INFO = 1,
|
|
730
|
-
WARN = 2,
|
|
731
|
-
ERROR = 3,
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
export class Logger {
|
|
735
|
-
private level: LogLevel;
|
|
736
|
-
private context: string;
|
|
737
|
-
|
|
738
|
-
constructor(context: string, level: LogLevel = LogLevel.INFO) {
|
|
739
|
-
this.context = context;
|
|
740
|
-
this.level = level;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
debug(message: string, data?: any) {
|
|
744
|
-
if (this.level <= LogLevel.DEBUG) {
|
|
745
|
-
console.debug(`[DEBUG] ${this.context}: ${message}`, data);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
info(message: string, data?: any) {
|
|
750
|
-
if (this.level <= LogLevel.INFO) {
|
|
751
|
-
console.info(`[INFO] ${this.context}: ${message}`, data);
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
warn(message: string, data?: any) {
|
|
756
|
-
if (this.level <= LogLevel.WARN) {
|
|
757
|
-
console.warn(`[WARN] ${this.context}: ${message}`, data);
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
error(message: string, error?: Error, data?: any) {
|
|
762
|
-
if (this.level <= LogLevel.ERROR) {
|
|
763
|
-
console.error(`[ERROR] ${this.context}: ${message}`, error, data);
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
// Usage
|
|
769
|
-
const logger = new Logger('AuthService', LogLevel.DEBUG);
|
|
770
|
-
logger.info('User logged in', { userId: '123' });
|
|
771
|
-
logger.error('Authentication failed', new Error('Invalid credentials'));
|
|
772
|
-
```
|
|
773
|
-
|
|
774
|
-
## Rollback Strategy
|
|
775
|
-
|
|
776
|
-
### 1. Blue-Green Deployment
|
|
777
|
-
|
|
778
|
-
```yaml
|
|
779
|
-
# .github/workflows/blue-green-deploy.yml
|
|
780
|
-
name: Blue-Green Deployment
|
|
781
|
-
|
|
782
|
-
on:
|
|
783
|
-
push:
|
|
784
|
-
branches: [main]
|
|
785
|
-
|
|
786
|
-
jobs:
|
|
787
|
-
deploy-blue:
|
|
788
|
-
runs-on: ubuntu-latest
|
|
789
|
-
steps:
|
|
790
|
-
- name: Deploy to Blue Environment
|
|
791
|
-
run: |
|
|
792
|
-
# Deploy to blue environment
|
|
793
|
-
echo "Deploying to blue environment..."
|
|
794
|
-
|
|
795
|
-
- name: Run Health Checks
|
|
796
|
-
run: |
|
|
797
|
-
# Run health checks on blue environment
|
|
798
|
-
curl -f https://blue.your-domain.com/health
|
|
799
|
-
|
|
800
|
-
- name: Switch Traffic to Blue
|
|
801
|
-
run: |
|
|
802
|
-
# Switch traffic from green to blue
|
|
803
|
-
echo "Switching traffic to blue environment..."
|
|
804
|
-
|
|
805
|
-
rollback:
|
|
806
|
-
runs-on: ubuntu-latest
|
|
807
|
-
if: failure()
|
|
808
|
-
steps:
|
|
809
|
-
- name: Rollback to Green
|
|
810
|
-
run: |
|
|
811
|
-
# Rollback to green environment
|
|
812
|
-
echo "Rolling back to green environment..."
|
|
813
|
-
```
|
|
814
|
-
|
|
815
|
-
### 2. Canary Deployment
|
|
816
|
-
|
|
817
|
-
```typescript
|
|
818
|
-
// utils/canary-deployment.ts
|
|
819
|
-
export class CanaryDeployment {
|
|
820
|
-
private static instance: CanaryDeployment;
|
|
821
|
-
private currentVersion: string;
|
|
822
|
-
private canaryPercentage: number = 0;
|
|
823
|
-
|
|
824
|
-
static getInstance(): CanaryDeployment {
|
|
825
|
-
if (!CanaryDeployment.instance) {
|
|
826
|
-
CanaryDeployment.instance = new CanaryDeployment();
|
|
827
|
-
}
|
|
828
|
-
return CanaryDeployment.instance;
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
setCanaryPercentage(percentage: number) {
|
|
832
|
-
this.canaryPercentage = Math.max(0, Math.min(100, percentage));
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
shouldServeCanary(userId: string): boolean {
|
|
836
|
-
// Deterministic canary selection based on user ID
|
|
837
|
-
const hash = this.hashString(userId);
|
|
838
|
-
return (hash % 100) < this.canaryPercentage;
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
private hashString(str: string): number {
|
|
842
|
-
let hash = 0;
|
|
843
|
-
for (let i = 0; i < str.length; i++) {
|
|
844
|
-
const char = str.charCodeAt(i);
|
|
845
|
-
hash = ((hash << 5) - hash) + char;
|
|
846
|
-
hash = hash & hash; // Convert to 32-bit integer
|
|
847
|
-
}
|
|
848
|
-
return Math.abs(hash);
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
trackCanaryMetrics(userId: string, version: string, success: boolean) {
|
|
852
|
-
// Track canary metrics
|
|
853
|
-
const monitor = ApplicationMonitor.getInstance();
|
|
854
|
-
monitor.trackEvent('canary_request', {
|
|
855
|
-
userId,
|
|
856
|
-
version,
|
|
857
|
-
success,
|
|
858
|
-
percentage: this.canaryPercentage,
|
|
859
|
-
});
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
// Usage
|
|
864
|
-
const canary = CanaryDeployment.getInstance();
|
|
865
|
-
canary.setCanaryPercentage(10); // 10% of users get canary
|
|
866
|
-
|
|
867
|
-
if (canary.shouldServeCanary(user.id)) {
|
|
868
|
-
// Serve canary version
|
|
869
|
-
canary.trackCanaryMetrics(user.id, 'v2.0.0', true);
|
|
870
|
-
}
|
|
871
|
-
```
|
|
872
|
-
|
|
873
|
-
## Performance Monitoring
|
|
874
|
-
|
|
875
|
-
### 1. Core Web Vitals
|
|
876
|
-
|
|
877
|
-
```typescript
|
|
878
|
-
// utils/web-vitals.ts
|
|
879
|
-
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
|
|
880
|
-
|
|
881
|
-
export const trackWebVitals = () => {
|
|
882
|
-
getCLS(console.log);
|
|
883
|
-
getFID(console.log);
|
|
884
|
-
getFCP(console.log);
|
|
885
|
-
getLCP(console.log);
|
|
886
|
-
getTTFB(console.log);
|
|
887
|
-
};
|
|
888
|
-
|
|
889
|
-
export const trackCustomMetrics = () => {
|
|
890
|
-
// Track custom performance metrics
|
|
891
|
-
const observer = new PerformanceObserver((list) => {
|
|
892
|
-
for (const entry of list.getEntries()) {
|
|
893
|
-
const monitor = ApplicationMonitor.getInstance();
|
|
894
|
-
monitor.trackPerformance(entry.name, entry.startTime);
|
|
895
|
-
}
|
|
896
|
-
});
|
|
897
|
-
|
|
898
|
-
observer.observe({ entryTypes: ['measure', 'navigation'] });
|
|
899
|
-
};
|
|
900
|
-
|
|
901
|
-
// Track component render times
|
|
902
|
-
export const trackComponentPerformance = (componentName: string) => {
|
|
903
|
-
const startTime = performance.now();
|
|
904
|
-
|
|
905
|
-
return () => {
|
|
906
|
-
const endTime = performance.now();
|
|
907
|
-
const renderTime = endTime - startTime;
|
|
908
|
-
|
|
909
|
-
const monitor = ApplicationMonitor.getInstance();
|
|
910
|
-
monitor.trackPerformance(`${componentName}_render`, renderTime);
|
|
911
|
-
};
|
|
912
|
-
};
|
|
913
|
-
```
|
|
914
|
-
|
|
915
|
-
### 2. Error Tracking
|
|
916
|
-
|
|
917
|
-
```typescript
|
|
918
|
-
// utils/error-tracking.ts
|
|
919
|
-
import * as Sentry from '@sentry/react';
|
|
920
|
-
|
|
921
|
-
export const initializeErrorTracking = () => {
|
|
922
|
-
if (process.env.VITE_APP_ENV === 'production') {
|
|
923
|
-
Sentry.init({
|
|
924
|
-
dsn: process.env.VITE_SENTRY_DSN,
|
|
925
|
-
environment: process.env.VITE_APP_ENV,
|
|
926
|
-
integrations: [
|
|
927
|
-
new Sentry.BrowserTracing(),
|
|
928
|
-
new Sentry.Replay(),
|
|
929
|
-
],
|
|
930
|
-
tracesSampleRate: 0.1,
|
|
931
|
-
replaysSessionSampleRate: 0.1,
|
|
932
|
-
replaysOnErrorSampleRate: 1.0,
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
};
|
|
936
|
-
|
|
937
|
-
export const captureError = (error: Error, context?: Record<string, any>) => {
|
|
938
|
-
if (process.env.VITE_APP_ENV === 'production') {
|
|
939
|
-
Sentry.captureException(error, {
|
|
940
|
-
extra: context,
|
|
941
|
-
});
|
|
942
|
-
} else {
|
|
943
|
-
console.error('Error captured:', error, context);
|
|
944
|
-
}
|
|
945
|
-
};
|
|
946
|
-
```
|
|
947
|
-
|
|
948
|
-
## Deployment Checklist
|
|
949
|
-
|
|
950
|
-
### Pre-Deployment Checklist
|
|
951
|
-
|
|
952
|
-
- [ ] All tests passing
|
|
953
|
-
- [ ] Code review completed
|
|
954
|
-
- [ ] Security scan passed
|
|
955
|
-
- [ ] Performance benchmarks met
|
|
956
|
-
- [ ] Environment variables configured
|
|
957
|
-
- [ ] Database migrations applied
|
|
958
|
-
- [ ] SSL certificates valid
|
|
959
|
-
- [ ] Monitoring configured
|
|
960
|
-
- [ ] Rollback plan ready
|
|
961
|
-
- [ ] Team notified
|
|
962
|
-
|
|
963
|
-
### Deployment Checklist
|
|
964
|
-
|
|
965
|
-
- [ ] Deploy to staging environment
|
|
966
|
-
- [ ] Run smoke tests
|
|
967
|
-
- [ ] Verify all features work
|
|
968
|
-
- [ ] Check performance metrics
|
|
969
|
-
- [ ] Validate security headers
|
|
970
|
-
- [ ] Test error handling
|
|
971
|
-
- [ ] Verify monitoring alerts
|
|
972
|
-
- [ ] Deploy to production
|
|
973
|
-
- [ ] Monitor application health
|
|
974
|
-
- [ ] Verify user experience
|
|
975
|
-
|
|
976
|
-
### Post-Deployment Checklist
|
|
977
|
-
|
|
978
|
-
- [ ] Monitor error rates
|
|
979
|
-
- [ ] Check performance metrics
|
|
980
|
-
- [ ] Verify user feedback
|
|
981
|
-
- [ ] Monitor resource usage
|
|
982
|
-
- [ ] Check security alerts
|
|
983
|
-
- [ ] Validate analytics data
|
|
984
|
-
- [ ] Update documentation
|
|
985
|
-
- [ ] Archive old deployment
|
|
986
|
-
- [ ] Clean up temporary files
|
|
987
|
-
- [ ] Schedule next deployment
|
|
988
|
-
|
|
989
|
-
## Troubleshooting Deployment Issues
|
|
990
|
-
|
|
991
|
-
### 1. Common Deployment Problems
|
|
992
|
-
|
|
993
|
-
```typescript
|
|
994
|
-
// utils/deployment-troubleshooting.ts
|
|
995
|
-
export const commonDeploymentIssues = {
|
|
996
|
-
buildFailures: {
|
|
997
|
-
symptoms: ['Build timeout', 'Memory errors', 'Dependency conflicts'],
|
|
998
|
-
solutions: [
|
|
999
|
-
'Increase build memory allocation',
|
|
1000
|
-
'Update dependencies',
|
|
1001
|
-
'Clear build cache',
|
|
1002
|
-
'Check for circular dependencies',
|
|
1003
|
-
],
|
|
1004
|
-
},
|
|
1005
|
-
|
|
1006
|
-
environmentIssues: {
|
|
1007
|
-
symptoms: ['Missing environment variables', 'Wrong API endpoints'],
|
|
1008
|
-
solutions: [
|
|
1009
|
-
'Verify all required env vars are set',
|
|
1010
|
-
'Check environment-specific configs',
|
|
1011
|
-
'Validate API credentials',
|
|
1012
|
-
'Test API connectivity',
|
|
1013
|
-
],
|
|
1014
|
-
},
|
|
1015
|
-
|
|
1016
|
-
performanceIssues: {
|
|
1017
|
-
symptoms: ['Slow page loads', 'High memory usage'],
|
|
1018
|
-
solutions: [
|
|
1019
|
-
'Optimize bundle size',
|
|
1020
|
-
'Implement code splitting',
|
|
1021
|
-
'Add caching strategies',
|
|
1022
|
-
'Monitor resource usage',
|
|
1023
|
-
],
|
|
1024
|
-
},
|
|
1025
|
-
};
|
|
1026
|
-
```
|
|
1027
|
-
|
|
1028
|
-
### 2. Emergency Rollback
|
|
1029
|
-
|
|
1030
|
-
```bash
|
|
1031
|
-
#!/bin/bash
|
|
1032
|
-
# emergency-rollback.sh
|
|
1033
|
-
|
|
1034
|
-
echo "Starting emergency rollback..."
|
|
1035
|
-
|
|
1036
|
-
# Stop current deployment
|
|
1037
|
-
echo "Stopping current deployment..."
|
|
1038
|
-
# Add your deployment stop commands here
|
|
1039
|
-
|
|
1040
|
-
# Rollback to previous version
|
|
1041
|
-
echo "Rolling back to previous version..."
|
|
1042
|
-
# Add your rollback commands here
|
|
1043
|
-
|
|
1044
|
-
# Verify rollback
|
|
1045
|
-
echo "Verifying rollback..."
|
|
1046
|
-
curl -f https://your-domain.com/health
|
|
1047
|
-
|
|
1048
|
-
if [ $? -eq 0 ]; then
|
|
1049
|
-
echo "Rollback successful"
|
|
1050
|
-
exit 0
|
|
1051
|
-
else
|
|
1052
|
-
echo "Rollback failed"
|
|
1053
|
-
exit 1
|
|
1054
|
-
fi
|
|
1055
|
-
|
|
1056
|
-
## ♿ Accessibility
|
|
1057
|
-
|
|
1058
|
-
Deployment should maintain accessibility:
|
|
1059
|
-
|
|
1060
|
-
- **Production builds maintain accessibility** - Verify accessibility features work in production
|
|
1061
|
-
- **Environment variables don't break accessibility** - Ensure accessibility settings are correct
|
|
1062
|
-
- **CDN caching doesn't affect accessibility** - Verify cached assets maintain accessibility
|
|
1063
|
-
- **Error pages are accessible** - Ensure error pages meet accessibility standards
|
|
1064
|
-
- **Monitoring includes accessibility metrics** - Track accessibility in production
|
|
1065
|
-
|
|
1066
|
-
### Accessibility Best Practices
|
|
1067
|
-
|
|
1068
|
-
1. **Test production builds with screen readers** - Verify accessibility works in production
|
|
1069
|
-
2. **Monitor accessibility in production** - Track accessibility metrics
|
|
1070
|
-
3. **Ensure error pages are accessible** - Error pages should meet WCAG standards
|
|
1071
|
-
4. **Test with assistive technologies** - Verify production deployment works with screen readers
|
|
1072
|
-
5. **Document accessibility requirements** - Include accessibility in deployment checklists
|
|
1073
|
-
|
|
1074
|
-
## ⚠️ Edge Cases
|
|
1075
|
-
|
|
1076
|
-
### Deployment Failures
|
|
1077
|
-
|
|
1078
|
-
When deployment fails:
|
|
1079
|
-
- Have rollback plan ready
|
|
1080
|
-
- Test deployment procedures in staging
|
|
1081
|
-
- Monitor deployment logs
|
|
1082
|
-
- Verify all dependencies are available
|
|
1083
|
-
- Test with minimal configuration
|
|
1084
|
-
|
|
1085
|
-
### Environment-Specific Issues
|
|
1086
|
-
|
|
1087
|
-
When issues occur in specific environments:
|
|
1088
|
-
- Verify environment variables are correct
|
|
1089
|
-
- Check build configuration matches environment
|
|
1090
|
-
- Ensure all services are available
|
|
1091
|
-
- Test with environment-specific data
|
|
1092
|
-
- Review environment differences
|
|
1093
|
-
|
|
1094
|
-
### Rollback Scenarios
|
|
1095
|
-
|
|
1096
|
-
When rollback is needed:
|
|
1097
|
-
- Have automated rollback procedures
|
|
1098
|
-
- Test rollback in staging environment
|
|
1099
|
-
- Verify data integrity after rollback
|
|
1100
|
-
- Document rollback steps clearly
|
|
1101
|
-
- Monitor system after rollback
|
|
1102
|
-
|
|
1103
|
-
For more information about deploying your application, see the [Security Guide](./security.md) and [Performance Guide](./performance.md).
|