@jmruthers/pace-core 0.5.189 → 0.5.191
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/core-usage-manifest.json +0 -4
- package/dist/{AuthService-B-cd2MA4.d.ts → AuthService-CbP_utw2.d.ts} +7 -3
- package/dist/{DataTable-IVYljGJ6.d.ts → DataTable-Be6dH_dR.d.ts} +1 -1
- package/dist/{DataTable-GUFUNZ3N.js → DataTable-WKRZD47S.js} +8 -8
- package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-ULXC_u6U.d.ts} +84 -25
- package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
- package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-FTSG5XH7.js} +4 -2
- package/dist/{api-YP7XD5L6.js → api-IHKALJZD.js} +4 -2
- package/dist/{chunk-VGZZXKBR.js → chunk-6LTQQAT6.js} +351 -157
- package/dist/chunk-6LTQQAT6.js.map +1 -0
- package/dist/{chunk-MX64ZF6I.js → chunk-6TQDD426.js} +15 -15
- package/dist/chunk-6TQDD426.js.map +1 -0
- package/dist/{chunk-YHCN776L.js → chunk-G37KK66H.js} +2 -75
- package/dist/chunk-G37KK66H.js.map +1 -0
- package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
- package/dist/chunk-HW3OVDUF.js.map +1 -0
- package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
- package/dist/chunk-I7PSE6JW.js.map +1 -0
- package/dist/{chunk-IM4QE42D.js → chunk-LOMZXPSN.js} +141 -326
- package/dist/chunk-LOMZXPSN.js.map +1 -0
- package/dist/chunk-OETXORNB.js +614 -0
- package/dist/chunk-OETXORNB.js.map +1 -0
- package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
- package/dist/{chunk-HEHYGYOX.js → chunk-ROXMHMY2.js} +403 -46
- package/dist/chunk-ROXMHMY2.js.map +1 -0
- package/dist/{chunk-2UUZZJFT.js → chunk-ULHIJK66.js} +228 -177
- package/dist/{chunk-2UUZZJFT.js.map → chunk-ULHIJK66.js.map} +1 -1
- package/dist/{chunk-YGPFYGA6.js → chunk-VKB2CO4Z.js} +838 -503
- package/dist/chunk-VKB2CO4Z.js.map +1 -0
- package/dist/{chunk-3GOZZZYH.js → chunk-VRGWKHDB.js} +238 -301
- package/dist/chunk-VRGWKHDB.js.map +1 -0
- package/dist/{chunk-UCQSRW7Z.js → chunk-XNYQOL3Z.js} +431 -384
- package/dist/chunk-XNYQOL3Z.js.map +1 -0
- package/dist/{chunk-DDM4CCYT.js → chunk-XYXSXPUK.js} +79 -59
- package/dist/chunk-XYXSXPUK.js.map +1 -0
- package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
- package/dist/chunk-ZSAAAMVR.js.map +1 -0
- package/dist/components.d.ts +5 -6
- package/dist/components.js +19 -19
- package/dist/components.js.map +1 -1
- package/dist/{database.generated-DI89OQeI.d.ts → database.generated-CzIvgcPu.d.ts} +165 -201
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
- package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
- package/dist/hooks.d.ts +20 -15
- package/dist/hooks.js +14 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +17 -15
- package/dist/index.js +86 -81
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +3 -3
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +77 -13
- package/dist/rbac/index.js +12 -9
- package/dist/{types-Bwgl--Xo.d.ts → types-CEpcvwwF.d.ts} +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-TZe0gy-4.d.ts} +17 -10
- package/dist/utils.d.ts +8 -8
- package/dist/utils.js +16 -16
- package/docs/README.md +2 -2
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +2 -2
- package/docs/api/classes/Logger.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +2 -2
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +2 -2
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +5 -5
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +2 -2
- package/docs/api/classes/SecureSupabaseClient.md +25 -20
- package/docs/api/classes/StorageUtils.md +7 -4
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +1 -1
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AddressFieldProps.md +1 -1
- package/docs/api/interfaces/AddressFieldRef.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/AutocompleteOptions.md +1 -1
- package/docs/api/interfaces/AvatarProps.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +20 -6
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/ComplianceResult.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
- package/docs/api/interfaces/DatabaseIssue.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +62 -16
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +2 -2
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +26 -12
- package/docs/api/interfaces/FileUploadProps.md +30 -19
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoggerConfig.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +7 -7
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/ParsedAddress.md +2 -2
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +3 -11
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/QuickFix.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +2 -2
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +4 -4
- package/docs/api/interfaces/StorageFileInfo.md +7 -7
- package/docs/api/interfaces/StorageFileMetadata.md +25 -14
- package/docs/api/interfaces/StorageListOptions.md +22 -9
- package/docs/api/interfaces/StorageListResult.md +4 -4
- package/docs/api/interfaces/StorageUploadOptions.md +21 -8
- package/docs/api/interfaces/StorageUploadResult.md +6 -6
- package/docs/api/interfaces/StorageUrlOptions.md +19 -6
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
- package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +5 -5
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +165 -106
- package/docs/api-reference/components.md +15 -7
- package/docs/api-reference/providers.md +2 -2
- package/docs/api-reference/rpc-functions.md +1 -0
- package/docs/best-practices/README.md +1 -1
- package/docs/best-practices/deployment.md +8 -8
- package/docs/getting-started/examples/README.md +2 -2
- package/docs/getting-started/installation-guide.md +4 -4
- package/docs/getting-started/quick-start.md +3 -3
- package/docs/migration/MIGRATION_GUIDE.md +3 -3
- package/docs/migration/README.md +18 -0
- package/docs/migration/database-changes-december-2025.md +767 -0
- package/docs/migration/person-scoped-profiles-migration-guide.md +472 -0
- package/docs/rbac/compliance/compliance-guide.md +2 -2
- package/docs/rbac/event-based-apps.md +2 -2
- package/docs/rbac/getting-started.md +2 -2
- package/docs/rbac/quick-start.md +2 -2
- package/docs/security/README.md +4 -4
- package/docs/standards/07-rbac-and-rls-standard.md +430 -7
- package/docs/troubleshooting/README.md +2 -2
- package/docs/troubleshooting/migration.md +3 -3
- package/package.json +1 -3
- package/scripts/check-pace-core-compliance.cjs +1 -1
- package/scripts/check-pace-core-compliance.js +1 -1
- package/src/__tests__/fixtures/supabase.ts +301 -0
- package/src/__tests__/public-recipe-view.test.ts +19 -19
- package/src/__tests__/rls-policies.test.ts +210 -74
- package/src/components/AddressField/AddressField.test.tsx +42 -0
- package/src/components/AddressField/AddressField.tsx +71 -60
- package/src/components/AddressField/README.md +7 -6
- package/src/components/Alert/Alert.test.tsx +50 -10
- package/src/components/Alert/Alert.tsx +5 -3
- package/src/components/Avatar/Avatar.test.tsx +95 -43
- package/src/components/Avatar/Avatar.tsx +16 -16
- package/src/components/Button/Button.test.tsx +2 -1
- package/src/components/Button/Button.tsx +3 -3
- package/src/components/Calendar/Calendar.test.tsx +53 -37
- package/src/components/Calendar/Calendar.tsx +409 -82
- package/src/components/Card/Card.test.tsx +7 -4
- package/src/components/Card/Card.tsx +3 -6
- package/src/components/Checkbox/Checkbox.tsx +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +5 -5
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
- package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
- package/src/components/DataTable/components/DataTableBody.tsx +12 -12
- package/src/components/DataTable/components/DataTableCore.tsx +3 -3
- package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
- package/src/components/DataTable/components/EditableRow.tsx +2 -2
- package/src/components/DataTable/components/EmptyState.tsx +3 -3
- package/src/components/DataTable/components/GroupHeader.tsx +2 -2
- package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +4 -4
- package/src/components/DataTable/components/LoadingState.tsx +1 -1
- package/src/components/DataTable/components/PaginationControls.tsx +11 -11
- package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
- package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
- package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
- package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/EventSelector/EventSelector.tsx +7 -7
- package/src/components/FileDisplay/FileDisplay.tsx +291 -179
- package/src/components/FileUpload/FileUpload.tsx +7 -4
- package/src/components/Header/Header.test.tsx +28 -0
- package/src/components/Header/Header.tsx +22 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +42 -22
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
- package/src/components/PaceAppLayout/test-setup.tsx +1 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
- package/src/components/Progress/Progress.test.tsx +18 -19
- package/src/components/Progress/Progress.tsx +31 -32
- package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
- package/src/components/Select/Select.test.tsx +4 -1
- package/src/components/Select/Select.tsx +65 -20
- package/src/components/Switch/Switch.test.tsx +2 -1
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.test.tsx +8 -2
- package/src/components/UserMenu/UserMenu.tsx +3 -3
- package/src/eslint-rules/pace-core-compliance.cjs +0 -2
- package/src/eslint-rules/pace-core-compliance.js +0 -2
- package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
- package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
- package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
- package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -1
- package/src/hooks/__tests__/usePublicEvent.test.ts +608 -0
- package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +67 -24
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEvent.ts +10 -10
- package/src/hooks/public/usePublicFileDisplay.ts +173 -87
- package/src/hooks/useAppConfig.ts +24 -5
- package/src/hooks/useFileDisplay.ts +298 -36
- package/src/hooks/useFileReference.ts +56 -11
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/useInactivityTracker.ts +16 -7
- package/src/hooks/usePermissionCache.test.ts +85 -8
- package/src/hooks/useQueryCache.ts +27 -6
- package/src/hooks/useSecureDataAccess.test.ts +87 -42
- package/src/hooks/useSecureDataAccess.ts +95 -48
- package/src/providers/__tests__/OrganisationProvider.test.tsx +27 -21
- package/src/providers/services/EventServiceProvider.tsx +37 -17
- package/src/providers/services/InactivityServiceProvider.tsx +4 -4
- package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
- package/src/rbac/api.ts +240 -36
- package/src/rbac/cache-invalidation.ts +21 -7
- package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
- package/src/rbac/components/NavigationGuard.tsx +23 -63
- package/src/rbac/components/NavigationProvider.test.tsx +52 -23
- package/src/rbac/components/NavigationProvider.tsx +13 -11
- package/src/rbac/components/PagePermissionGuard.tsx +77 -203
- package/src/rbac/components/PagePermissionProvider.tsx +13 -11
- package/src/rbac/components/PermissionEnforcer.tsx +24 -62
- package/src/rbac/components/RoleBasedRouter.tsx +14 -12
- package/src/rbac/components/SecureDataProvider.tsx +13 -11
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
- package/src/rbac/engine.ts +4 -2
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
- package/src/rbac/hooks/index.ts +3 -0
- package/src/rbac/hooks/useCan.test.ts +101 -53
- package/src/rbac/hooks/usePermissions.ts +108 -41
- package/src/rbac/hooks/useRBAC.test.ts +11 -3
- package/src/rbac/hooks/useRBAC.ts +83 -40
- package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
- package/src/rbac/hooks/useResolvedScope.ts +128 -70
- package/src/rbac/hooks/useSecureSupabase.ts +36 -19
- package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
- package/src/rbac/request-deduplication.ts +1 -1
- package/src/rbac/secureClient.ts +72 -12
- package/src/rbac/security.ts +29 -23
- package/src/rbac/types.ts +10 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
- package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
- package/src/rbac/utils/__tests__/eventContext.test.ts +8 -3
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +74 -12
- package/src/rbac/utils/contextValidator.ts +288 -0
- package/src/rbac/utils/eventContext.ts +52 -3
- package/src/services/AuthService.ts +37 -8
- package/src/services/EventService.ts +165 -21
- package/src/services/OrganisationService.ts +125 -137
- package/src/services/__tests__/EventService.test.ts +26 -21
- package/src/services/__tests__/OrganisationService.pagination.test.ts +34 -8
- package/src/services/__tests__/OrganisationService.test.ts +218 -86
- package/src/types/database.generated.ts +166 -201
- package/src/types/file-reference.ts +13 -10
- package/src/types/supabase.ts +2 -2
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +3 -2
- package/src/utils/app/appNameResolver.test.ts +346 -73
- package/src/utils/context/superAdminOverride.ts +58 -0
- package/src/utils/file-reference/index.ts +65 -37
- package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
- package/src/utils/google-places/googlePlacesUtils.ts +1 -1
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
- package/src/utils/google-places/types.ts +1 -1
- package/src/utils/request-deduplication.ts +4 -4
- package/src/utils/security/secureDataAccess.test.ts +1 -1
- package/src/utils/security/secureDataAccess.ts +7 -4
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.test.ts +1 -1
- package/src/utils/storage/helpers.ts +38 -19
- package/src/utils/storage/types.ts +15 -8
- package/src/utils/validation/__tests__/csrf.test.ts +105 -0
- package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
- package/src/vite-env.d.ts +2 -2
- package/dist/chunk-3GOZZZYH.js.map +0 -1
- package/dist/chunk-DDM4CCYT.js.map +0 -1
- package/dist/chunk-E7UAOUMY.js +0 -75
- package/dist/chunk-E7UAOUMY.js.map +0 -1
- package/dist/chunk-F2IMUDXZ.js.map +0 -1
- package/dist/chunk-HEHYGYOX.js.map +0 -1
- package/dist/chunk-IM4QE42D.js.map +0 -1
- package/dist/chunk-MX64ZF6I.js.map +0 -1
- package/dist/chunk-SAUPYVLF.js.map +0 -1
- package/dist/chunk-THRPYOFK.js.map +0 -1
- package/dist/chunk-UCQSRW7Z.js.map +0 -1
- package/dist/chunk-VGZZXKBR.js.map +0 -1
- package/dist/chunk-YGPFYGA6.js.map +0 -1
- package/dist/chunk-YHCN776L.js.map +0 -1
- /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-WKRZD47S.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-FTSG5XH7.js.map} +0 -0
- /package/dist/{api-YP7XD5L6.js.map → api-IHKALJZD.js.map} +0 -0
- /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
# Person-Scoped Profiles Migration Guide
|
|
2
|
+
|
|
3
|
+
**Version:** 0.5.190+
|
|
4
|
+
**Migration Date:** 2025-12-05
|
|
5
|
+
**Breaking Changes:** Yes
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Profiles (membership, medical, and contact) have been migrated from **organisation-scoped** to **person-scoped**. Each person now has:
|
|
10
|
+
|
|
11
|
+
- **One membership profile** (`pace_member`) - regardless of organisation
|
|
12
|
+
- **One medical profile** (`medi_profile`) - regardless of organisation
|
|
13
|
+
- **Multiple contact profiles** (`pace_contact`) - person-scoped, multiple per type allowed
|
|
14
|
+
|
|
15
|
+
This change means profiles are no longer tied to specific organisations and are shared across all organisations a person belongs to.
|
|
16
|
+
|
|
17
|
+
## What Changed
|
|
18
|
+
|
|
19
|
+
### Tables Modified
|
|
20
|
+
|
|
21
|
+
#### 1. `pace_member`
|
|
22
|
+
- **Removed:** `organisation_id` column
|
|
23
|
+
- **Added:** Unique constraint on `person_id` (one membership per person)
|
|
24
|
+
- **Impact:** A person can now only have ONE membership record, regardless of how many organisations they belong to
|
|
25
|
+
|
|
26
|
+
#### 2. `medi_profile`
|
|
27
|
+
- **Removed:** `organisation_id` column
|
|
28
|
+
- **Impact:** One medical profile per person (via member relationship)
|
|
29
|
+
|
|
30
|
+
#### 3. `pace_contact`
|
|
31
|
+
- **Removed:** `organisation_id` and `member_id` columns
|
|
32
|
+
- **Added:** `person_id` column (NOT NULL, FK to `pace_person`)
|
|
33
|
+
- **Impact:** Contacts are now directly linked to persons, not members
|
|
34
|
+
|
|
35
|
+
#### 4. Related Tables (organisation_id removed)
|
|
36
|
+
- `medi_condition`
|
|
37
|
+
- `medi_diet`
|
|
38
|
+
- `medi_action_plan`
|
|
39
|
+
- `medi_profile_versions`
|
|
40
|
+
- `pace_consent`
|
|
41
|
+
- `pace_identification`
|
|
42
|
+
- `pace_qualification`
|
|
43
|
+
|
|
44
|
+
### RLS Policy Changes
|
|
45
|
+
|
|
46
|
+
All RLS policies for these tables have been updated to:
|
|
47
|
+
- Remove organisation-based access checks
|
|
48
|
+
- Use person-scoped access control instead
|
|
49
|
+
- Allow access based on person ownership, not organisation membership
|
|
50
|
+
|
|
51
|
+
## Breaking Changes
|
|
52
|
+
|
|
53
|
+
### 1. Queries Filtering by `organisation_id`
|
|
54
|
+
|
|
55
|
+
**Before:**
|
|
56
|
+
```typescript
|
|
57
|
+
// ❌ This will fail - organisation_id column no longer exists
|
|
58
|
+
const { data } = await supabase
|
|
59
|
+
.from('pace_member')
|
|
60
|
+
.select('*')
|
|
61
|
+
.eq('organisation_id', orgId);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**After:**
|
|
65
|
+
```typescript
|
|
66
|
+
// ✅ Filter by person_id instead
|
|
67
|
+
const { data } = await supabase
|
|
68
|
+
.from('pace_member')
|
|
69
|
+
.select('*')
|
|
70
|
+
.eq('person_id', personId);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2. Joins Using `organisation_id`
|
|
74
|
+
|
|
75
|
+
**Before:**
|
|
76
|
+
```typescript
|
|
77
|
+
// ❌ This will fail
|
|
78
|
+
const { data } = await supabase
|
|
79
|
+
.from('pace_member')
|
|
80
|
+
.select('*, organisations(*)')
|
|
81
|
+
.eq('organisation_id', orgId);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**After:**
|
|
85
|
+
```typescript
|
|
86
|
+
// ✅ Join via person → user → organisation memberships
|
|
87
|
+
const { data } = await supabase
|
|
88
|
+
.from('pace_member')
|
|
89
|
+
.select('*, pace_person(*, user_profiles(*))')
|
|
90
|
+
.eq('person_id', personId);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Contact Queries Using `member_id`
|
|
94
|
+
|
|
95
|
+
**Before:**
|
|
96
|
+
```typescript
|
|
97
|
+
// ❌ This will fail - member_id column no longer exists
|
|
98
|
+
const { data } = await supabase
|
|
99
|
+
.from('pace_contact')
|
|
100
|
+
.select('*')
|
|
101
|
+
.eq('member_id', memberId);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**After:**
|
|
105
|
+
```typescript
|
|
106
|
+
// ✅ Use person_id instead
|
|
107
|
+
const { data } = await supabase
|
|
108
|
+
.from('pace_contact')
|
|
109
|
+
.select('*')
|
|
110
|
+
.eq('person_id', personId);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 4. Insert/Update Operations
|
|
114
|
+
|
|
115
|
+
**Before:**
|
|
116
|
+
```typescript
|
|
117
|
+
// ❌ This will fail - organisation_id required
|
|
118
|
+
await supabase
|
|
119
|
+
.from('pace_member')
|
|
120
|
+
.insert({
|
|
121
|
+
person_id: personId,
|
|
122
|
+
organisation_id: orgId, // ❌ Column doesn't exist
|
|
123
|
+
membership_number: '12345'
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**After:**
|
|
128
|
+
```typescript
|
|
129
|
+
// ✅ No organisation_id needed
|
|
130
|
+
await supabase
|
|
131
|
+
.from('pace_member')
|
|
132
|
+
.insert({
|
|
133
|
+
person_id: personId,
|
|
134
|
+
membership_number: '12345'
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Impact Assessment Checklist
|
|
139
|
+
|
|
140
|
+
Use this checklist to identify areas in your app that need updates:
|
|
141
|
+
|
|
142
|
+
### Database Queries
|
|
143
|
+
|
|
144
|
+
- [ ] Search codebase for `pace_member` queries filtering by `organisation_id`
|
|
145
|
+
- [ ] Search codebase for `medi_profile` queries filtering by `organisation_id`
|
|
146
|
+
- [ ] Search codebase for `pace_contact` queries using `member_id`
|
|
147
|
+
- [ ] Search codebase for `pace_consent` queries filtering by `organisation_id`
|
|
148
|
+
- [ ] Search codebase for `pace_identification` queries filtering by `organisation_id`
|
|
149
|
+
- [ ] Search codebase for `pace_qualification` queries filtering by `organisation_id`
|
|
150
|
+
- [ ] Search codebase for `medi_condition`, `medi_diet`, `medi_action_plan` queries filtering by `organisation_id`
|
|
151
|
+
|
|
152
|
+
### TypeScript Types
|
|
153
|
+
|
|
154
|
+
- [ ] Update TypeScript types (regenerate from database schema)
|
|
155
|
+
- [ ] Remove `organisation_id` from type definitions for profile tables
|
|
156
|
+
- [ ] Update `pace_contact` types to use `person_id` instead of `member_id`
|
|
157
|
+
|
|
158
|
+
### UI Components
|
|
159
|
+
|
|
160
|
+
- [ ] Review profile display components - remove organisation context assumptions
|
|
161
|
+
- [ ] Update forms that create/edit profiles - remove organisation_id fields
|
|
162
|
+
- [ ] Update contact management - use person_id instead of member_id
|
|
163
|
+
- [ ] Review profile selection/filtering UI - remove organisation filters
|
|
164
|
+
|
|
165
|
+
### Business Logic
|
|
166
|
+
|
|
167
|
+
- [ ] Review code that assumes multiple memberships per person
|
|
168
|
+
- [ ] Update logic that creates profiles per organisation
|
|
169
|
+
- [ ] Review permission checks that rely on organisation_id for profiles
|
|
170
|
+
- [ ] Update any code that merges/duplicates profiles across organisations
|
|
171
|
+
|
|
172
|
+
### Data Access Patterns
|
|
173
|
+
|
|
174
|
+
- [ ] Review use of `useSecureDataAccess` hook with profile tables
|
|
175
|
+
- [ ] Update any custom data access utilities
|
|
176
|
+
- [ ] Review RPC functions that query profile tables
|
|
177
|
+
|
|
178
|
+
## Code Migration Examples
|
|
179
|
+
|
|
180
|
+
### Example 1: Fetching Member Profile
|
|
181
|
+
|
|
182
|
+
**Before:**
|
|
183
|
+
```typescript
|
|
184
|
+
async function getMemberProfile(personId: string, orgId: string) {
|
|
185
|
+
const { data } = await supabase
|
|
186
|
+
.from('pace_member')
|
|
187
|
+
.select('*')
|
|
188
|
+
.eq('person_id', personId)
|
|
189
|
+
.eq('organisation_id', orgId) // ❌
|
|
190
|
+
.single();
|
|
191
|
+
return data;
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**After:**
|
|
196
|
+
```typescript
|
|
197
|
+
async function getMemberProfile(personId: string) {
|
|
198
|
+
// ✅ No organisation_id needed - one profile per person
|
|
199
|
+
const { data } = await supabase
|
|
200
|
+
.from('pace_member')
|
|
201
|
+
.select('*')
|
|
202
|
+
.eq('person_id', personId)
|
|
203
|
+
.single();
|
|
204
|
+
return data;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Example 2: Fetching Contacts
|
|
209
|
+
|
|
210
|
+
**Before:**
|
|
211
|
+
```typescript
|
|
212
|
+
async function getContacts(memberId: string) {
|
|
213
|
+
const { data } = await supabase
|
|
214
|
+
.from('pace_contact')
|
|
215
|
+
.select('*')
|
|
216
|
+
.eq('member_id', memberId) // ❌
|
|
217
|
+
.eq('organisation_id', orgId); // ❌
|
|
218
|
+
return data;
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**After:**
|
|
223
|
+
```typescript
|
|
224
|
+
async function getContacts(personId: string) {
|
|
225
|
+
// ✅ Use person_id directly
|
|
226
|
+
const { data } = await supabase
|
|
227
|
+
.from('pace_contact')
|
|
228
|
+
.select('*')
|
|
229
|
+
.eq('person_id', personId);
|
|
230
|
+
return data;
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Example 3: Creating Medical Profile
|
|
235
|
+
|
|
236
|
+
**Before:**
|
|
237
|
+
```typescript
|
|
238
|
+
async function createMedicalProfile(memberId: string, orgId: string, data: MedicalData) {
|
|
239
|
+
const { data: profile } = await supabase
|
|
240
|
+
.from('medi_profile')
|
|
241
|
+
.insert({
|
|
242
|
+
member_id: memberId,
|
|
243
|
+
organisation_id: orgId, // ❌
|
|
244
|
+
...data
|
|
245
|
+
})
|
|
246
|
+
.select()
|
|
247
|
+
.single();
|
|
248
|
+
return profile;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**After:**
|
|
253
|
+
```typescript
|
|
254
|
+
async function createMedicalProfile(memberId: string, data: MedicalData) {
|
|
255
|
+
// ✅ No organisation_id needed
|
|
256
|
+
const { data: profile } = await supabase
|
|
257
|
+
.from('medi_profile')
|
|
258
|
+
.insert({
|
|
259
|
+
member_id: memberId,
|
|
260
|
+
...data
|
|
261
|
+
})
|
|
262
|
+
.select()
|
|
263
|
+
.single();
|
|
264
|
+
return profile;
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Example 4: Getting Person's Member in Organisation Context
|
|
269
|
+
|
|
270
|
+
**Before:**
|
|
271
|
+
```typescript
|
|
272
|
+
// ❌ This pattern no longer works
|
|
273
|
+
const member = await getMemberForPersonInOrg(personId, orgId);
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**After:**
|
|
277
|
+
```typescript
|
|
278
|
+
// ✅ Get the person's single membership
|
|
279
|
+
const { data: member } = await supabase
|
|
280
|
+
.from('pace_member')
|
|
281
|
+
.select('*')
|
|
282
|
+
.eq('person_id', personId)
|
|
283
|
+
.single();
|
|
284
|
+
|
|
285
|
+
// If you need to check organisation access, check via rbac_organisation_roles
|
|
286
|
+
const { data: orgRoles } = await supabase
|
|
287
|
+
.from('rbac_organisation_roles')
|
|
288
|
+
.select('organisation_id')
|
|
289
|
+
.eq('user_id', userId)
|
|
290
|
+
.eq('organisation_id', orgId)
|
|
291
|
+
.eq('status', 'active');
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Testing Recommendations
|
|
295
|
+
|
|
296
|
+
### 1. Unit Tests
|
|
297
|
+
|
|
298
|
+
- [ ] Update test fixtures to remove `organisation_id` from profile records
|
|
299
|
+
- [ ] Update mock data generators
|
|
300
|
+
- [ ] Fix tests that assert organisation_id values
|
|
301
|
+
|
|
302
|
+
### 2. Integration Tests
|
|
303
|
+
|
|
304
|
+
- [ ] Test profile creation without organisation_id
|
|
305
|
+
- [ ] Test profile queries by person_id
|
|
306
|
+
- [ ] Test contact management with person_id
|
|
307
|
+
- [ ] Verify RLS policies work correctly
|
|
308
|
+
|
|
309
|
+
### 3. E2E Tests
|
|
310
|
+
|
|
311
|
+
- [ ] Test profile display across different organisations
|
|
312
|
+
- [ ] Verify profiles are shared correctly
|
|
313
|
+
- [ ] Test contact management flows
|
|
314
|
+
- [ ] Verify permission checks still work
|
|
315
|
+
|
|
316
|
+
### 4. Data Validation
|
|
317
|
+
|
|
318
|
+
- [ ] Verify no duplicate memberships exist per person
|
|
319
|
+
- [ ] Verify medical profiles are correctly linked
|
|
320
|
+
- [ ] Verify contacts are correctly migrated to person_id
|
|
321
|
+
|
|
322
|
+
## Common Patterns to Update
|
|
323
|
+
|
|
324
|
+
### Pattern 1: Organisation-Scoped Profile Lists
|
|
325
|
+
|
|
326
|
+
**Before:**
|
|
327
|
+
```typescript
|
|
328
|
+
// Get all members in an organisation
|
|
329
|
+
const { data } = await supabase
|
|
330
|
+
.from('pace_member')
|
|
331
|
+
.select('*')
|
|
332
|
+
.eq('organisation_id', orgId);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**After:**
|
|
336
|
+
```typescript
|
|
337
|
+
// Get all members in an organisation via person → user → org roles
|
|
338
|
+
const { data: orgMembers } = await supabase
|
|
339
|
+
.from('rbac_organisation_roles')
|
|
340
|
+
.select(`
|
|
341
|
+
organisation_id,
|
|
342
|
+
user_id,
|
|
343
|
+
pace_person!inner(
|
|
344
|
+
id,
|
|
345
|
+
pace_member(*)
|
|
346
|
+
)
|
|
347
|
+
`)
|
|
348
|
+
.eq('organisation_id', orgId)
|
|
349
|
+
.eq('status', 'active');
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Pattern 2: Profile Existence Checks
|
|
353
|
+
|
|
354
|
+
**Before:**
|
|
355
|
+
```typescript
|
|
356
|
+
// Check if member exists in organisation
|
|
357
|
+
const { data } = await supabase
|
|
358
|
+
.from('pace_member')
|
|
359
|
+
.select('id')
|
|
360
|
+
.eq('person_id', personId)
|
|
361
|
+
.eq('organisation_id', orgId)
|
|
362
|
+
.single();
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
**After:**
|
|
366
|
+
```typescript
|
|
367
|
+
// Check if person has a membership (regardless of org)
|
|
368
|
+
const { data } = await supabase
|
|
369
|
+
.from('pace_member')
|
|
370
|
+
.select('id')
|
|
371
|
+
.eq('person_id', personId)
|
|
372
|
+
.single();
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Pattern 3: Profile Creation with Organisation Context
|
|
376
|
+
|
|
377
|
+
**Before:**
|
|
378
|
+
```typescript
|
|
379
|
+
// Create profile for person in organisation
|
|
380
|
+
await supabase
|
|
381
|
+
.from('pace_member')
|
|
382
|
+
.insert({
|
|
383
|
+
person_id: personId,
|
|
384
|
+
organisation_id: orgId,
|
|
385
|
+
membership_number: generateNumber()
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**After:**
|
|
390
|
+
```typescript
|
|
391
|
+
// Create profile for person (one per person, not per org)
|
|
392
|
+
// Check if already exists first
|
|
393
|
+
const { data: existing } = await supabase
|
|
394
|
+
.from('pace_member')
|
|
395
|
+
.select('id')
|
|
396
|
+
.eq('person_id', personId)
|
|
397
|
+
.single();
|
|
398
|
+
|
|
399
|
+
if (!existing) {
|
|
400
|
+
await supabase
|
|
401
|
+
.from('pace_member')
|
|
402
|
+
.insert({
|
|
403
|
+
person_id: personId,
|
|
404
|
+
membership_number: generateNumber()
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## TypeScript Type Updates
|
|
410
|
+
|
|
411
|
+
After applying migrations, regenerate your database types:
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
npx supabase gen types typescript --project-id <your-project-id> > src/types/database.generated.ts
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
The updated types will reflect:
|
|
418
|
+
- Removed `organisation_id` from profile tables
|
|
419
|
+
- `pace_contact` using `person_id` instead of `member_id`
|
|
420
|
+
- Updated relationships
|
|
421
|
+
|
|
422
|
+
## RLS Policy Behavior
|
|
423
|
+
|
|
424
|
+
RLS policies now work as follows:
|
|
425
|
+
|
|
426
|
+
1. **Person Ownership**: Users can access profiles for persons they own (via `pace_person.user_id`)
|
|
427
|
+
2. **Contact Permissions**: Users can access contacts where they are the contact person or own the person
|
|
428
|
+
3. **No Organisation Filtering**: Profiles are accessible regardless of organisation context
|
|
429
|
+
4. **Super Admin Override**: Super admins can access all profiles
|
|
430
|
+
|
|
431
|
+
## Migration Support
|
|
432
|
+
|
|
433
|
+
If you encounter issues:
|
|
434
|
+
|
|
435
|
+
1. **Check Migration Status**: Verify all migrations are applied
|
|
436
|
+
2. **Verify Types**: Regenerate TypeScript types from current schema
|
|
437
|
+
3. **Review RLS**: Ensure RLS policies are correctly applied
|
|
438
|
+
4. **Check Logs**: Review Supabase logs for RLS policy violations
|
|
439
|
+
|
|
440
|
+
## RPC Functions Updated
|
|
441
|
+
|
|
442
|
+
The following RPC functions have been updated to work with person-scoped profiles:
|
|
443
|
+
|
|
444
|
+
- **`data_pace_linked_profiles_list`** - Now uses `person_id` from `pace_contact` instead of `member_id`
|
|
445
|
+
- **`data_pace_contacts_list`** - Now uses `person_id` from `pace_contact` instead of `member_id`
|
|
446
|
+
- **`data_pace_contact_get`** - Now uses `person_id` from `pace_contact` instead of `member_id`
|
|
447
|
+
|
|
448
|
+
These functions now:
|
|
449
|
+
- Join `pace_contact` via `person_id` instead of `member_id`
|
|
450
|
+
- Get `member_id` from `pace_member` via `person_id` join
|
|
451
|
+
- Get `organisation_id` from user's organisation roles (since profiles are no longer organisation-scoped)
|
|
452
|
+
|
|
453
|
+
If you have custom RPC functions that reference `pace_contact.member_id` or profile table `organisation_id` columns, you'll need to update them similarly.
|
|
454
|
+
|
|
455
|
+
## Questions?
|
|
456
|
+
|
|
457
|
+
For questions or issues related to this migration:
|
|
458
|
+
- Review the migration files in `supabase/migrations/`
|
|
459
|
+
- Check RLS policy definitions in the migration files
|
|
460
|
+
- Review the pace-core documentation for updated API patterns
|
|
461
|
+
- Check for custom RPC functions that may need updates
|
|
462
|
+
|
|
463
|
+
## Summary
|
|
464
|
+
|
|
465
|
+
**Key Takeaways:**
|
|
466
|
+
- Profiles are now person-scoped, not organisation-scoped
|
|
467
|
+
- Remove all `organisation_id` filters/queries for profile tables
|
|
468
|
+
- Use `person_id` instead of `member_id` for contacts
|
|
469
|
+
- One membership per person (enforced by unique constraint)
|
|
470
|
+
- Update all TypeScript types after migration
|
|
471
|
+
- Test thoroughly, especially cross-organisation scenarios
|
|
472
|
+
|
|
@@ -152,7 +152,7 @@ import { createClient } from '@supabase/supabase-js';
|
|
|
152
152
|
|
|
153
153
|
const supabase = createClient(
|
|
154
154
|
import.meta.env.VITE_SUPABASE_URL,
|
|
155
|
-
import.meta.env.
|
|
155
|
+
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
|
|
156
156
|
);
|
|
157
157
|
|
|
158
158
|
// ⚠️ REQUIRED: Call setupRBAC before rendering
|
|
@@ -266,7 +266,7 @@ import { createClient } from '@supabase/supabase-js';
|
|
|
266
266
|
|
|
267
267
|
export const supabase = createClient(
|
|
268
268
|
import.meta.env.VITE_SUPABASE_URL,
|
|
269
|
-
import.meta.env.
|
|
269
|
+
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
|
|
270
270
|
);
|
|
271
271
|
```
|
|
272
272
|
|
|
@@ -89,7 +89,7 @@ Create `.env.local`:
|
|
|
89
89
|
```bash
|
|
90
90
|
# .env.local
|
|
91
91
|
VITE_SUPABASE_URL=https://your-project.supabase.co
|
|
92
|
-
|
|
92
|
+
VITE_SUPABASE_PUBLISHABLE_KEY=your-publishable-key-here
|
|
93
93
|
VITE_APP_NAME=pace-trac
|
|
94
94
|
```
|
|
95
95
|
|
|
@@ -225,7 +225,7 @@ Create `src/lib/supabase.ts`:
|
|
|
225
225
|
import { createClient } from '@supabase/supabase-js'
|
|
226
226
|
|
|
227
227
|
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
|
228
|
-
const
|
|
228
|
+
const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
|
|
229
229
|
|
|
230
230
|
if (!supabaseUrl || !supabaseAnonKey) {
|
|
231
231
|
throw new Error('Missing Supabase environment variables')
|
|
@@ -99,7 +99,7 @@ import '@jmruthers/pace-core/src/styles/core.css';
|
|
|
99
99
|
// Initialize Supabase
|
|
100
100
|
const supabase = createClient(
|
|
101
101
|
import.meta.env.VITE_SUPABASE_URL!,
|
|
102
|
-
import.meta.env.
|
|
102
|
+
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY!
|
|
103
103
|
);
|
|
104
104
|
|
|
105
105
|
// ⚠️ REQUIRED: Setup RBAC before rendering
|
|
@@ -258,7 +258,7 @@ import App from './App';
|
|
|
258
258
|
// Initialize Supabase
|
|
259
259
|
const supabase = createClient(
|
|
260
260
|
import.meta.env.VITE_SUPABASE_URL!,
|
|
261
|
-
import.meta.env.
|
|
261
|
+
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY!
|
|
262
262
|
);
|
|
263
263
|
|
|
264
264
|
// ⚠️ REQUIRED: Setup RBAC before rendering
|
package/docs/rbac/quick-start.md
CHANGED
|
@@ -88,7 +88,7 @@ Create `.env.local`:
|
|
|
88
88
|
# .env.local
|
|
89
89
|
VITE_SUPABASE_URL=https://your-project.supabase.co
|
|
90
90
|
# Accepts both legacy anon keys and modern publishable keys (sb_publishable_...)
|
|
91
|
-
|
|
91
|
+
VITE_SUPABASE_PUBLISHABLE_KEY=your-publishable-key-here
|
|
92
92
|
VITE_APP_NAME=user-manager
|
|
93
93
|
```
|
|
94
94
|
|
|
@@ -213,7 +213,7 @@ Create `src/lib/supabase.ts`:
|
|
|
213
213
|
import { createClient } from '@supabase/supabase-js'
|
|
214
214
|
|
|
215
215
|
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
|
216
|
-
const
|
|
216
|
+
const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
|
|
217
217
|
|
|
218
218
|
if (!supabaseUrl || !supabaseAnonKey) {
|
|
219
219
|
throw new Error('Missing Supabase environment variables')
|
package/docs/security/README.md
CHANGED
|
@@ -139,10 +139,10 @@ function ProtectedComponent() {
|
|
|
139
139
|
|
|
140
140
|
### 3. Inactivity Auto-Logout
|
|
141
141
|
|
|
142
|
-
PACE Core includes built-in inactivity tracking for enhanced security:
|
|
142
|
+
PACE Core includes built-in inactivity tracking for enhanced security. **All inactivity timeout props are mandatory** - apps must explicitly configure them:
|
|
143
143
|
|
|
144
|
-
- **Automatic logout** after
|
|
145
|
-
- **Warning modal** appears
|
|
144
|
+
- **Automatic logout** after configured period of inactivity (must be configured)
|
|
145
|
+
- **Warning modal** appears before logout (must be configured)
|
|
146
146
|
- **Cross-tab synchronization** - activity in any tab resets the timer
|
|
147
147
|
- **Persistence** - survives page reloads and browser restarts
|
|
148
148
|
- **Production-safe** - cannot be disabled in production builds
|
|
@@ -597,7 +597,7 @@ Secure configuration using environment variables:
|
|
|
597
597
|
```bash
|
|
598
598
|
# Authentication
|
|
599
599
|
VITE_SUPABASE_URL=your_supabase_url
|
|
600
|
-
|
|
600
|
+
VITE_SUPABASE_PUBLISHABLE_KEY=your_publishable_key
|
|
601
601
|
VITE_SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
|
|
602
602
|
|
|
603
603
|
# Security
|