@jmruthers/pace-core 0.6.5 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
---
|
|
2
|
+
lastUpdated: 2025-01-04T00:00:00+00:00
|
|
3
|
+
version: 2.0.0
|
|
4
|
+
reviewedBy: rbac-architecture-review
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# RBAC Migration Guide
|
|
8
|
+
|
|
9
|
+
> **🔄 Migrating to RBAC Contract v2.0.0** | [← Back to RBAC Documentation](./README.md) | [RBAC Contract](./RBAC_CONTRACT.md)
|
|
10
|
+
|
|
11
|
+
This guide helps you migrate your consuming application to comply with the RBAC Contract v2.0.0.
|
|
12
|
+
|
|
13
|
+
## Breaking Changes
|
|
14
|
+
|
|
15
|
+
### 1. RBAC Package Surface Area Reduction
|
|
16
|
+
|
|
17
|
+
**What Changed:**
|
|
18
|
+
- Removed redundant and overlapping RBAC exports to enforce a single correct pattern
|
|
19
|
+
- Reduced API surface area by ~40-50%
|
|
20
|
+
- All removed functionality has clear migration paths
|
|
21
|
+
|
|
22
|
+
**Impact:**
|
|
23
|
+
- Code using removed components/hooks/APIs will fail to build
|
|
24
|
+
- Must migrate to the minimal, canonical API
|
|
25
|
+
|
|
26
|
+
**Migration:**
|
|
27
|
+
|
|
28
|
+
#### Components Removed
|
|
29
|
+
|
|
30
|
+
**PermissionEnforcer → PagePermissionGuard**
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// ❌ OLD
|
|
34
|
+
import { PermissionEnforcer } from '@jmruthers/pace-core/rbac';
|
|
35
|
+
|
|
36
|
+
<PermissionEnforcer permissions={['read:events']} operation="event-management">
|
|
37
|
+
<Content />
|
|
38
|
+
</PermissionEnforcer>
|
|
39
|
+
|
|
40
|
+
// ✅ NEW
|
|
41
|
+
import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
|
|
42
|
+
|
|
43
|
+
<PagePermissionGuard pageName="events" operation="read">
|
|
44
|
+
<Content />
|
|
45
|
+
</PagePermissionGuard>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**PermissionGuard (from adapters) → PagePermissionGuard**
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// ❌ OLD
|
|
52
|
+
import { PermissionGuard } from '@jmruthers/pace-core/rbac';
|
|
53
|
+
|
|
54
|
+
<PermissionGuard permission="update:events" scope={{ organisationId: 'org-123' }}>
|
|
55
|
+
<Content />
|
|
56
|
+
</PermissionGuard>
|
|
57
|
+
|
|
58
|
+
// ✅ NEW
|
|
59
|
+
import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
|
|
60
|
+
|
|
61
|
+
<PagePermissionGuard pageName="events" operation="update">
|
|
62
|
+
<Content />
|
|
63
|
+
</PagePermissionGuard>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**AccessLevelGuard → useAccessLevel Hook**
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
// ❌ OLD
|
|
70
|
+
import { AccessLevelGuard } from '@jmruthers/pace-core/rbac';
|
|
71
|
+
|
|
72
|
+
<AccessLevelGuard minLevel="admin" scope={{ organisationId: 'org-123' }}>
|
|
73
|
+
<AdminPanel />
|
|
74
|
+
</AccessLevelGuard>
|
|
75
|
+
|
|
76
|
+
// ✅ NEW
|
|
77
|
+
import { useAccessLevel } from '@jmruthers/pace-core/rbac';
|
|
78
|
+
|
|
79
|
+
function AdminPanel() {
|
|
80
|
+
const { accessLevel } = useAccessLevel();
|
|
81
|
+
|
|
82
|
+
if (accessLevel !== 'admin' && accessLevel !== 'super') {
|
|
83
|
+
return <AccessDenied />;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return <AdminPanelContent />;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**RoleBasedRouter → PagePermissionGuard + React Router**
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
// ❌ OLD
|
|
94
|
+
import { RoleBasedRouter } from '@jmruthers/pace-core/rbac';
|
|
95
|
+
|
|
96
|
+
<RoleBasedRouter routes={routeConfig}>
|
|
97
|
+
<App />
|
|
98
|
+
</RoleBasedRouter>
|
|
99
|
+
|
|
100
|
+
// ✅ NEW
|
|
101
|
+
import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
|
|
102
|
+
import { Routes, Route } from 'react-router-dom';
|
|
103
|
+
|
|
104
|
+
<Routes>
|
|
105
|
+
<Route path="/dashboard" element={
|
|
106
|
+
<PagePermissionGuard pageName="dashboard" operation="read">
|
|
107
|
+
<Dashboard />
|
|
108
|
+
</PagePermissionGuard>
|
|
109
|
+
} />
|
|
110
|
+
</Routes>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**EnhancedNavigationMenu → NavigationMenu + NavigationGuard**
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
// ❌ OLD
|
|
117
|
+
import { EnhancedNavigationMenu } from '@jmruthers/pace-core/rbac';
|
|
118
|
+
|
|
119
|
+
<EnhancedNavigationMenu items={items} />
|
|
120
|
+
|
|
121
|
+
// ✅ NEW
|
|
122
|
+
import { NavigationMenu, NavigationGuard } from '@jmruthers/pace-core';
|
|
123
|
+
|
|
124
|
+
<NavigationMenu>
|
|
125
|
+
{items.map(item => (
|
|
126
|
+
<NavigationGuard key={item.id} permission={item.permission}>
|
|
127
|
+
<NavigationItem {...item} />
|
|
128
|
+
</NavigationGuard>
|
|
129
|
+
))}
|
|
130
|
+
</NavigationMenu>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Context Providers Removed**
|
|
134
|
+
|
|
135
|
+
All context providers have been removed. Use components/hooks directly:
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
// ❌ OLD
|
|
139
|
+
import { PagePermissionProvider, SecureDataProvider, NavigationProvider } from '@jmruthers/pace-core/rbac';
|
|
140
|
+
|
|
141
|
+
<PagePermissionProvider>
|
|
142
|
+
<SecureDataProvider>
|
|
143
|
+
<NavigationProvider>
|
|
144
|
+
<App />
|
|
145
|
+
</NavigationProvider>
|
|
146
|
+
</SecureDataProvider>
|
|
147
|
+
</PagePermissionProvider>
|
|
148
|
+
|
|
149
|
+
// ✅ NEW - No providers needed, use components/hooks directly
|
|
150
|
+
import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
|
|
151
|
+
import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
152
|
+
|
|
153
|
+
// Use PagePermissionGuard in routes
|
|
154
|
+
// Use useSecureSupabase hook in components that need secure client
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### Hooks Removed
|
|
158
|
+
|
|
159
|
+
**useHasAnyPermission → useMultiplePermissions**
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
// ❌ OLD
|
|
163
|
+
import { useHasAnyPermission } from '@jmruthers/pace-core/rbac';
|
|
164
|
+
|
|
165
|
+
const hasAny = useHasAnyPermission(['read:events', 'read:users']);
|
|
166
|
+
|
|
167
|
+
// ✅ NEW
|
|
168
|
+
import { useMultiplePermissions } from '@jmruthers/pace-core/rbac';
|
|
169
|
+
|
|
170
|
+
const { permissions } = useMultiplePermissions(['read:events', 'read:users']);
|
|
171
|
+
const hasAny = Object.values(permissions).some(Boolean);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**useHasAllPermissions → useMultiplePermissions**
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
// ❌ OLD
|
|
178
|
+
import { useHasAllPermissions } from '@jmruthers/pace-core/rbac';
|
|
179
|
+
|
|
180
|
+
const hasAll = useHasAllPermissions(['read:events', 'update:events']);
|
|
181
|
+
|
|
182
|
+
// ✅ NEW
|
|
183
|
+
import { useMultiplePermissions } from '@jmruthers/pace-core/rbac';
|
|
184
|
+
|
|
185
|
+
const { permissions } = useMultiplePermissions(['read:events', 'update:events']);
|
|
186
|
+
const hasAll = Object.values(permissions).every(Boolean);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**useCachedPermissions → Automatic Caching**
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
// ❌ OLD
|
|
193
|
+
import { useCachedPermissions } from '@jmruthers/pace-core/rbac';
|
|
194
|
+
|
|
195
|
+
const cached = useCachedPermissions(['read:events']);
|
|
196
|
+
|
|
197
|
+
// ✅ NEW - Caching is automatic in all hooks
|
|
198
|
+
import { useCan } from '@jmruthers/pace-core/rbac';
|
|
199
|
+
|
|
200
|
+
const can = useCan('read:events'); // Automatically cached
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### API Functions Removed
|
|
204
|
+
|
|
205
|
+
**hasPermission → isPermitted**
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
// ❌ OLD
|
|
209
|
+
import { hasPermission } from '@jmruthers/pace-core/rbac';
|
|
210
|
+
|
|
211
|
+
const hasAccess = await hasPermission({
|
|
212
|
+
permission: 'read:events',
|
|
213
|
+
pageName: 'events'
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// ✅ NEW
|
|
217
|
+
import { isPermitted } from '@jmruthers/pace-core/rbac';
|
|
218
|
+
|
|
219
|
+
const hasAccess = await isPermitted({
|
|
220
|
+
permission: 'read:events',
|
|
221
|
+
pageName: 'events'
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Cache-only helpers → Automatic Caching**
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
// ❌ OLD
|
|
229
|
+
import { hasPermissionCached, hasAnyPermissionCached } from '@jmruthers/pace-core/rbac';
|
|
230
|
+
|
|
231
|
+
const cached = hasPermissionCached(userId, scope, 'read:events');
|
|
232
|
+
const anyCached = hasAnyPermissionCached(userId, scope, ['read:events', 'read:users']);
|
|
233
|
+
|
|
234
|
+
// ✅ NEW - Use hooks or API with automatic caching
|
|
235
|
+
import { useCan, useMultiplePermissions } from '@jmruthers/pace-core/rbac';
|
|
236
|
+
import { isPermittedCached } from '@jmruthers/pace-core/rbac';
|
|
237
|
+
|
|
238
|
+
// In components (automatic caching)
|
|
239
|
+
const can = useCan('read:events');
|
|
240
|
+
|
|
241
|
+
// In API/server code
|
|
242
|
+
const cached = await isPermittedCached({
|
|
243
|
+
permission: 'read:events',
|
|
244
|
+
pageName: 'events'
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### Internal Exports
|
|
249
|
+
|
|
250
|
+
The following exports are now marked as `@internal` and should not be used by consuming apps:
|
|
251
|
+
|
|
252
|
+
- `RBACEngine`, `createRBACEngine` → Use `isPermitted` API instead
|
|
253
|
+
- `RBACCache`, `rbacCache`, `CACHE_PATTERNS` → Caching is automatic
|
|
254
|
+
- `SecureSupabaseClient`, `createSecureClient`, `fromSupabaseClient` → Use `useSecureSupabase` hook instead
|
|
255
|
+
|
|
256
|
+
**Migration Steps:**
|
|
257
|
+
|
|
258
|
+
1. **Search for removed exports:**
|
|
259
|
+
```bash
|
|
260
|
+
grep -r "PermissionEnforcer\|PermissionGuard\|AccessLevelGuard\|RoleBasedRouter\|EnhancedNavigationMenu\|PagePermissionProvider\|SecureDataProvider\|NavigationProvider\|useHasAnyPermission\|useHasAllPermissions\|useCachedPermissions\|hasPermission\|hasPermissionCached\|hasAnyPermissionCached" src/
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
2. **Replace with canonical alternatives** (see examples above)
|
|
264
|
+
|
|
265
|
+
3. **Remove internal export usage:**
|
|
266
|
+
```bash
|
|
267
|
+
grep -r "RBACEngine\|createRBACEngine\|RBACCache\|rbacCache\|CACHE_PATTERNS\|SecureSupabaseClient\|createSecureClient\|fromSupabaseClient" src/
|
|
268
|
+
```
|
|
269
|
+
Replace with public APIs/hooks
|
|
270
|
+
|
|
271
|
+
4. **Verify build:**
|
|
272
|
+
```bash
|
|
273
|
+
npm run build
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 2. ESLint Rules Now ERROR (Not Warning)
|
|
277
|
+
|
|
278
|
+
**What Changed:**
|
|
279
|
+
- All RBAC compliance ESLint rules are now **ERROR** severity
|
|
280
|
+
- Builds will fail if violations are detected
|
|
281
|
+
- No more warnings - violations must be fixed
|
|
282
|
+
|
|
283
|
+
**Impact:**
|
|
284
|
+
- Existing code with violations will fail to build
|
|
285
|
+
- Must fix all violations before deployment
|
|
286
|
+
|
|
287
|
+
**Migration:**
|
|
288
|
+
1. Run ESLint to identify violations:
|
|
289
|
+
```bash
|
|
290
|
+
npm run lint
|
|
291
|
+
```
|
|
292
|
+
2. Fix all violations (see sections below)
|
|
293
|
+
3. Verify build passes:
|
|
294
|
+
```bash
|
|
295
|
+
npm run build
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 2. EventPageGuard Wrapper Pattern Removed
|
|
299
|
+
|
|
300
|
+
**What Changed:**
|
|
301
|
+
- `EventPageGuard` wrapper components are **forbidden**
|
|
302
|
+
- Must use `PagePermissionGuard` directly
|
|
303
|
+
- Event context validation should be in page components
|
|
304
|
+
|
|
305
|
+
**Before:**
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
// ❌ OLD PATTERN - Remove this
|
|
309
|
+
import { EventPageGuard } from '@/components/permissions';
|
|
310
|
+
|
|
311
|
+
function DashboardPage() {
|
|
312
|
+
return (
|
|
313
|
+
<EventPageGuard pageName={PAGE_NAMES.DASHBOARD}>
|
|
314
|
+
<DashboardContent />
|
|
315
|
+
</EventPageGuard>
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**After:**
|
|
321
|
+
|
|
322
|
+
```tsx
|
|
323
|
+
// ✅ NEW PATTERN - Use this
|
|
324
|
+
import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
|
|
325
|
+
import { useEvents } from '@jmruthers/pace-core';
|
|
326
|
+
import { EventSelectionPrompt } from '@/components/permissions/EventSelectionPrompt';
|
|
327
|
+
|
|
328
|
+
function DashboardPage() {
|
|
329
|
+
const { selectedEvent } = useEvents();
|
|
330
|
+
|
|
331
|
+
// Handle event context validation in page
|
|
332
|
+
if (!selectedEvent) {
|
|
333
|
+
return <EventSelectionPrompt />;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<PagePermissionGuard pageName={PAGE_NAMES.DASHBOARD} operation="read">
|
|
338
|
+
<DashboardContent />
|
|
339
|
+
</PagePermissionGuard>
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Migration Steps:**
|
|
345
|
+
|
|
346
|
+
1. **Remove EventPageGuard component:**
|
|
347
|
+
```bash
|
|
348
|
+
rm src/components/permissions/EventPageGuard.tsx
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
2. **Update all imports:**
|
|
352
|
+
```tsx
|
|
353
|
+
// Remove
|
|
354
|
+
import { EventPageGuard } from '@/components/permissions';
|
|
355
|
+
|
|
356
|
+
// Add
|
|
357
|
+
import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
3. **Replace all usages:**
|
|
361
|
+
- Replace `<EventPageGuard pageName="...">` with `<PagePermissionGuard pageName="..." operation="read">`
|
|
362
|
+
- Add event context validation in page components
|
|
363
|
+
- Add `operation` prop (usually `"read"`)
|
|
364
|
+
|
|
365
|
+
4. **Update index exports:**
|
|
366
|
+
```tsx
|
|
367
|
+
// src/components/permissions/index.ts
|
|
368
|
+
// Remove EventPageGuard export
|
|
369
|
+
// export { EventPageGuard } from './EventPageGuard';
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 3. Custom AccessDenied Components No Longer Allowed
|
|
373
|
+
|
|
374
|
+
**What Changed:**
|
|
375
|
+
- Custom access denied components are **forbidden**
|
|
376
|
+
- Must use `AccessDenied` from pace-core
|
|
377
|
+
- Ensures consistent UX across all apps
|
|
378
|
+
|
|
379
|
+
**Before:**
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
// ❌ OLD PATTERN - Remove this
|
|
383
|
+
function CustomAccessDenied() {
|
|
384
|
+
return (
|
|
385
|
+
<div>
|
|
386
|
+
<h2>Access Denied</h2>
|
|
387
|
+
<p>You don't have permission.</p>
|
|
388
|
+
</div>
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
<PagePermissionGuard
|
|
393
|
+
pageName="dashboard"
|
|
394
|
+
fallback={<CustomAccessDenied />}
|
|
395
|
+
>
|
|
396
|
+
<DashboardContent />
|
|
397
|
+
</PagePermissionGuard>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**After:**
|
|
401
|
+
|
|
402
|
+
```tsx
|
|
403
|
+
// ✅ NEW PATTERN - Use this
|
|
404
|
+
import { AccessDenied } from '@jmruthers/pace-core/rbac';
|
|
405
|
+
|
|
406
|
+
<PagePermissionGuard
|
|
407
|
+
pageName="dashboard"
|
|
408
|
+
operation="read"
|
|
409
|
+
fallback={<AccessDenied />}
|
|
410
|
+
>
|
|
411
|
+
<DashboardContent />
|
|
412
|
+
</PagePermissionGuard>
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Migration Steps:**
|
|
416
|
+
|
|
417
|
+
1. **Remove custom access denied components:**
|
|
418
|
+
```bash
|
|
419
|
+
rm src/components/permissions/CustomAccessDenied.tsx
|
|
420
|
+
rm src/components/permissions/StandardAccessDenied.tsx
|
|
421
|
+
# etc.
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
2. **Update imports:**
|
|
425
|
+
```tsx
|
|
426
|
+
// Remove
|
|
427
|
+
import { CustomAccessDenied } from '@/components/permissions';
|
|
428
|
+
|
|
429
|
+
// Add
|
|
430
|
+
import { AccessDenied } from '@jmruthers/pace-core/rbac';
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
3. **Replace all usages:**
|
|
434
|
+
```tsx
|
|
435
|
+
// Replace
|
|
436
|
+
fallback={<CustomAccessDenied />}
|
|
437
|
+
|
|
438
|
+
// With
|
|
439
|
+
fallback={<AccessDenied />}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
4. **Customize if needed (via props):**
|
|
443
|
+
```tsx
|
|
444
|
+
<AccessDenied
|
|
445
|
+
message="Custom message"
|
|
446
|
+
onGoBack={() => navigate('/dashboard')}
|
|
447
|
+
showSignOut={true}
|
|
448
|
+
/>
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### 4. Direct RBAC Table Queries Now Errors
|
|
452
|
+
|
|
453
|
+
**What Changed:**
|
|
454
|
+
- Direct queries to RBAC tables are **forbidden**
|
|
455
|
+
- Must use `useSecureSupabase` hook
|
|
456
|
+
- ESLint will error on violations
|
|
457
|
+
|
|
458
|
+
**Before:**
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
// ❌ OLD PATTERN - Remove this
|
|
462
|
+
const { data } = await supabase
|
|
463
|
+
.from('rbac_user_profiles')
|
|
464
|
+
.select('user_id, display_name')
|
|
465
|
+
.in('user_id', userIds);
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**After:**
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
// ✅ NEW PATTERN - Use this
|
|
472
|
+
import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
473
|
+
|
|
474
|
+
function MyComponent() {
|
|
475
|
+
const secureSupabase = useSecureSupabase(supabase);
|
|
476
|
+
|
|
477
|
+
const { data } = await secureSupabase
|
|
478
|
+
.from('rbac_user_profiles')
|
|
479
|
+
.select('user_id, display_name')
|
|
480
|
+
.in('user_id', userIds);
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Migration Steps:**
|
|
485
|
+
|
|
486
|
+
1. **Find all direct RBAC table queries:**
|
|
487
|
+
```bash
|
|
488
|
+
# Search for RBAC table queries
|
|
489
|
+
grep -r "\.from(['\"]rbac_" src/
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
2. **Update to use useSecureSupabase:**
|
|
493
|
+
- Import `useSecureSupabase` from `@jmruthers/pace-core/rbac`
|
|
494
|
+
- Call `useSecureSupabase(supabase)` in component
|
|
495
|
+
- Replace `supabase` with `secureSupabase` in queries
|
|
496
|
+
|
|
497
|
+
3. **Verify queries work:**
|
|
498
|
+
- Test that queries still return expected data
|
|
499
|
+
- Verify security is maintained
|
|
500
|
+
|
|
501
|
+
### 5. Direct RPC Calls Now Errors
|
|
502
|
+
|
|
503
|
+
**What Changed:**
|
|
504
|
+
- Direct calls to `rbac_check_permission_simplified` are **forbidden**
|
|
505
|
+
- Must use `isPermitted` from pace-core
|
|
506
|
+
- ESLint will error on violations
|
|
507
|
+
|
|
508
|
+
**Before:**
|
|
509
|
+
|
|
510
|
+
```tsx
|
|
511
|
+
// ❌ OLD PATTERN - Remove this
|
|
512
|
+
const { data, error } = await supabase.rpc('rbac_check_permission_simplified', {
|
|
513
|
+
p_user_id: userId,
|
|
514
|
+
p_permission: 'read:dashboard',
|
|
515
|
+
p_organisation_id: orgId
|
|
516
|
+
});
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**After:**
|
|
520
|
+
|
|
521
|
+
```tsx
|
|
522
|
+
// ✅ NEW PATTERN - Use this
|
|
523
|
+
import { isPermitted } from '@jmruthers/pace-core/rbac';
|
|
524
|
+
|
|
525
|
+
const hasAccess = await isPermitted({
|
|
526
|
+
permission: 'read:dashboard',
|
|
527
|
+
pageName: 'dashboard'
|
|
528
|
+
});
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**Migration Steps:**
|
|
532
|
+
|
|
533
|
+
1. **Find all direct RPC calls:**
|
|
534
|
+
```bash
|
|
535
|
+
# Search for RPC calls
|
|
536
|
+
grep -r "rbac_check_permission_simplified" src/
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
2. **Replace with isPermitted:**
|
|
540
|
+
- Import `isPermitted` from `@jmruthers/pace-core/rbac`
|
|
541
|
+
- Replace RPC call with `isPermitted` call
|
|
542
|
+
- Update permission format if needed
|
|
543
|
+
|
|
544
|
+
3. **Verify permission checks work:**
|
|
545
|
+
- Test that permission checks return expected results
|
|
546
|
+
- Verify caching behavior is correct
|
|
547
|
+
|
|
548
|
+
### 6. enforcePermissions Pattern Clarified
|
|
549
|
+
|
|
550
|
+
**What Changed:**
|
|
551
|
+
- `enforcePermissions` usage clarified for event-based apps
|
|
552
|
+
- Must be `false` for event-based apps
|
|
553
|
+
- Must be `true` for organisation-based apps
|
|
554
|
+
|
|
555
|
+
**Before (Event-Based Apps):**
|
|
556
|
+
|
|
557
|
+
```tsx
|
|
558
|
+
// ❌ OLD PATTERN - May have been true
|
|
559
|
+
<PaceAppLayout
|
|
560
|
+
appName="MyApp"
|
|
561
|
+
enforcePermissions={true} // Wrong for event-based apps
|
|
562
|
+
showEvents={true}
|
|
563
|
+
>
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**After (Event-Based Apps):**
|
|
567
|
+
|
|
568
|
+
```tsx
|
|
569
|
+
// ✅ NEW PATTERN - Must be false
|
|
570
|
+
<PaceAppLayout
|
|
571
|
+
appName="MyApp"
|
|
572
|
+
enforcePermissions={false} // Correct for event-based apps
|
|
573
|
+
showEvents={true}
|
|
574
|
+
>
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
**Migration Steps:**
|
|
578
|
+
|
|
579
|
+
1. **Identify app type:**
|
|
580
|
+
- Event-based: Uses events, pages handle checks
|
|
581
|
+
- Organisation-based: Uses organisations, layout handles checks
|
|
582
|
+
|
|
583
|
+
2. **Update enforcePermissions:**
|
|
584
|
+
- Event-based apps: Set to `false`
|
|
585
|
+
- Organisation-based apps: Set to `true`
|
|
586
|
+
|
|
587
|
+
3. **Verify behavior:**
|
|
588
|
+
- Test that pages are properly protected
|
|
589
|
+
- Verify no redundant permission checks
|
|
590
|
+
|
|
591
|
+
## Step-by-Step Migration Checklist
|
|
592
|
+
|
|
593
|
+
### Phase 1: Preparation
|
|
594
|
+
|
|
595
|
+
- [ ] Review [RBAC Contract](./RBAC_CONTRACT.md)
|
|
596
|
+
- [ ] Run ESLint: `npm run lint`
|
|
597
|
+
- [ ] Document current violations
|
|
598
|
+
|
|
599
|
+
### Phase 2: Remove Wrapper Components
|
|
600
|
+
|
|
601
|
+
- [ ] Remove `EventPageGuard` component
|
|
602
|
+
- [ ] Update all imports
|
|
603
|
+
- [ ] Replace all `EventPageGuard` usages with `PagePermissionGuard`
|
|
604
|
+
- [ ] Add event context validation in pages
|
|
605
|
+
- [ ] Test all pages load correctly
|
|
606
|
+
|
|
607
|
+
### Phase 3: Replace Custom Access Denied
|
|
608
|
+
|
|
609
|
+
- [ ] Remove custom access denied components
|
|
610
|
+
- [ ] Update imports to use `AccessDenied` from pace-core
|
|
611
|
+
- [ ] Replace all fallback props
|
|
612
|
+
- [ ] Customize via props if needed
|
|
613
|
+
- [ ] Test access denied scenarios
|
|
614
|
+
|
|
615
|
+
### Phase 4: Fix Direct Queries
|
|
616
|
+
|
|
617
|
+
- [ ] Find all direct RBAC table queries
|
|
618
|
+
- [ ] Replace with `useSecureSupabase`
|
|
619
|
+
- [ ] Find all direct RPC calls
|
|
620
|
+
- [ ] Replace with `isPermitted`
|
|
621
|
+
- [ ] Test all queries work correctly
|
|
622
|
+
|
|
623
|
+
### Phase 5: Remove Hardcoded Role Checks
|
|
624
|
+
|
|
625
|
+
- [ ] Find all hardcoded role comparisons (`role === 'admin'`, etc.)
|
|
626
|
+
- [ ] Replace with `useAccessLevel` hook or `getRoleContext` API
|
|
627
|
+
- [ ] Test role-based logic still works correctly
|
|
628
|
+
|
|
629
|
+
**Example Migration:**
|
|
630
|
+
|
|
631
|
+
```tsx
|
|
632
|
+
// ❌ OLD
|
|
633
|
+
if (user.role === 'admin') {
|
|
634
|
+
// ...
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// ✅ NEW
|
|
638
|
+
import { useAccessLevel } from '@jmruthers/pace-core/rbac';
|
|
639
|
+
const { accessLevel } = useAccessLevel();
|
|
640
|
+
if (accessLevel === 'admin') {
|
|
641
|
+
// ...
|
|
642
|
+
}
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### Phase 6: Remove Custom Permission Utilities
|
|
646
|
+
|
|
647
|
+
- [ ] Find all custom permission utility functions (`checkPermission`, `hasPermission`, etc.)
|
|
648
|
+
- [ ] Replace with `isPermitted` API or `useCan` hook
|
|
649
|
+
- [ ] Test permission checks still work correctly
|
|
650
|
+
|
|
651
|
+
**Example Migration:**
|
|
652
|
+
|
|
653
|
+
```tsx
|
|
654
|
+
// ❌ OLD
|
|
655
|
+
function checkPermission(userId, permission) {
|
|
656
|
+
// Custom logic...
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// ✅ NEW
|
|
660
|
+
import { isPermitted } from '@jmruthers/pace-core/rbac';
|
|
661
|
+
const hasAccess = await isPermitted({ permission: 'read:dashboard' });
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### Phase 7: Enforce Type-Safe Resource Names
|
|
665
|
+
|
|
666
|
+
- [ ] Create `RESOURCE_NAMES` constant object in your config
|
|
667
|
+
- [ ] Replace all `useResourcePermissions('string-literal')` with `RESOURCE_NAMES.CONSTANT`
|
|
668
|
+
- [ ] Update all permission checks to use constants
|
|
669
|
+
- [ ] Test all resource permissions still work
|
|
670
|
+
|
|
671
|
+
**Example Migration:**
|
|
672
|
+
|
|
673
|
+
```tsx
|
|
674
|
+
// ❌ OLD
|
|
675
|
+
const { canCreate } = useResourcePermissions('journal');
|
|
676
|
+
|
|
677
|
+
// ✅ NEW
|
|
678
|
+
// 1. Create config/resource-names.ts
|
|
679
|
+
export const RESOURCE_NAMES = {
|
|
680
|
+
JOURNAL: 'journal',
|
|
681
|
+
RISKS: 'risks',
|
|
682
|
+
CONTACTS: 'contacts',
|
|
683
|
+
} as const;
|
|
684
|
+
|
|
685
|
+
// 2. Use in components
|
|
686
|
+
import { RESOURCE_NAMES } from '@/config/resource-names';
|
|
687
|
+
const { canCreate } = useResourcePermissions(RESOURCE_NAMES.JOURNAL);
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### Phase 8: Remove Permission Wrapper Functions
|
|
691
|
+
|
|
692
|
+
- [ ] Find all permission wrapper functions (e.g., `canEdit(postId)`, `canDeletePost(postId)`)
|
|
693
|
+
- [ ] Remove wrapper functions from hooks
|
|
694
|
+
- [ ] Update components to use `useResourcePermissions` directly
|
|
695
|
+
- [ ] Test permission checks still work correctly
|
|
696
|
+
|
|
697
|
+
**Example Migration:**
|
|
698
|
+
|
|
699
|
+
```tsx
|
|
700
|
+
// ❌ OLD - In hook
|
|
701
|
+
const canEdit = useCallback((postId: string) => {
|
|
702
|
+
const hasPermission = canUpdate('journal');
|
|
703
|
+
const post = posts.find(p => p.id === postId);
|
|
704
|
+
return hasPermission && !!post;
|
|
705
|
+
}, [posts, canUpdate]);
|
|
706
|
+
|
|
707
|
+
// ❌ OLD - In component
|
|
708
|
+
<JournalEntry canEdit={canEdit(post.id)} />
|
|
709
|
+
|
|
710
|
+
// ✅ NEW - In component
|
|
711
|
+
import { RESOURCE_NAMES } from '@/config/resource-names';
|
|
712
|
+
const { canUpdate } = useResourcePermissions(RESOURCE_NAMES.JOURNAL);
|
|
713
|
+
<JournalEntry canEdit={canUpdate(RESOURCE_NAMES.JOURNAL)} />
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### Phase 9: Update Configuration
|
|
717
|
+
|
|
718
|
+
- [ ] Update `enforcePermissions` for app type
|
|
719
|
+
- [ ] Verify `PagePermissionGuard` on all pages
|
|
720
|
+
- [ ] Test permission enforcement works
|
|
721
|
+
|
|
722
|
+
### Phase 10: Verification
|
|
723
|
+
|
|
724
|
+
- [ ] Run ESLint: `npm run lint`
|
|
725
|
+
- [ ] Run build: `npm run build`
|
|
726
|
+
- [ ] Test all pages and permission checks
|
|
727
|
+
- [ ] Verify no console errors
|
|
728
|
+
|
|
729
|
+
## Common Issues and Solutions
|
|
730
|
+
|
|
731
|
+
### Issue: "EventPageGuard is not defined"
|
|
732
|
+
|
|
733
|
+
**Solution:**
|
|
734
|
+
- Remove `EventPageGuard` import
|
|
735
|
+
- Use `PagePermissionGuard` from `@jmruthers/pace-core/rbac` instead
|
|
736
|
+
|
|
737
|
+
### Issue: "AccessDenied is not defined"
|
|
738
|
+
|
|
739
|
+
**Solution:**
|
|
740
|
+
- Import `AccessDenied` from `@jmruthers/pace-core/rbac`
|
|
741
|
+
- Remove custom access denied components
|
|
742
|
+
|
|
743
|
+
### Issue: "Direct query to RBAC table detected"
|
|
744
|
+
|
|
745
|
+
**Solution:**
|
|
746
|
+
- Use `useSecureSupabase` hook
|
|
747
|
+
- Replace `supabase` with `secureSupabase` in queries
|
|
748
|
+
|
|
749
|
+
### Issue: "Direct RPC call detected"
|
|
750
|
+
|
|
751
|
+
**Solution:**
|
|
752
|
+
- Use `isPermitted` from `@jmruthers/pace-core/rbac`
|
|
753
|
+
- Replace RPC call with `isPermitted` call
|
|
754
|
+
|
|
755
|
+
### Issue: "Route found without PagePermissionGuard"
|
|
756
|
+
|
|
757
|
+
**Solution:**
|
|
758
|
+
- Wrap all route components with `PagePermissionGuard`
|
|
759
|
+
- Add `operation` prop (usually `"read"`)
|
|
760
|
+
|
|
761
|
+
### Issue: "Hardcoded role check detected"
|
|
762
|
+
|
|
763
|
+
**Solution:**
|
|
764
|
+
- Replace `user.role === 'admin'` with `useAccessLevel` hook
|
|
765
|
+
- Use `getRoleContext` API for programmatic checks
|
|
766
|
+
|
|
767
|
+
### Issue: "Custom permission utility function detected"
|
|
768
|
+
|
|
769
|
+
**Solution:**
|
|
770
|
+
- Remove custom permission functions
|
|
771
|
+
- Use `isPermitted` API or `useCan` hook from pace-core
|
|
772
|
+
|
|
773
|
+
### Issue: "Resource permission string literal detected"
|
|
774
|
+
|
|
775
|
+
**Solution:**
|
|
776
|
+
- Create `RESOURCE_NAMES` constant object
|
|
777
|
+
- Replace `useResourcePermissions('journal')` with `useResourcePermissions(RESOURCE_NAMES.JOURNAL)`
|
|
778
|
+
|
|
779
|
+
### Issue: "Permission wrapper function detected"
|
|
780
|
+
|
|
781
|
+
**Solution:**
|
|
782
|
+
- Remove wrapper functions from hooks
|
|
783
|
+
- Use `useResourcePermissions` directly in components
|
|
784
|
+
|
|
785
|
+
## Timeline
|
|
786
|
+
|
|
787
|
+
**Recommended migration order:**
|
|
788
|
+
|
|
789
|
+
1. **Week 1**: Remove wrapper components (EventPageGuard)
|
|
790
|
+
2. **Week 2**: Replace custom access denied components
|
|
791
|
+
3. **Week 3**: Fix direct queries and RPC calls
|
|
792
|
+
4. **Week 4**: Remove hardcoded role checks and custom permission utilities
|
|
793
|
+
5. **Week 5**: Enforce type-safe resource names and remove wrapper functions
|
|
794
|
+
6. **Week 6**: Update configuration and verify
|
|
795
|
+
|
|
796
|
+
**Total estimated time:** 4-6 weeks depending on codebase size
|
|
797
|
+
|
|
798
|
+
## Getting Help
|
|
799
|
+
|
|
800
|
+
If you encounter issues during migration:
|
|
801
|
+
|
|
802
|
+
1. Review [RBAC Contract](./RBAC_CONTRACT.md) for contract details
|
|
803
|
+
2. Check [Troubleshooting Guide](./troubleshooting.md) for common issues
|
|
804
|
+
3. Review [Examples](./examples.md) for migration patterns
|
|
805
|
+
4. Check [API Reference](./api-reference.md) for API details
|
|
806
|
+
|
|
807
|
+
## Related Documentation
|
|
808
|
+
|
|
809
|
+
- [RBAC Contract](./RBAC_CONTRACT.md) - The definitive contract
|
|
810
|
+
- [RBAC README](./README.md) - Overview and quick start
|
|
811
|
+
- [Quick Start Guide](./quick-start.md) - Step-by-step setup
|
|
812
|
+
- [Event-Based Apps](./event-based-apps.md) - Event-based app patterns
|
|
813
|
+
- [Permission Enforcement](../implementation-guides/permission-enforcement.md) - Detailed enforcement patterns
|
|
814
|
+
|
|
815
|
+
---
|
|
816
|
+
|
|
817
|
+
**Last Updated**: 2025-01-04
|
|
818
|
+
**Version**: 2.0.0
|
|
819
|
+
|