@jmruthers/pace-core 0.5.181 → 0.5.183
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 +1 -1
- package/README.md +16 -2
- package/dist/{AuthService-DYuQPJj6.d.ts → AuthService-B-cd2MA4.d.ts} +9 -11
- package/dist/{DataTable-CWAZZcXC.d.ts → DataTable-Bz8ffqyA.d.ts} +1 -1
- package/dist/{DataTable-UA6CL4JI.js → DataTable-QAB34V6K.js} +14 -15
- package/dist/UnifiedAuthProvider-7F6T4B6K.js +13 -0
- package/dist/{UnifiedAuthProvider-DJxGTftH.d.ts → UnifiedAuthProvider-F86d7dSi.d.ts} +5 -6
- package/dist/{api-45XYYO2A.js → api-ROMBCNKU.js} +5 -5
- package/dist/{audit-64X3VJXB.js → audit-WRS3KJKI.js} +4 -4
- package/dist/auth-BZOJqrdd.d.ts +49 -0
- package/dist/{chunk-CX5M4ZAG.js → chunk-5DRSZLL2.js} +1 -1
- package/dist/chunk-5DRSZLL2.js.map +1 -0
- package/dist/{chunk-BESYRHQM.js → chunk-6C4YBBJM.js} +10 -7
- package/dist/chunk-6C4YBBJM.js.map +1 -0
- package/dist/{chunk-PLDDJCW6.js → chunk-7D4SUZUM.js} +2 -13
- package/dist/{chunk-HRO5HWN2.js → chunk-CSOFYHAG.js} +55 -162
- package/dist/chunk-CSOFYHAG.js.map +1 -0
- package/dist/{chunk-ANBQRTPX.js → chunk-E66EQZE6.js} +3 -5
- package/dist/{chunk-ANBQRTPX.js.map → chunk-E66EQZE6.js.map} +1 -1
- package/dist/{chunk-Q5QRDWKI.js → chunk-F2IMUDXZ.js} +4 -6
- package/dist/chunk-F2IMUDXZ.js.map +1 -0
- package/dist/{chunk-SBVILCCA.js → chunk-FSFQFJCU.js} +28 -6
- package/dist/chunk-FSFQFJCU.js.map +1 -0
- package/dist/chunk-FUEYYMX5.js +2296 -0
- package/dist/chunk-FUEYYMX5.js.map +1 -0
- package/dist/{chunk-FFKNH6U5.js → chunk-HKIT6O7W.js} +3 -5
- package/dist/{chunk-FFKNH6U5.js.map → chunk-HKIT6O7W.js.map} +1 -1
- package/dist/chunk-KQCRWDSA.js +1 -0
- package/dist/{chunk-S5OFRT4M.js → chunk-KUEN3HFB.js} +6 -6
- package/dist/chunk-KUEN3HFB.js.map +1 -0
- package/dist/chunk-LMC26NLJ.js +84 -0
- package/dist/chunk-LMC26NLJ.js.map +1 -0
- package/dist/{chunk-BVYWGZVV.js → chunk-M7W4CP3M.js} +52 -19
- package/dist/chunk-M7W4CP3M.js.map +1 -0
- package/dist/{chunk-HZLDFOE4.js → chunk-MI7HBHN3.js} +164 -243
- package/dist/chunk-MI7HBHN3.js.map +1 -0
- package/dist/{chunk-PPMP5J6T.js → chunk-PWAHJW4G.js} +180 -29
- package/dist/chunk-PWAHJW4G.js.map +1 -0
- package/dist/chunk-PWLANIRT.js +127 -0
- package/dist/{chunk-XDNLUEXI.js.map → chunk-PWLANIRT.js.map} +1 -1
- package/dist/chunk-QCDXODCA.js +75 -0
- package/dist/chunk-QCDXODCA.js.map +1 -0
- package/dist/{chunk-D7LCGMVS.js → chunk-QETLRQI6.js} +526 -887
- package/dist/chunk-QETLRQI6.js.map +1 -0
- package/dist/{chunk-5MT24GKJ.js → chunk-QUVSNGIP.js} +264 -262
- package/dist/chunk-QUVSNGIP.js.map +1 -0
- package/dist/chunk-QXHPKYJV.js +113 -0
- package/dist/chunk-QXHPKYJV.js.map +1 -0
- package/dist/{chunk-OWAG3GSU.js → chunk-R77UEZ4E.js} +11 -1
- package/dist/chunk-R77UEZ4E.js.map +1 -0
- package/dist/{chunk-ZYTYSTO5.js → chunk-RA3JUFMW.js} +314 -161
- package/dist/chunk-RA3JUFMW.js.map +1 -0
- package/dist/{chunk-ERISIBYU.js → chunk-SQGMNID3.js} +3 -8
- package/dist/chunk-SQGMNID3.js.map +1 -0
- package/dist/{chunk-XJ2HZOBU.js → chunk-UHNYIBXL.js} +1 -1
- package/dist/chunk-UHNYIBXL.js.map +1 -0
- package/{src/utils/secureStorage.ts → dist/chunk-VBXEHIUJ.js} +113 -88
- package/dist/{chunk-7QCC6MCP.js.map → chunk-VBXEHIUJ.js.map} +1 -1
- package/dist/{chunk-VZ4VDGTB.js → chunk-W22JP75J.js} +5 -13
- package/dist/{chunk-VZ4VDGTB.js.map → chunk-W22JP75J.js.map} +1 -1
- package/dist/components.d.ts +12 -93
- package/dist/components.js +23 -106
- package/dist/components.js.map +1 -1
- package/dist/core-CUElvH_C.d.ts +164 -0
- package/dist/database.generated-CBmg2950.d.ts +8284 -0
- package/dist/event-CW5YB_2p.d.ts +239 -0
- package/dist/{file-reference-C6Gkn77H.d.ts → file-reference-D06mEEWW.d.ts} +7 -5
- package/dist/functions-D_kgHktt.d.ts +208 -0
- package/dist/hooks.d.ts +54 -7
- package/dist/hooks.js +204 -17
- package/dist/hooks.js.map +1 -1
- package/dist/{EventLogo-B3V3otev.d.ts → index-Bl--n7-T.d.ts} +387 -397
- package/dist/index.d.ts +94 -261
- package/dist/index.js +314 -126
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +7 -8
- package/dist/providers.js +6 -13
- package/dist/rbac/index.d.ts +171 -101
- package/dist/rbac/index.js +23 -17
- package/dist/styles/index.d.ts +1 -3
- package/dist/styles/index.js +2 -17
- package/dist/theming/runtime.js +3 -3
- package/dist/types-UU913iLA.d.ts +102 -0
- package/dist/{types-Dfz9dmVH.d.ts → types-_x1f4QBF.d.ts} +6 -6
- package/dist/types.d.ts +88 -227
- package/dist/types.js +64 -112
- package/dist/types.js.map +1 -1
- package/dist/{usePublicRouteParams-B7PabvuH.d.ts → usePublicRouteParams-JJczomYq.d.ts} +203 -6
- package/dist/utils.d.ts +299 -13
- package/dist/utils.js +481 -55
- package/dist/utils.js.map +1 -1
- package/dist/validation-643vUDZW.d.ts +177 -0
- package/docs/DOCUMENTATION_REVIEW_TRACKER.md +511 -0
- package/docs/README.md +9 -8
- package/docs/api/README.md +16 -2
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +4 -4
- package/docs/api/classes/MissingUserContextError.md +4 -4
- package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
- package/docs/api/classes/PermissionDeniedError.md +4 -4
- package/docs/api/classes/RBACAuditManager.md +14 -14
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +2 -2
- package/docs/api/classes/RBACError.md +4 -4
- package/docs/api/classes/RBACNotInitializedError.md +4 -4
- package/docs/api/classes/SecureSupabaseClient.md +29 -9
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +17 -17
- package/docs/api/enums/RBACErrorCode.md +228 -0
- package/docs/api/enums/RPCFunction.md +118 -0
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +2 -2
- package/docs/api/interfaces/CalendarProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +29 -3
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +2 -2
- package/docs/api/interfaces/DataTableColumn.md +6 -6
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +2 -2
- 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 +5 -5
- package/docs/api/interfaces/ExportOptions.md +4 -4
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +13 -13
- package/docs/api/interfaces/FileReference.md +12 -12
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +10 -10
- package/docs/api/interfaces/FileUploadProps.md +19 -19
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +166 -0
- package/docs/api/interfaces/FormProps.md +113 -0
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +8 -8
- package/docs/api/interfaces/InputProps.md +2 -2
- package/docs/api/interfaces/LabelProps.md +8 -8
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +17 -73
- package/docs/api/interfaces/NavigationMenuProps.md +38 -53
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +13 -13
- package/docs/api/interfaces/OrganisationContextType.md +21 -21
- package/docs/api/interfaces/OrganisationMembership.md +15 -15
- package/docs/api/interfaces/OrganisationProviderProps.md +59 -2
- package/docs/api/interfaces/OrganisationSecurityError.md +5 -5
- package/docs/api/interfaces/PaceAppLayoutProps.md +26 -39
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +50 -0
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
- package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
- package/docs/api/interfaces/PublicPageLayoutProps.md +15 -15
- package/docs/api/interfaces/RBACAccessValidateParams.md +52 -0
- package/docs/api/interfaces/RBACAccessValidateResult.md +41 -0
- package/docs/api/interfaces/RBACAuditLogParams.md +85 -0
- package/docs/api/interfaces/RBACAuditLogResult.md +52 -0
- package/docs/api/interfaces/RBACConfig.md +2 -2
- package/docs/api/interfaces/RBACContext.md +52 -0
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +74 -0
- package/docs/api/interfaces/RBACPermissionCheckParams.md +74 -0
- package/docs/api/interfaces/RBACPermissionCheckResult.md +52 -0
- package/docs/api/interfaces/RBACPermissionsGetParams.md +63 -0
- package/docs/api/interfaces/RBACPermissionsGetResult.md +63 -0
- package/docs/api/interfaces/RBACResult.md +58 -0
- package/docs/api/interfaces/RBACRoleGrantParams.md +63 -0
- package/docs/api/interfaces/RBACRoleGrantResult.md +52 -0
- package/docs/api/interfaces/RBACRoleRevokeParams.md +63 -0
- package/docs/api/interfaces/RBACRoleRevokeResult.md +52 -0
- package/docs/api/interfaces/RBACRoleValidateParams.md +52 -0
- package/docs/api/interfaces/RBACRoleValidateResult.md +63 -0
- package/docs/api/interfaces/RBACRolesListParams.md +52 -0
- package/docs/api/interfaces/RBACRolesListResult.md +74 -0
- package/docs/api/interfaces/RBACSessionTrackParams.md +74 -0
- package/docs/api/interfaces/RBACSessionTrackResult.md +52 -0
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +15 -2
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- 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 +43 -2
- package/docs/api/interfaces/TextareaProps.md +2 -2
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +61 -61
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +87 -0
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +81 -0
- package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
- package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
- 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 +2 -2
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +4 -4
- package/docs/api/interfaces/UserProfile.md +7 -7
- package/docs/api/modules.md +484 -462
- package/docs/api-reference/components.md +186 -15
- package/docs/api-reference/deprecated.md +376 -0
- package/docs/api-reference/hooks.md +149 -19
- package/docs/api-reference/providers.md +61 -6
- package/docs/api-reference/rpc-functions.md +397 -0
- package/docs/api-reference/types.md +135 -78
- package/docs/api-reference/utilities.md +51 -380
- package/docs/architecture/README.md +49 -3
- package/docs/architecture/database-schema-requirements.md +40 -3
- package/docs/architecture/rbac-security-architecture.md +41 -4
- package/docs/architecture/services.md +127 -42
- package/docs/best-practices/README.md +51 -5
- package/docs/best-practices/accessibility.md +32 -3
- package/docs/best-practices/common-patterns.md +50 -3
- package/docs/best-practices/deployment.md +50 -4
- package/docs/best-practices/performance.md +50 -3
- package/docs/best-practices/security.md +94 -41
- package/docs/best-practices/testing.md +33 -4
- package/docs/core-concepts/authentication.md +5 -5
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +3 -3
- package/docs/core-concepts/permissions.md +3 -3
- package/docs/core-concepts/rbac-system.md +5 -5
- package/docs/documentation-index.md +30 -8
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +7 -5
- package/docs/getting-started/examples/basic-auth-app.md +3 -0
- package/docs/getting-started/examples/full-featured-app.md +5 -3
- package/docs/getting-started/faq.md +6 -6
- package/docs/getting-started/installation-guide.md +192 -13
- package/docs/getting-started/local-development.md +303 -0
- package/docs/getting-started/quick-reference.md +3 -3
- package/docs/getting-started/quick-start.md +517 -0
- package/docs/implementation-guides/app-layout.md +45 -3
- package/docs/implementation-guides/authentication.md +66 -7
- package/docs/implementation-guides/component-styling.md +53 -3
- package/docs/implementation-guides/data-tables.md +76 -7
- package/docs/implementation-guides/datatable-filtering.md +1 -2
- package/docs/implementation-guides/datatable-rbac-usage.md +0 -1
- package/docs/implementation-guides/dynamic-colors.md +155 -4
- package/docs/implementation-guides/file-reference-system.md +72 -3
- package/docs/implementation-guides/file-upload-storage.md +72 -3
- package/docs/implementation-guides/forms.md +53 -3
- package/docs/implementation-guides/inactivity-tracking.md +53 -3
- package/docs/implementation-guides/large-datasets.md +1 -1
- package/docs/implementation-guides/navigation.md +55 -5
- package/docs/implementation-guides/organisation-security.md +72 -3
- package/docs/implementation-guides/performance.md +57 -1
- package/docs/implementation-guides/permission-enforcement.md +81 -8
- package/docs/implementation-guides/public-pages.md +560 -14
- package/docs/migration/MIGRATION_GUIDE.md +409 -50
- package/docs/migration/README.md +37 -3
- package/docs/migration/organisation-context-timing-fix.md +39 -4
- package/docs/migration/quick-migration-guide.md +41 -5
- package/docs/migration/rbac-migration.md +59 -3
- package/docs/migration/service-architecture.md +77 -14
- package/docs/rbac/README.md +79 -3
- package/docs/rbac/advanced-patterns.md +47 -3
- package/docs/rbac/api-reference.md +77 -8
- package/docs/rbac/event-based-apps.md +50 -5
- package/docs/rbac/examples/rbac-rls-integration-example.md +3 -3
- package/docs/rbac/examples.md +39 -3
- package/docs/rbac/getting-started.md +63 -4
- package/docs/rbac/quick-start.md +57 -5
- package/docs/rbac/rbac-rls-integration.md +68 -6
- package/docs/rbac/super-admin-guide.md +47 -3
- package/docs/rbac/troubleshooting.md +3 -3
- package/docs/security/README.md +68 -3
- package/docs/security/checklist.md +50 -3
- package/docs/standards/01-architecture-standard.md +39 -0
- package/docs/standards/02-api-and-rpc-standard.md +39 -0
- package/docs/standards/03-component-standard.md +32 -0
- package/docs/standards/04-code-style-standard.md +32 -0
- package/docs/standards/05-security-standard.md +30 -0
- package/docs/standards/06-testing-and-docs-standard.md +29 -0
- package/docs/standards/README.md +35 -0
- package/docs/styles/README.md +89 -8
- package/docs/testing/README.md +175 -24
- package/docs/troubleshooting/README.md +50 -3
- package/docs/troubleshooting/common-issues.md +271 -5
- package/docs/troubleshooting/debugging.md +54 -1
- package/docs/troubleshooting/migration.md +54 -1
- package/docs/troubleshooting/organisation-context-setup.md +29 -3
- package/docs/troubleshooting/styling-issues.md +246 -4
- package/{src/components/DataTable/examples → examples/DataTable}/GroupingAggregationExample.tsx +1 -1
- package/examples/{components 2/DataTable/HierarchicalActionsExample.tsx → DataTable/HierarchicalActionsExample.tsx} +7 -6
- package/{src/components/DataTable/examples → examples/DataTable}/HierarchicalExample.tsx +8 -6
- package/examples/{components 2/DataTable/PerformanceExample.tsx → DataTable/PerformanceExample.tsx} +2 -2
- package/examples/{components 2/DataTable/index.ts → DataTable/index.ts} +1 -0
- package/{src/components/Dialog/examples → examples/Dialog}/HtmlDialogExample.tsx +3 -3
- package/examples/{components 2/Dialog/ScrollableDialogExample.tsx → Dialog/ScrollableDialogExample.tsx} +1 -1
- package/{src/components/Dialog/examples → examples/Dialog}/SmartDialogExample.tsx +1 -1
- package/examples/{components 2/Dialog/index.ts → Dialog/index.ts} +0 -3
- package/examples/{features/public-pages → PublicPages}/CorrectPublicPageImplementation.tsx +52 -17
- package/examples/{features/public-pages → PublicPages}/PublicEventPage.tsx +65 -35
- package/examples/{features/public-pages → PublicPages}/PublicPageApp.tsx +52 -18
- package/examples/{features/public-pages → PublicPages}/PublicPageUsageExample.tsx +28 -15
- package/examples/README.md +81 -33
- package/examples/index.ts +14 -12
- package/examples/{RBAC → rbac}/CompleteRBACExample.tsx +1 -1
- package/examples/{features/rbac → rbac}/EventBasedApp.tsx +4 -4
- package/examples/{features/rbac → rbac}/PermissionExample.tsx +5 -3
- package/package.json +21 -27
- package/src/__tests__/helpers/test-utils.tsx +29 -3
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +7 -5
- package/src/components/Alert/Alert.test.tsx +2 -2
- package/src/components/Alert/Alert.tsx +4 -4
- package/src/components/Avatar/Avatar.test.tsx +17 -6
- package/src/components/Badge/Badge.test.tsx +1 -1
- package/src/components/Badge/Badge.tsx +2 -2
- package/src/components/Button/Button.test.tsx +2 -2
- package/src/components/Button/Button.tsx +11 -7
- package/src/components/Calendar/Calendar.test.tsx +41 -8
- package/src/components/Calendar/Calendar.tsx +39 -36
- package/src/components/Card/Card.tsx +51 -13
- package/src/components/Checkbox/Checkbox.test.tsx +36 -12
- package/src/components/DataTable/DataTable.test.tsx +1 -1
- package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +13 -7
- package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +14 -42
- package/src/components/DataTable/__tests__/DataTable.export.test.tsx +13 -10
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +14 -11
- package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +4 -2
- package/src/components/DataTable/__tests__/DataTable.test.tsx +13 -7
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +13 -10
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +15 -11
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +12 -6
- package/src/components/DataTable/__tests__/keyboard.test.tsx +12 -6
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +10 -6
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +1 -1
- package/src/components/DataTable/components/DataTableBody.tsx +10 -25
- package/src/components/DataTable/components/DataTableCore.tsx +1 -1
- package/src/components/DataTable/components/FilterRow.tsx +3 -1
- package/src/components/DataTable/components/ImportModal.tsx +1 -1
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +9 -9
- package/src/components/DataTable/core/ColumnFactory.ts +6 -6
- package/src/components/DataTable/core/DataTableContext.tsx +14 -10
- package/src/components/DataTable/core/LocalDataAdapter.ts +2 -1
- package/src/components/DataTable/core/PluginRegistry.ts +3 -3
- package/src/components/DataTable/core/StateManager.ts +12 -11
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +104 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +101 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +84 -0
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +102 -0
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +104 -0
- package/src/components/DataTable/core/interfaces.ts +17 -17
- package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +124 -0
- package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +117 -0
- package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +102 -0
- package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +53 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +0 -2
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +9 -8
- package/src/components/DataTable/types.ts +5 -5
- package/src/components/DataTable/utils/aggregationUtils.ts +4 -4
- package/src/components/DataTable/utils/columnUtils.ts +3 -2
- package/src/components/DataTable/utils/debugTools.ts +1 -1
- package/src/components/DataTable/utils/exportUtils.ts +6 -6
- package/src/components/DataTable/utils/hierarchicalSorting.ts +6 -6
- package/src/components/DataTable/utils/hierarchicalUtils.ts +0 -8
- package/src/components/DataTable/utils/index.ts +0 -1
- package/src/components/DataTable/utils/performanceUtils.ts +9 -4
- package/src/components/Dialog/Dialog.test.tsx +49 -27
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +13 -8
- package/src/components/EventSelector/EventSelector.test.tsx +60 -12
- package/src/components/EventSelector/EventSelector.tsx +38 -15
- package/src/components/EventSelector/index.ts +2 -2
- package/src/components/FileDisplay/FileDisplay.test.tsx +143 -85
- package/src/components/FileDisplay/FileDisplay.tsx +1 -0
- package/src/components/FileUpload/FileUpload.test.tsx +532 -152
- package/src/components/FileUpload/FileUpload.tsx +43 -8
- package/src/components/Footer/Footer.test.tsx +19 -14
- package/src/components/Form/Form.test.tsx +96 -14
- package/src/components/Form/Form.tsx +210 -1
- package/src/components/Form/index.ts +3 -7
- package/src/components/Header/Header.test.tsx +24 -17
- package/src/components/Header/Header.tsx +3 -1
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -4
- package/src/components/Input/Input.test.tsx +61 -36
- package/src/components/Label/{__tests__/Label.test.tsx → Label.test.tsx} +2 -2
- package/src/components/Label/Label.tsx +2 -3
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +6 -5
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +6 -2
- package/src/components/LoginForm/LoginForm.test.tsx +14 -13
- package/src/components/LoginForm/LoginForm.tsx +1 -1
- package/src/components/LoginForm/index.ts +7 -0
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +233 -20
- package/src/components/NavigationMenu/NavigationMenu.tsx +191 -55
- package/src/components/NavigationMenu/index.ts +1 -1
- package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +20 -11
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +1 -1
- package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.integration.test.tsx → PaceAppLayout.integration.test.tsx} +272 -79
- package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.performance.test.tsx → PaceAppLayout.performance.test.tsx} +155 -32
- package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.security.test.tsx → PaceAppLayout.security.test.tsx} +211 -65
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +498 -210
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +63 -64
- package/src/components/PaceAppLayout/test-setup.tsx +192 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +193 -39
- package/src/components/{PasswordReset → PasswordChange}/PasswordChangeForm.test.tsx +2 -2
- package/src/components/{PasswordReset → PasswordChange}/PasswordChangeForm.tsx +10 -4
- package/src/components/PasswordChange/index.ts +2 -0
- package/src/components/Progress/Progress.test.tsx +11 -0
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/Progress/index.ts +10 -0
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +2 -1
- package/src/components/PublicLayout/PublicLayout.test.tsx +1210 -0
- package/src/components/PublicLayout/PublicPageLayout.tsx +190 -36
- package/src/components/PublicLayout/PublicPageProvider.tsx +8 -7
- package/src/components/PublicLayout/index.ts +10 -28
- package/src/components/Select/Select.test.tsx +7 -7
- package/src/components/Select/Select.tsx +277 -11
- package/src/components/Select/index.ts +1 -2
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +232 -0
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +40 -19
- package/src/components/Table/{__tests__/Table.test.tsx → Table.test.tsx} +94 -41
- package/src/components/Tabs/Tabs.test.tsx +10 -9
- package/src/components/Tabs/Tabs.tsx +61 -33
- package/src/components/Textarea/Textarea.test.tsx +31 -18
- package/src/components/Toast/Toast.tsx +2 -2
- package/src/components/Tooltip/Tooltip.test.tsx +1 -1
- package/src/components/UserMenu/UserMenu.test.tsx +7 -6
- package/src/components/UserMenu/UserMenu.tsx +2 -2
- package/src/components/index.ts +5 -4
- package/src/constants/performance.ts +19 -8
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +21 -22
- package/src/hooks/__tests__/useEvents.unit.test.ts +5 -4
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +2 -2
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -0
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +16 -11
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -3
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +1 -3
- package/src/hooks/__tests__/useRBAC.unit.test.ts +24 -2
- package/src/hooks/index.ts +4 -0
- package/src/hooks/public/index.ts +2 -0
- package/src/hooks/public/usePublicEvent.ts +4 -6
- package/src/hooks/public/usePublicEventLogo.test.ts +147 -0
- package/src/hooks/public/usePublicRouteParams.ts +1 -1
- package/src/hooks/services/useAuth.ts +2 -4
- package/src/hooks/services/useCurrentEvent.ts +1 -1
- package/src/hooks/useAppConfig.ts +1 -1
- package/src/hooks/useDataTablePerformance.ts +2 -2
- package/src/hooks/useEventTheme.ts +1 -1
- package/src/hooks/useEvents.ts +51 -10
- package/src/hooks/useOrganisationPermissions.test.ts +3 -3
- package/src/hooks/useOrganisationPermissions.ts +1 -1
- package/src/hooks/useOrganisationSecurity.ts +2 -2
- package/src/hooks/usePermissionCache.test.ts +9 -9
- package/src/hooks/usePermissionCache.ts +2 -2
- package/src/index.ts +19 -12
- package/src/providers/OrganisationProvider.tsx +73 -9
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +113 -13
- package/src/providers/__tests__/AuthProvider.test.tsx +2 -1
- package/src/providers/__tests__/EventProvider.test.tsx +24 -15
- package/src/providers/__tests__/OrganisationProvider.test.tsx +87 -36
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +80 -24
- package/src/providers/index.ts +0 -3
- package/src/providers/services/AuthServiceProvider.tsx +2 -17
- package/src/providers/services/EventServiceProvider.tsx +11 -16
- package/src/providers/services/InactivityServiceProvider.tsx +9 -12
- package/src/providers/services/OrganisationServiceProvider.tsx +9 -12
- package/src/providers/services/UnifiedAuthProvider.tsx +85 -18
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +11 -4
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +105 -21
- package/src/rbac/adapters.tsx +1 -1
- package/src/rbac/api.ts +20 -4
- package/src/rbac/audit-enhanced.ts +47 -2
- package/src/rbac/audit.ts +47 -2
- package/src/rbac/components/NavigationGuard.tsx +1 -1
- package/src/rbac/components/NavigationProvider.test.tsx +7 -6
- package/src/rbac/components/NavigationProvider.tsx +1 -1
- package/src/rbac/components/PagePermissionGuard.tsx +1 -1
- package/src/rbac/components/PagePermissionProvider.test.tsx +7 -6
- package/src/rbac/components/PagePermissionProvider.tsx +1 -1
- package/src/rbac/components/PermissionEnforcer.tsx +1 -1
- package/src/rbac/components/RoleBasedRouter.tsx +1 -1
- package/src/rbac/components/SecureDataProvider.test.tsx +7 -6
- package/src/rbac/components/SecureDataProvider.tsx +1 -1
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +6 -6
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +11 -10
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +10 -11
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +19 -15
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +13 -12
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +19 -15
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +18 -18
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +11 -10
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +8 -7
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +10 -11
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +48 -19
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +476 -0
- package/src/rbac/hooks/index.ts +3 -0
- package/src/rbac/hooks/usePermissions.ts +31 -85
- package/src/rbac/hooks/useRBAC.test.ts +13 -1
- package/src/rbac/hooks/useRBAC.ts +13 -67
- package/src/rbac/hooks/useResolvedScope.ts +11 -0
- package/src/rbac/hooks/useSecureSupabase.ts +308 -0
- package/src/rbac/index.ts +3 -0
- package/src/rbac/secureClient.ts +53 -6
- package/src/rbac/security.ts +37 -1
- package/src/{types/rbac-functions.ts → rbac/types/functions.ts} +30 -30
- package/src/rbac/types.ts +3 -2
- package/src/services/AuthService.ts +33 -25
- package/src/services/EventService.ts +56 -44
- package/src/services/InactivityService.ts +33 -53
- package/src/services/OrganisationService.ts +36 -40
- package/src/services/__tests__/AuthService.restoreSession.test.ts +6 -2
- package/src/services/__tests__/EventService.test.ts +67 -33
- package/src/services/interfaces/IEventService.ts +1 -1
- package/src/styles/core.css +2 -2
- package/src/styles/index.test.ts +21 -0
- package/src/styles/index.ts +1 -5
- package/src/types/__tests__/guards.test.ts +1 -1
- package/src/types/__tests__/organisation.roles.test.ts +55 -0
- package/src/types/__tests__/type-validation.test.ts +0 -1
- package/src/types/auth.ts +42 -2
- package/src/types/core.ts +251 -0
- package/src/types/database.ts +11 -496
- package/src/types/event.ts +102 -0
- package/src/types/file-reference.ts +6 -4
- package/src/types/guards.ts +2 -1
- package/src/types/index.ts +48 -14
- package/src/types/lodash.debounce.d.ts +15 -0
- package/src/types/organisation.ts +14 -10
- package/src/types/supabase.ts +15 -17
- package/src/utils/__tests__/secureErrors.unit.test.ts +1 -1
- package/src/utils/__tests__/validationUtils.unit.test.ts +0 -29
- package/src/utils/app/appNameResolver.ts +1 -1
- package/src/utils/audit/audit.test.ts +65 -0
- package/src/utils/device/deviceFingerprint.test.ts +171 -0
- package/src/utils/dynamic/dynamicUtils.ts +3 -2
- package/src/utils/file-reference/index.ts +25 -6
- package/src/utils/security/secureErrors.ts +1 -1
- package/src/utils/validation/__tests__/validationUtils.test.ts +72 -0
- package/src/utils/validation/index.ts +6 -12
- package/src/utils/validation/validationUtils.ts +0 -13
- package/dist/UnifiedAuthProvider-B37ATQHE.js +0 -16
- package/dist/auth-DReDSLq9.d.ts +0 -16
- package/dist/chunk-3JI76CYK.js +0 -2444
- package/dist/chunk-3JI76CYK.js.map +0 -1
- package/dist/chunk-56XJ3TU6.js +0 -11
- package/dist/chunk-56XJ3TU6.js.map +0 -1
- package/dist/chunk-5MT24GKJ.js.map +0 -1
- package/dist/chunk-7QCC6MCP.js +0 -288
- package/dist/chunk-BESYRHQM.js.map +0 -1
- package/dist/chunk-BJPBT3CU.js +0 -21
- package/dist/chunk-BJPBT3CU.js.map +0 -1
- package/dist/chunk-BVYWGZVV.js.map +0 -1
- package/dist/chunk-CX5M4ZAG.js.map +0 -1
- package/dist/chunk-D7LCGMVS.js.map +0 -1
- package/dist/chunk-EGI6MUL6.js +0 -27
- package/dist/chunk-EGI6MUL6.js.map +0 -1
- package/dist/chunk-ERISIBYU.js.map +0 -1
- package/dist/chunk-HRO5HWN2.js.map +0 -1
- package/dist/chunk-HZLDFOE4.js.map +0 -1
- package/dist/chunk-JISYG63F.js +0 -70
- package/dist/chunk-JISYG63F.js.map +0 -1
- package/dist/chunk-LIMSTKYD.js +0 -61
- package/dist/chunk-LIMSTKYD.js.map +0 -1
- package/dist/chunk-OWAG3GSU.js.map +0 -1
- package/dist/chunk-PPMP5J6T.js.map +0 -1
- package/dist/chunk-Q5QRDWKI.js.map +0 -1
- package/dist/chunk-S5OFRT4M.js.map +0 -1
- package/dist/chunk-SBVILCCA.js.map +0 -1
- package/dist/chunk-TUMEWN34.js +0 -15
- package/dist/chunk-TUMEWN34.js.map +0 -1
- package/dist/chunk-XDNLUEXI.js +0 -138
- package/dist/chunk-XJ2HZOBU.js.map +0 -1
- package/dist/chunk-ZYTYSTO5.js.map +0 -1
- package/dist/chunk-ZZ2SS7NI.js +0 -237
- package/dist/chunk-ZZ2SS7NI.js.map +0 -1
- package/dist/database-C6jy7EOu.d.ts +0 -500
- package/dist/organisation-D6qRDtbF.d.ts +0 -93
- package/dist/schema-DTDZQe2u.d.ts +0 -28
- package/dist/unified-DQ4VcT7H.d.ts +0 -198
- package/dist/useInactivityTracker-TO6ZOF35.js +0 -11
- package/dist/validation.d.ts +0 -47
- package/dist/validation.js +0 -24
- package/dist/validation.js.map +0 -1
- package/docs/DOCUMENTATION_AUDIT.md +0 -172
- package/docs/DOCUMENTATION_STANDARD.md +0 -137
- package/docs/api/classes/PublicErrorBoundary.md +0 -132
- package/docs/api/interfaces/EventLogoProps.md +0 -152
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +0 -94
- package/docs/api/interfaces/PublicErrorBoundaryState.md +0 -68
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +0 -86
- package/docs/architecture/rpc-function-standards.md +0 -1106
- package/docs/getting-started/consuming-app-vite-config.md +0 -239
- package/docs/implementation-guides/event-theming-summary.md +0 -226
- package/docs/implementation-guides/public-pages-advanced.md +0 -1038
- package/docs/migration/v0.4.15-tailwind-scanning.md +0 -278
- package/docs/migration/v0.4.16-css-first-approach.md +0 -312
- package/docs/migration/v0.4.17-source-path-fix.md +0 -235
- package/docs/rbac/RBAC_EVENT_CONTEXT_LOADING.md +0 -222
- package/docs/rbac/RBAC_LOGIN_SAFETY_FIX.md +0 -95
- package/docs/rbac/RBAC_V0.5.147_FIX.md +0 -117
- package/docs/rbac/README-rbac-rls-integration.md +0 -374
- package/docs/styles/usage.md +0 -227
- package/docs/testing/visual-testing.md +0 -120
- package/docs/troubleshooting/DEBUG_NETWORK_ERROR.md +0 -152
- package/docs/troubleshooting/FIX_SUPABASE_CORS.md +0 -184
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +0 -193
- package/docs/troubleshooting/database-view-compatibility.md +0 -125
- package/docs/troubleshooting/react-hooks-issue-analysis.md +0 -172
- package/docs/troubleshooting/tailwind-content-scanning.md +0 -219
- package/examples/RBAC/EventBasedApp.tsx +0 -239
- package/examples/RBAC/PermissionExample.tsx +0 -151
- package/examples/STRUCTURE.md +0 -125
- package/examples/components 2/DataTable/HierarchicalExample.tsx +0 -475
- package/examples/components 2/Dialog/BasicHtmlTest.tsx +0 -55
- package/examples/components 2/Dialog/DebugHtmlExample.tsx +0 -68
- package/examples/components 2/Dialog/HtmlDialogExample.tsx +0 -202
- package/examples/components 2/Dialog/SimpleHtmlTest.tsx +0 -61
- package/examples/components 2/Dialog/SmartDialogExample.tsx +0 -322
- package/examples/components 2/index.ts +0 -11
- package/examples/features/index.ts +0 -12
- package/examples/features/rbac/CompleteRBACExample.tsx +0 -324
- package/examples/features/rbac/index.ts +0 -13
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +0 -301
- package/examples/public-pages/PublicEventPage.tsx +0 -274
- package/examples/public-pages/PublicPageApp.tsx +0 -308
- package/examples/public-pages/PublicPageUsageExample.tsx +0 -216
- package/examples/public-pages/index.ts +0 -14
- package/src/__tests__/TEST_STANDARD.md +0 -1008
- package/src/components/Checkbox/__mocks__/Checkbox.tsx +0 -2
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +0 -421
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +0 -177
- package/src/components/DataTable/examples/PerformanceExample.tsx +0 -506
- package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +0 -316
- package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +0 -45
- package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +0 -211
- package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +0 -126
- package/src/components/Dialog/README.md +0 -804
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +0 -55
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +0 -68
- package/src/components/Dialog/examples/ScrollableDialogExample.tsx +0 -290
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +0 -61
- package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +0 -71
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +0 -122
- package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +0 -147
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +0 -611
- package/src/components/Dialog/utils/safeHtml.ts +0 -185
- package/src/components/EventSelector/types.ts +0 -79
- package/src/components/Form/FormErrorSummary.tsx +0 -113
- package/src/components/Form/FormField.tsx +0 -249
- package/src/components/Form/FormFieldset.tsx +0 -127
- package/src/components/Form/FormLiveRegion.tsx +0 -198
- package/src/components/Input/__mocks__/Input.tsx +0 -2
- package/src/components/NavigationMenu/types.ts +0 -85
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +0 -326
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -1078
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
- package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
- package/src/components/PasswordReset/index.ts +0 -2
- package/src/components/ProtectedRoute/README.md +0 -164
- package/src/components/PublicLayout/EventLogo.tsx +0 -175
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +0 -282
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +0 -216
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +0 -131
- package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
- package/src/components/PublicLayout/PublicPageFooter.tsx +0 -124
- package/src/components/PublicLayout/PublicPageHeader.tsx +0 -209
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +0 -449
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +0 -393
- package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +0 -192
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +0 -351
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +0 -402
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +0 -460
- package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +0 -313
- package/src/components/Select/hooks.ts +0 -289
- package/src/hooks/useCounter.test.ts +0 -131
- package/src/hooks/useDebounce.test.ts +0 -375
- package/src/providers/AuthProvider.tsx +0 -15
- package/src/providers/EventProvider.tsx +0 -16
- package/src/providers/InactivityProvider.tsx +0 -15
- package/src/providers/OrganisationProvider.context.test.tsx +0 -169
- package/src/providers/UnifiedAuthProvider.tsx +0 -15
- package/src/types/theme.ts +0 -6
- package/src/types/unified.ts +0 -265
- package/src/utils/appConfig.ts +0 -47
- package/src/utils/appIdResolver.test.ts +0 -499
- package/src/utils/appIdResolver.ts +0 -130
- package/src/utils/appNameResolver.simple.test.ts +0 -212
- package/src/utils/appNameResolver.test.ts +0 -121
- package/src/utils/appNameResolver.ts +0 -191
- package/src/utils/audit.ts +0 -127
- package/src/utils/auth-utils.ts +0 -96
- package/src/utils/bundleAnalysis.ts +0 -129
- package/src/utils/debugLogger.ts +0 -67
- package/src/utils/deviceFingerprint.ts +0 -215
- package/src/utils/dynamicUtils.ts +0 -105
- package/src/utils/file-reference.test.ts +0 -788
- package/src/utils/file-reference.ts +0 -519
- package/src/utils/formatDate.test.ts +0 -237
- package/src/utils/formatting.ts +0 -170
- package/src/utils/lazyLoad.tsx +0 -44
- package/src/utils/logger.ts +0 -179
- package/src/utils/organisationContext.test.ts +0 -322
- package/src/utils/organisationContext.ts +0 -153
- package/src/utils/performanceBenchmark.ts +0 -64
- package/src/utils/performanceBudgets.ts +0 -110
- package/src/utils/permissionTypes.ts +0 -37
- package/src/utils/permissionUtils.test.ts +0 -393
- package/src/utils/permissionUtils.ts +0 -34
- package/src/utils/sanitization.ts +0 -264
- package/src/utils/schemaUtils.ts +0 -37
- package/src/utils/secureDataAccess.test.ts +0 -711
- package/src/utils/secureDataAccess.ts +0 -377
- package/src/utils/secureErrors.ts +0 -79
- package/src/utils/security.ts +0 -156
- package/src/utils/securityMonitor.ts +0 -45
- package/src/utils/sessionTracking.ts +0 -126
- package/src/utils/validation.ts +0 -111
- package/src/utils/validationUtils.ts +0 -120
- package/src/validation/index.ts +0 -12
- /package/dist/{DataTable-UA6CL4JI.js.map → DataTable-QAB34V6K.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-B37ATQHE.js.map → UnifiedAuthProvider-7F6T4B6K.js.map} +0 -0
- /package/dist/{api-45XYYO2A.js.map → api-ROMBCNKU.js.map} +0 -0
- /package/dist/{audit-64X3VJXB.js.map → audit-WRS3KJKI.js.map} +0 -0
- /package/dist/{chunk-PLDDJCW6.js.map → chunk-7D4SUZUM.js.map} +0 -0
- /package/dist/{useInactivityTracker-TO6ZOF35.js.map → chunk-KQCRWDSA.js.map} +0 -0
- /package/examples/{components 2/DataTable → DataTable}/InitialPageSizeExample.tsx +0 -0
- /package/examples/{features/public-pages → PublicPages}/index.ts +0 -0
- /package/examples/{RBAC → rbac}/index.ts +0 -0
|
@@ -1,1106 +0,0 @@
|
|
|
1
|
-
# RPC Function Standards
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This document defines the standards for creating, naming, and structuring RPC (Remote Procedure Call) functions in the PACE Core database. These standards ensure consistency, security, and maintainability across all database functions.
|
|
6
|
-
|
|
7
|
-
## Naming Convention
|
|
8
|
-
|
|
9
|
-
### Pattern
|
|
10
|
-
|
|
11
|
-
RPC function names must follow: **`<family>_<domain>_<verb>`**
|
|
12
|
-
|
|
13
|
-
### Family Prefixes
|
|
14
|
-
|
|
15
|
-
The family prefix categorizes the function's purpose:
|
|
16
|
-
|
|
17
|
-
- **`data_`** - Data access functions that retrieve or manipulate application data
|
|
18
|
-
- Examples: `data_user_events_get`, `data_cake_meals_get`, `data_user_organisations_get`
|
|
19
|
-
|
|
20
|
-
- **`rbac_`** - RBAC (Role-Based Access Control) functions for permission checking, role management, and security
|
|
21
|
-
- Examples: `rbac_check_permission_simplified`, `rbac_permissions_get`, `rbac_role_grant`
|
|
22
|
-
|
|
23
|
-
- **`util_`** - Utility functions for common operations, helpers, and shared logic
|
|
24
|
-
- Examples: `util_app_resolve`, `util_format_date`
|
|
25
|
-
|
|
26
|
-
- **`app_`** - Application-specific functions tied to a particular app module
|
|
27
|
-
- Examples: `app_cake_supply_calculate`, `app_cake_distribution_get`
|
|
28
|
-
|
|
29
|
-
### Domain
|
|
30
|
-
|
|
31
|
-
The domain identifies the entity or context the function operates on:
|
|
32
|
-
|
|
33
|
-
- **User-related**: `user_events`, `user_organisations`, `user_roles`
|
|
34
|
-
- **App-specific**: `cake_meals`, `cake_distribution`, `cake_supply`
|
|
35
|
-
- **System**: `permissions`, `roles`, `session`, `audit`
|
|
36
|
-
|
|
37
|
-
### Verb
|
|
38
|
-
|
|
39
|
-
The verb describes the action being performed:
|
|
40
|
-
|
|
41
|
-
- **`get`** - Retrieve a single record or collection
|
|
42
|
-
- **`list`** - Retrieve a collection (alternative to `get`)
|
|
43
|
-
- **`create`** - Create a new record
|
|
44
|
-
- **`update`** - Update an existing record
|
|
45
|
-
- **`delete`** - Delete a record
|
|
46
|
-
- **`check`** - Validate or check a condition (returns boolean)
|
|
47
|
-
- **`validate`** - Validate data or access (returns boolean or result)
|
|
48
|
-
- **`grant`** - Grant a permission or role
|
|
49
|
-
- **`revoke`** - Revoke a permission or role
|
|
50
|
-
- **`calculate`** - Perform calculations
|
|
51
|
-
- **`resolve`** - Resolve or transform data
|
|
52
|
-
|
|
53
|
-
### Examples
|
|
54
|
-
|
|
55
|
-
```sql
|
|
56
|
-
-- ✅ Good examples
|
|
57
|
-
data_user_events_get -- Get user events
|
|
58
|
-
data_cake_meals_get -- Get cake meals
|
|
59
|
-
rbac_check_permission_simplified -- Check permission
|
|
60
|
-
rbac_permissions_get -- Get permissions
|
|
61
|
-
rbac_role_grant -- Grant role
|
|
62
|
-
util_app_resolve -- Resolve app
|
|
63
|
-
data_cake_distribution_list -- List distribution data
|
|
64
|
-
|
|
65
|
-
-- ❌ Bad examples
|
|
66
|
-
getUserEvents -- Wrong: camelCase, missing prefix
|
|
67
|
-
cake_meals_get -- Wrong: missing family prefix
|
|
68
|
-
rbac_checkPermission -- Wrong: camelCase
|
|
69
|
-
get_cake_meals -- Wrong: wrong prefix order
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Function Structure
|
|
73
|
-
|
|
74
|
-
### Standard Template
|
|
75
|
-
|
|
76
|
-
```sql
|
|
77
|
-
CREATE OR REPLACE FUNCTION public.<family>_<domain>_<verb>(
|
|
78
|
-
p_param1 TEXT, -- ⚠️ Use TEXT for strings, NOT CHARACTER VARYING
|
|
79
|
-
p_param2 INTEGER DEFAULT NULL, -- Use INTEGER, DOUBLE PRECISION, SMALLINT for numbers
|
|
80
|
-
p_param3 BOOLEAN DEFAULT NULL, -- Use BOOLEAN for boolean values
|
|
81
|
-
p_user_id UUID DEFAULT auth.uid(),
|
|
82
|
-
p_organisation_id UUID DEFAULT NULL
|
|
83
|
-
)
|
|
84
|
-
RETURNS TABLE(
|
|
85
|
-
column1 TYPE,
|
|
86
|
-
column2 TYPE
|
|
87
|
-
)
|
|
88
|
-
LANGUAGE plpgsql
|
|
89
|
-
SECURITY DEFINER
|
|
90
|
-
SET search_path TO 'public'
|
|
91
|
-
AS $$
|
|
92
|
-
DECLARE
|
|
93
|
-
v_local_variable TYPE;
|
|
94
|
-
v_is_super_admin BOOLEAN := false;
|
|
95
|
-
BEGIN
|
|
96
|
-
-- 1. Input validation
|
|
97
|
-
IF p_param1 IS NULL THEN
|
|
98
|
-
RETURN;
|
|
99
|
-
END IF;
|
|
100
|
-
|
|
101
|
-
-- 2. Super admin check (if applicable)
|
|
102
|
-
SELECT EXISTS(
|
|
103
|
-
SELECT 1 FROM rbac_global_roles
|
|
104
|
-
WHERE user_id = COALESCE(p_user_id, auth.uid())
|
|
105
|
-
AND role = 'super_admin'
|
|
106
|
-
AND valid_from <= NOW()
|
|
107
|
-
AND (valid_to IS NULL OR valid_to >= NOW())
|
|
108
|
-
) INTO v_is_super_admin;
|
|
109
|
-
|
|
110
|
-
IF v_is_super_admin THEN
|
|
111
|
-
-- Super admin logic
|
|
112
|
-
RETURN QUERY SELECT ...;
|
|
113
|
-
RETURN;
|
|
114
|
-
END IF;
|
|
115
|
-
|
|
116
|
-
-- 3. Organisation context validation (if required)
|
|
117
|
-
IF p_organisation_id IS NULL THEN
|
|
118
|
-
RAISE EXCEPTION 'Organisation context is required';
|
|
119
|
-
RETURN;
|
|
120
|
-
END IF;
|
|
121
|
-
|
|
122
|
-
-- 4. Dynamic RBAC permission check (replaces manual organisation/event checks)
|
|
123
|
-
-- Use rbac_check_permission_simplified() for consistency with RLS policies
|
|
124
|
-
-- ⚠️ CRITICAL: Permission format must match what rbac_permissions_get returns
|
|
125
|
-
-- Format: 'operation:page.{pageName}' (e.g., 'read:page.dishes', 'create:page.meals')
|
|
126
|
-
-- The permission string is passed to rbac_permissions_get and must match exactly
|
|
127
|
-
IF NOT rbac_check_permission_simplified(
|
|
128
|
-
COALESCE(p_user_id, auth.uid()),
|
|
129
|
-
'read:page.dishes', -- Format: operation:page.{pageName} - MUST match rbac_permissions_get output
|
|
130
|
-
p_organisation_id,
|
|
131
|
-
p_event_id, -- p_event_id if event-scoped, NULL if org-scoped
|
|
132
|
-
(SELECT id FROM rbac_apps WHERE name = 'CAKE' LIMIT 1), -- p_app_id
|
|
133
|
-
'dishes' -- p_page_id (page name from rbac_app_pages)
|
|
134
|
-
) THEN
|
|
135
|
-
RETURN; -- No permission
|
|
136
|
-
END IF;
|
|
137
|
-
|
|
138
|
-
-- 5. Main logic (RLS is bypassed but we've checked permissions above)
|
|
139
|
-
RETURN QUERY SELECT ...;
|
|
140
|
-
|
|
141
|
-
EXCEPTION WHEN OTHERS THEN
|
|
142
|
-
RAISE WARNING 'Function failed: %', SQLERRM;
|
|
143
|
-
RETURN;
|
|
144
|
-
END;
|
|
145
|
-
$$;
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Key Requirements
|
|
149
|
-
|
|
150
|
-
1. **Always use `SECURITY DEFINER`** - Functions must run with elevated privileges to bypass RLS. **However**, you must still implement security checks using `rbac_check_permission_simplified()` internally (see Dynamic RLS Integration section above).
|
|
151
|
-
|
|
152
|
-
2. **Always set `SET search_path TO 'public'`** - Prevents SQL injection attacks
|
|
153
|
-
|
|
154
|
-
3. **Parameter Naming and Types**:
|
|
155
|
-
- Prefix all parameters with `p_` (e.g., `p_event_id`, `p_user_id`)
|
|
156
|
-
- Use `p_user_id UUID DEFAULT auth.uid()` for user context
|
|
157
|
-
- Use `p_organisation_id UUID DEFAULT NULL` for organisation context
|
|
158
|
-
- Use descriptive names
|
|
159
|
-
- **⚠️ CRITICAL: Parameter Type Requirements**:
|
|
160
|
-
- **String parameters MUST use `TEXT`**, NOT `CHARACTER VARYING` or `VARCHAR`
|
|
161
|
-
- **Numeric parameters**: Use `DOUBLE PRECISION` for decimal numbers, `INTEGER` for whole numbers, `SMALLINT` for small integers
|
|
162
|
-
- **Boolean parameters**: Use `BOOLEAN`
|
|
163
|
-
- **Date/Time parameters**: Use `DATE`, `TIMESTAMP`, or `TIMESTAMPTZ` as appropriate
|
|
164
|
-
- **UUID parameters**: Use `UUID`
|
|
165
|
-
- **Why TEXT instead of CHARACTER VARYING?**
|
|
166
|
-
- Application code calls functions with TEXT parameters
|
|
167
|
-
- PostgreSQL cannot automatically choose between TEXT and CHARACTER VARYING versions
|
|
168
|
-
- Having both creates ambiguity errors: "Could not choose the best candidate function"
|
|
169
|
-
- TEXT is the standard PostgreSQL type for string parameters in RPC functions
|
|
170
|
-
- Even though database columns may use CHARACTER VARYING, function parameters should use TEXT
|
|
171
|
-
|
|
172
|
-
4. **Variable Naming**:
|
|
173
|
-
- Prefix local variables with `v_` (e.g., `v_is_super_admin`, `v_event_exists`)
|
|
174
|
-
- Use descriptive names
|
|
175
|
-
|
|
176
|
-
5. **Return Types**:
|
|
177
|
-
- Use `RETURNS TABLE(...)` for functions that return multiple rows
|
|
178
|
-
- Use `RETURNS BOOLEAN` for check/validation functions
|
|
179
|
-
- Use `RETURNS JSON` or `RETURNS JSONB` for complex data
|
|
180
|
-
- Use `RETURNS UUID` or `RETURNS TEXT` for single values
|
|
181
|
-
|
|
182
|
-
6. **Error Handling**:
|
|
183
|
-
- Always include `EXCEPTION WHEN OTHERS` block
|
|
184
|
-
- Log errors with `RAISE WARNING` or `RAISE NOTICE`
|
|
185
|
-
- Return empty results on error (fail-secure)
|
|
186
|
-
|
|
187
|
-
7. **Security Checks**:
|
|
188
|
-
- Always check super_admin status first (if applicable)
|
|
189
|
-
- Always use `rbac_check_permission_simplified()` for permission checks (ensures consistency with dynamic RLS)
|
|
190
|
-
- Always validate organisation membership (for non-super-admin)
|
|
191
|
-
- Always validate event access (for event-scoped functions)
|
|
192
|
-
- Never trust client-provided parameters without validation
|
|
193
|
-
- **Important**: Even though RLS is bypassed with `SECURITY DEFINER`, you must implement the same security checks that RLS policies would enforce
|
|
194
|
-
|
|
195
|
-
8. **Comments**:
|
|
196
|
-
- Add header comment explaining function purpose
|
|
197
|
-
- Document parameters
|
|
198
|
-
- Document return value
|
|
199
|
-
- Document security implications
|
|
200
|
-
|
|
201
|
-
## Dynamic RLS Integration
|
|
202
|
-
|
|
203
|
-
### Overview
|
|
204
|
-
|
|
205
|
-
PACE Core uses **Dynamic RLS (Row Level Security)** with RBAC-aware policies. This means RLS policies use `rbac_check_permission_simplified()` to dynamically check permissions based on the current RBAC configuration, rather than hardcoded role checks.
|
|
206
|
-
|
|
207
|
-
### RPC Functions vs RLS Policies
|
|
208
|
-
|
|
209
|
-
There are **two layers** of security in PACE Core:
|
|
210
|
-
|
|
211
|
-
1. **RLS Policies** - For direct table access (client-side queries)
|
|
212
|
-
- Use `rbac_check_permission_simplified()` in policy USING clauses
|
|
213
|
-
- Enforce security at the database level for all direct queries
|
|
214
|
-
- Example: `CREATE POLICY ... USING (rbac_check_permission_simplified(...))`
|
|
215
|
-
|
|
216
|
-
2. **RPC Functions** - For complex operations (server-side logic)
|
|
217
|
-
- Run with `SECURITY DEFINER` which **bypasses RLS**
|
|
218
|
-
- Must implement their own security checks
|
|
219
|
-
- Should use `rbac_check_permission_simplified()` internally for consistency
|
|
220
|
-
|
|
221
|
-
### Why RPC Functions Bypass RLS
|
|
222
|
-
|
|
223
|
-
RPC functions use `SECURITY DEFINER` which bypasses RLS. This is **intentional and required** for several reasons:
|
|
224
|
-
|
|
225
|
-
#### Technical Reasons
|
|
226
|
-
|
|
227
|
-
1. **Performance** - RPC functions need to query multiple tables efficiently without RLS overhead on every operation
|
|
228
|
-
2. **Complex Logic** - Functions perform calculations, aggregations, and joins that RLS policies can't handle elegantly
|
|
229
|
-
3. **Query Optimization** - Functions can optimize queries for specific use cases without RLS interference
|
|
230
|
-
|
|
231
|
-
#### Security Architecture Reasons
|
|
232
|
-
|
|
233
|
-
4. **Centralized Security** - Functions implement security checks in one place rather than relying on multiple RLS policies
|
|
234
|
-
5. **Explicit Control** - Security logic is visible in the function code, not hidden in policy definitions
|
|
235
|
-
6. **Defense in Depth** - Even if RLS has bugs or is misconfigured, RPC function security checks still apply
|
|
236
|
-
7. **RLS as Safety Net** - RLS policies provide defense-in-depth for any direct queries, but RPC functions don't rely on them
|
|
237
|
-
|
|
238
|
-
#### Why This Architecture is Better
|
|
239
|
-
|
|
240
|
-
**Problem with RLS-Only Approach:**
|
|
241
|
-
- RLS policies can have bugs (we saw this with `cake_diner` policy)
|
|
242
|
-
- RLS policies can be misconfigured or forgotten
|
|
243
|
-
- Multiple policies on multiple tables = multiple places for bugs
|
|
244
|
-
- Direct queries bypass security if RLS is broken
|
|
245
|
-
|
|
246
|
-
**Solution with RPC Functions:**
|
|
247
|
-
- All security logic in one place (the function)
|
|
248
|
-
- Explicit permission checks that are easy to audit
|
|
249
|
-
- RLS still exists as defense-in-depth (catches bugs)
|
|
250
|
-
- Can't bypass security even if RLS fails
|
|
251
|
-
|
|
252
|
-
**Important**: You must still implement security checks in the RPC function itself. Bypassing RLS doesn't mean bypassing security - it means implementing security explicitly rather than relying on RLS policies.
|
|
253
|
-
|
|
254
|
-
### Using `rbac_check_permission_simplified()` in RPC Functions
|
|
255
|
-
|
|
256
|
-
RPC functions should use `rbac_check_permission_simplified()` for permission checks to ensure consistency with RLS policies:
|
|
257
|
-
|
|
258
|
-
```sql
|
|
259
|
-
CREATE OR REPLACE FUNCTION data_cake_meals_get(
|
|
260
|
-
p_event_id TEXT,
|
|
261
|
-
p_user_id UUID DEFAULT auth.uid(),
|
|
262
|
-
p_organisation_id UUID DEFAULT NULL
|
|
263
|
-
)
|
|
264
|
-
RETURNS TABLE(...)
|
|
265
|
-
LANGUAGE plpgsql
|
|
266
|
-
SECURITY DEFINER
|
|
267
|
-
SET search_path TO 'public'
|
|
268
|
-
AS $$
|
|
269
|
-
BEGIN
|
|
270
|
-
-- Super admin check (always first)
|
|
271
|
-
IF EXISTS(SELECT 1 FROM rbac_global_roles WHERE user_id = p_user_id AND role = 'super_admin') THEN
|
|
272
|
-
RETURN QUERY SELECT * FROM cake_meal WHERE meal_event_id = p_event_id;
|
|
273
|
-
RETURN;
|
|
274
|
-
END IF;
|
|
275
|
-
|
|
276
|
-
-- Use rbac_check_permission_simplified for dynamic RBAC checking
|
|
277
|
-
-- ⚠️ CRITICAL: Permission format must be 'operation:page.{pageName}'
|
|
278
|
-
-- This matches the format returned by rbac_permissions_get()
|
|
279
|
-
IF NOT rbac_check_permission_simplified(
|
|
280
|
-
p_user_id,
|
|
281
|
-
'read:page.meals', -- Format: operation:page.{pageName}
|
|
282
|
-
p_organisation_id,
|
|
283
|
-
p_event_id,
|
|
284
|
-
(SELECT id FROM rbac_apps WHERE name = 'CAKE' LIMIT 1),
|
|
285
|
-
'meals' -- Page name (resolved to page ID internally)
|
|
286
|
-
) THEN
|
|
287
|
-
RETURN; -- No permission
|
|
288
|
-
END IF;
|
|
289
|
-
|
|
290
|
-
-- Return data (bypasses RLS due to SECURITY DEFINER)
|
|
291
|
-
RETURN QUERY
|
|
292
|
-
SELECT * FROM cake_meal
|
|
293
|
-
WHERE meal_event_id = p_event_id
|
|
294
|
-
AND organisation_id = p_organisation_id;
|
|
295
|
-
END;
|
|
296
|
-
$$;
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### Key Points
|
|
300
|
-
|
|
301
|
-
1. **Always check permissions** - Even though RLS is bypassed, you must check permissions
|
|
302
|
-
2. **Use the same function** - Use `rbac_check_permission_simplified()` just like RLS policies do
|
|
303
|
-
3. **Consistent behavior** - This ensures RPC functions and direct queries have the same security behavior
|
|
304
|
-
4. **Performance** - `rbac_check_permission_simplified()` is optimized and cached
|
|
305
|
-
|
|
306
|
-
### RPC-First Architecture (Recommended)
|
|
307
|
-
|
|
308
|
-
**Security Best Practice**: Use RPC functions as the **primary access method** for all database operations. Treat RLS as defense-in-depth, not a primary security control.
|
|
309
|
-
|
|
310
|
-
#### Why RPC Functions Should Be Preferred
|
|
311
|
-
|
|
312
|
-
1. **Centralized Security Logic**
|
|
313
|
-
- All security checks in one place (the RPC function)
|
|
314
|
-
- Easier to audit and review
|
|
315
|
-
- Consistent behavior across all operations
|
|
316
|
-
|
|
317
|
-
2. **Avoids RLS Bypass Issues**
|
|
318
|
-
- RLS policies can have bugs, be misconfigured, or be bypassed
|
|
319
|
-
- RPC functions with explicit permission checks are more reliable
|
|
320
|
-
- SECURITY DEFINER functions bypass RLS, but implement their own checks
|
|
321
|
-
|
|
322
|
-
3. **Better Performance Control**
|
|
323
|
-
- Can optimize queries for specific use cases
|
|
324
|
-
- Can add caching at the function level
|
|
325
|
-
- Can pre-compute complex operations
|
|
326
|
-
|
|
327
|
-
4. **Audit and Logging**
|
|
328
|
-
- All data access goes through known functions
|
|
329
|
-
- Easier to log and monitor
|
|
330
|
-
- Can add audit trails automatically
|
|
331
|
-
|
|
332
|
-
5. **Business Logic Enforcement**
|
|
333
|
-
- Complex business rules enforced at database level
|
|
334
|
-
- Data validation and transformations in one place
|
|
335
|
-
- Prevents inconsistent logic across applications
|
|
336
|
-
|
|
337
|
-
#### Current Architecture (Allows Both)
|
|
338
|
-
|
|
339
|
-
Currently, PACE Core supports both RPC functions and direct queries:
|
|
340
|
-
|
|
341
|
-
**Use RPC Functions when:**
|
|
342
|
-
- Complex calculations or aggregations needed
|
|
343
|
-
- Multiple tables need to be joined with complex logic
|
|
344
|
-
- Performance is critical (pre-computed results)
|
|
345
|
-
- Business logic is too complex for RLS policies
|
|
346
|
-
- **Security-sensitive operations** (preferred for all operations)
|
|
347
|
-
|
|
348
|
-
**Use Direct Queries (with RLS) when:**
|
|
349
|
-
- Simple CRUD operations (only if RLS policies are properly configured)
|
|
350
|
-
- Standard filtering and sorting
|
|
351
|
-
- Client-side filtering is sufficient
|
|
352
|
-
- No complex business logic required
|
|
353
|
-
- ⚠️ **Not recommended for production** - Use RPC functions instead
|
|
354
|
-
|
|
355
|
-
#### Recommended Future Architecture: RPC-Only Access
|
|
356
|
-
|
|
357
|
-
For maximum security, consider migrating to an **RPC-only architecture**:
|
|
358
|
-
|
|
359
|
-
1. **All table access through RPC functions**
|
|
360
|
-
- Create RPC functions for all data operations
|
|
361
|
-
- Ban direct table queries from application code
|
|
362
|
-
- Use RLS as pure defense-in-depth (should never be relied upon)
|
|
363
|
-
|
|
364
|
-
2. **Benefits of RPC-Only:**
|
|
365
|
-
- **Single point of security enforcement** - All access controlled in functions
|
|
366
|
-
- **Easier auditing** - All access logged through RPC layer
|
|
367
|
-
- **Consistent behavior** - Same security checks for all operations
|
|
368
|
-
- **Easier maintenance** - Security logic in one place
|
|
369
|
-
- **Prevents bugs** - Can't accidentally bypass security by querying directly
|
|
370
|
-
|
|
371
|
-
3. **RLS as Defense-in-Depth:**
|
|
372
|
-
- RLS policies still exist and provide protection
|
|
373
|
-
- But RPC functions bypass them (SECURITY DEFINER)
|
|
374
|
-
- RLS catches any bugs or unauthorized direct access attempts
|
|
375
|
-
- Acts as a safety net, not primary security
|
|
376
|
-
|
|
377
|
-
4. **Migration Path:**
|
|
378
|
-
```
|
|
379
|
-
Phase 1: Create RPC functions for all operations
|
|
380
|
-
Phase 2: Update applications to use RPC functions
|
|
381
|
-
Phase 3: Enable strict mode to log/block direct queries
|
|
382
|
-
Phase 4: Remove direct query access entirely
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
### Example: Consistent Security Between RLS and RPC
|
|
386
|
-
|
|
387
|
-
**RLS Policy (for direct queries):**
|
|
388
|
-
```sql
|
|
389
|
-
CREATE POLICY "rbac_cake_meal_select" ON cake_meal
|
|
390
|
-
FOR SELECT TO authenticated
|
|
391
|
-
USING (
|
|
392
|
-
organisation_id IS NOT NULL
|
|
393
|
-
AND (
|
|
394
|
-
is_user_super_admin()
|
|
395
|
-
OR rbac_check_permission_simplified(
|
|
396
|
-
auth.uid(),
|
|
397
|
-
'read:page.meals', -- Format: operation:page.{pageName}
|
|
398
|
-
organisation_id,
|
|
399
|
-
meal_event_id,
|
|
400
|
-
(SELECT id FROM rbac_apps WHERE name = 'CAKE' LIMIT 1),
|
|
401
|
-
'meals' -- Page name
|
|
402
|
-
)
|
|
403
|
-
)
|
|
404
|
-
);
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
**RPC Function (for complex operations):**
|
|
408
|
-
```sql
|
|
409
|
-
CREATE OR REPLACE FUNCTION data_cake_meals_get(...)
|
|
410
|
-
...
|
|
411
|
-
BEGIN
|
|
412
|
-
-- Same security check logic as RLS policy
|
|
413
|
-
IF NOT (
|
|
414
|
-
v_is_super_admin OR
|
|
415
|
-
rbac_check_permission_simplified(
|
|
416
|
-
p_user_id,
|
|
417
|
-
'read:page.meals', -- Format: operation:page.{pageName}
|
|
418
|
-
p_organisation_id,
|
|
419
|
-
p_event_id,
|
|
420
|
-
(SELECT id FROM rbac_apps WHERE name = 'CAKE' LIMIT 1),
|
|
421
|
-
'meals' -- Page name
|
|
422
|
-
)
|
|
423
|
-
) THEN
|
|
424
|
-
RETURN;
|
|
425
|
-
END IF;
|
|
426
|
-
...
|
|
427
|
-
END;
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
Both use the **same permission checking function**, ensuring consistent security behavior.
|
|
431
|
-
|
|
432
|
-
## Security Best Practices
|
|
433
|
-
|
|
434
|
-
### 1. Input Validation
|
|
435
|
-
|
|
436
|
-
Always validate inputs:
|
|
437
|
-
|
|
438
|
-
```sql
|
|
439
|
-
-- Check for NULL required parameters
|
|
440
|
-
IF p_event_id IS NULL THEN
|
|
441
|
-
RETURN;
|
|
442
|
-
END IF;
|
|
443
|
-
|
|
444
|
-
-- Check for invalid values
|
|
445
|
-
IF NOT EXISTS(SELECT 1 FROM event WHERE event_id = p_event_id) THEN
|
|
446
|
-
RETURN;
|
|
447
|
-
END IF;
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
### 2. Organisation Context
|
|
451
|
-
|
|
452
|
-
Always require organisation context for non-super-admin operations:
|
|
453
|
-
|
|
454
|
-
```sql
|
|
455
|
-
-- Get organisation from context if not provided
|
|
456
|
-
IF p_organisation_id IS NULL THEN
|
|
457
|
-
p_organisation_id := current_setting('app.organisation_id', true)::uuid;
|
|
458
|
-
END IF;
|
|
459
|
-
|
|
460
|
-
IF p_organisation_id IS NULL THEN
|
|
461
|
-
RAISE EXCEPTION 'Organisation context is required';
|
|
462
|
-
END IF;
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
### 3. Super Admin Bypass
|
|
466
|
-
|
|
467
|
-
Always check for super_admin status first:
|
|
468
|
-
|
|
469
|
-
```sql
|
|
470
|
-
DECLARE
|
|
471
|
-
v_is_super_admin BOOLEAN;
|
|
472
|
-
BEGIN
|
|
473
|
-
SELECT EXISTS(
|
|
474
|
-
SELECT 1 FROM rbac_global_roles
|
|
475
|
-
WHERE user_id = COALESCE(p_user_id, auth.uid())
|
|
476
|
-
AND role = 'super_admin'
|
|
477
|
-
AND valid_from <= NOW()
|
|
478
|
-
AND (valid_to IS NULL OR valid_to >= NOW())
|
|
479
|
-
) INTO v_is_super_admin;
|
|
480
|
-
|
|
481
|
-
IF v_is_super_admin THEN
|
|
482
|
-
-- Super admin can access all data
|
|
483
|
-
RETURN QUERY SELECT * FROM table_name;
|
|
484
|
-
RETURN;
|
|
485
|
-
END IF;
|
|
486
|
-
|
|
487
|
-
-- Regular user logic with RBAC checks
|
|
488
|
-
...
|
|
489
|
-
END;
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
### 4. Organisation Membership Validation
|
|
493
|
-
|
|
494
|
-
Always validate organisation membership:
|
|
495
|
-
|
|
496
|
-
```sql
|
|
497
|
-
IF NOT EXISTS(
|
|
498
|
-
SELECT 1 FROM rbac_organisation_roles
|
|
499
|
-
WHERE user_id = COALESCE(p_user_id, auth.uid())
|
|
500
|
-
AND organisation_id = p_organisation_id
|
|
501
|
-
AND status = 'active'
|
|
502
|
-
AND revoked_at IS NULL
|
|
503
|
-
AND valid_from <= NOW()
|
|
504
|
-
AND (valid_to IS NULL OR valid_to >= NOW())
|
|
505
|
-
) THEN
|
|
506
|
-
RETURN; -- No access
|
|
507
|
-
END IF;
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
### 5. Event Access Validation
|
|
511
|
-
|
|
512
|
-
For event-scoped functions:
|
|
513
|
-
|
|
514
|
-
```sql
|
|
515
|
-
IF NOT EXISTS(
|
|
516
|
-
SELECT 1 FROM rbac_event_app_roles
|
|
517
|
-
WHERE user_id = COALESCE(p_user_id, auth.uid())
|
|
518
|
-
AND event_id = p_event_id
|
|
519
|
-
AND app_id = (SELECT id FROM rbac_apps WHERE name = 'CAKE' LIMIT 1)
|
|
520
|
-
AND status = 'active'
|
|
521
|
-
) THEN
|
|
522
|
-
RETURN; -- No event access
|
|
523
|
-
END IF;
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
## Performance Considerations
|
|
527
|
-
|
|
528
|
-
### 1. Use Indexes
|
|
529
|
-
|
|
530
|
-
Ensure queries use indexed columns:
|
|
531
|
-
- `organisation_id`
|
|
532
|
-
- `user_id`
|
|
533
|
-
- `event_id`
|
|
534
|
-
- Foreign key columns
|
|
535
|
-
|
|
536
|
-
### 2. Limit Result Sets
|
|
537
|
-
|
|
538
|
-
Always use `LIMIT` when appropriate:
|
|
539
|
-
|
|
540
|
-
```sql
|
|
541
|
-
RETURN QUERY
|
|
542
|
-
SELECT * FROM table_name
|
|
543
|
-
WHERE condition
|
|
544
|
-
ORDER BY column
|
|
545
|
-
LIMIT 1000; -- Prevent large result sets
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
### 3. Avoid N+1 Queries
|
|
549
|
-
|
|
550
|
-
Use CTEs (Common Table Expressions) or JOINs instead of subqueries:
|
|
551
|
-
|
|
552
|
-
```sql
|
|
553
|
-
-- ❌ Bad: N+1 query pattern
|
|
554
|
-
FOR rec IN SELECT id FROM table1 LOOP
|
|
555
|
-
SELECT * INTO v_data FROM table2 WHERE table1_id = rec.id;
|
|
556
|
-
END LOOP;
|
|
557
|
-
|
|
558
|
-
-- ✅ Good: Single query with JOIN
|
|
559
|
-
RETURN QUERY
|
|
560
|
-
SELECT t1.*, t2.*
|
|
561
|
-
FROM table1 t1
|
|
562
|
-
JOIN table2 t2 ON t2.table1_id = t1.id;
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
### 4. Cache Expensive Checks
|
|
566
|
-
|
|
567
|
-
For functions called frequently, consider caching super_admin checks:
|
|
568
|
-
|
|
569
|
-
```sql
|
|
570
|
-
-- Cache super_admin status in function
|
|
571
|
-
DECLARE
|
|
572
|
-
v_is_super_admin BOOLEAN;
|
|
573
|
-
BEGIN
|
|
574
|
-
-- Check once, use multiple times
|
|
575
|
-
SELECT EXISTS(...) INTO v_is_super_admin;
|
|
576
|
-
|
|
577
|
-
IF v_is_super_admin THEN
|
|
578
|
-
-- Fast path
|
|
579
|
-
ELSE
|
|
580
|
-
-- Regular path with RBAC
|
|
581
|
-
END IF;
|
|
582
|
-
END;
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
## Testing Requirements
|
|
586
|
-
|
|
587
|
-
### Unit Tests
|
|
588
|
-
|
|
589
|
-
Functions should be tested with:
|
|
590
|
-
|
|
591
|
-
1. **Null inputs** - Should handle gracefully
|
|
592
|
-
2. **Invalid inputs** - Should return empty or error
|
|
593
|
-
3. **Super admin access** - Should bypass checks
|
|
594
|
-
4. **Organisation membership** - Should enforce correctly
|
|
595
|
-
5. **Event access** - Should validate for event-scoped functions
|
|
596
|
-
6. **Empty results** - Should return empty set, not error
|
|
597
|
-
7. **Error conditions** - Should fail gracefully
|
|
598
|
-
|
|
599
|
-
### Example Test
|
|
600
|
-
|
|
601
|
-
```sql
|
|
602
|
-
-- Test super admin access
|
|
603
|
-
SELECT * FROM data_user_events_get('event-123', 'super-admin-user-id', NULL);
|
|
604
|
-
-- Should return all events
|
|
605
|
-
|
|
606
|
-
-- Test regular user with access
|
|
607
|
-
SELECT * FROM data_user_events_get('event-123', 'regular-user-id', 'org-123');
|
|
608
|
-
-- Should return events user has access to
|
|
609
|
-
|
|
610
|
-
-- Test user without access
|
|
611
|
-
SELECT * FROM data_user_events_get('event-123', 'unauthorized-user-id', 'org-123');
|
|
612
|
-
-- Should return empty
|
|
613
|
-
|
|
614
|
-
-- Test NULL input
|
|
615
|
-
SELECT * FROM data_user_events_get(NULL, 'user-id', 'org-123');
|
|
616
|
-
-- Should return empty gracefully
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
## Permission Format
|
|
620
|
-
|
|
621
|
-
### ⚠️ CRITICAL: Correct Permission Format
|
|
622
|
-
|
|
623
|
-
**The permission string format is critical and must match exactly what `rbac_permissions_get()` returns.**
|
|
624
|
-
|
|
625
|
-
#### Correct Format
|
|
626
|
-
|
|
627
|
-
```sql
|
|
628
|
-
-- ✅ CORRECT: Format is 'operation:page.{pageName}'
|
|
629
|
-
rbac_check_permission_simplified(
|
|
630
|
-
p_user_id,
|
|
631
|
-
'create:page.dishes', -- Format: operation:page.{pageName}
|
|
632
|
-
p_organisation_id,
|
|
633
|
-
p_event_id,
|
|
634
|
-
v_app_id,
|
|
635
|
-
'dishes' -- Page name (resolved to page ID internally)
|
|
636
|
-
)
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
#### Common Mistakes
|
|
640
|
-
|
|
641
|
-
```sql
|
|
642
|
-
-- ❌ WRONG: Missing 'page.' prefix
|
|
643
|
-
'create:dishes'
|
|
644
|
-
|
|
645
|
-
-- ❌ WRONG: Wrong separator
|
|
646
|
-
'create:page/dishes'
|
|
647
|
-
|
|
648
|
-
-- ❌ WRONG: Wrong format entirely
|
|
649
|
-
'dishes:create'
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
#### How to Determine the Correct Format
|
|
653
|
-
|
|
654
|
-
1. **Check existing migrations** - Look at recent migrations that work
|
|
655
|
-
2. **Check RLS policies** - Use the same format as RLS policies for the same resource
|
|
656
|
-
3. **Verify with rbac_permissions_get** - The permission string must match what this function returns in the `permission_type` column
|
|
657
|
-
|
|
658
|
-
#### Examples by Operation Type
|
|
659
|
-
|
|
660
|
-
```sql
|
|
661
|
-
-- Page-based permissions (most common)
|
|
662
|
-
'read:page.dishes' -- Read dishes page
|
|
663
|
-
'create:page.dishes' -- Create dishes
|
|
664
|
-
'update:page.dishes' -- Update dishes
|
|
665
|
-
'delete:page.dishes' -- Delete dishes
|
|
666
|
-
|
|
667
|
-
'read:page.meals' -- Read meals page
|
|
668
|
-
'read:page.distribution' -- Read distribution page
|
|
669
|
-
'read:page.deliveries' -- Read deliveries page
|
|
670
|
-
|
|
671
|
-
-- File-based permissions (special case)
|
|
672
|
-
'read:files' -- Read files
|
|
673
|
-
'create:files' -- Create files
|
|
674
|
-
'delete:files' -- Delete files
|
|
675
|
-
```
|
|
676
|
-
|
|
677
|
-
#### Parameter Guidelines
|
|
678
|
-
|
|
679
|
-
```sql
|
|
680
|
-
rbac_check_permission_simplified(
|
|
681
|
-
p_user_id, -- User ID (required)
|
|
682
|
-
'create:page.dishes', -- Permission string (format: operation:page.{pageName})
|
|
683
|
-
p_organisation_id, -- Organisation ID (required for non-super-admin)
|
|
684
|
-
p_event_id, -- Event ID (optional, for event-scoped permissions)
|
|
685
|
-
v_app_id, -- App ID (required, usually CAKE app)
|
|
686
|
-
'dishes' -- Page name (required, matches the page name in rbac_app_pages)
|
|
687
|
-
)
|
|
688
|
-
```
|
|
689
|
-
|
|
690
|
-
## Migration Guidelines
|
|
691
|
-
|
|
692
|
-
### Creating New Functions
|
|
693
|
-
|
|
694
|
-
1. **Create migration file with correct timestamp**:
|
|
695
|
-
```bash
|
|
696
|
-
# Generate timestamp: YYYYMMDDHHMMSS
|
|
697
|
-
date +%Y%m%d%H%M%S
|
|
698
|
-
# Example output: 20251104113510
|
|
699
|
-
|
|
700
|
-
# Create file: supabase/migrations/20251104113510_descriptive_name.sql
|
|
701
|
-
```
|
|
702
|
-
⚠️ **CRITICAL**: Always generate a NEW timestamp for each migration. Never reuse timestamps from previous migrations, even if they haven't been pushed yet.
|
|
703
|
-
|
|
704
|
-
2. **Add function**: Use standard template above
|
|
705
|
-
3. **Add comments**: Document purpose, parameters, returns
|
|
706
|
-
4. **Add grants**: `GRANT EXECUTE ON FUNCTION ... TO authenticated;`
|
|
707
|
-
5. **Add tests**: Include test queries in migration
|
|
708
|
-
6. **Regenerate types**: Run `npm run generate-types` to automatically generate TypeScript types from the database schema
|
|
709
|
-
7. **Verify types**: Check that `Database['public']['Functions']['function_name']` exists in `packages/core/src/types/database.generated.ts`
|
|
710
|
-
|
|
711
|
-
### ⚠️ Common Migration Mistakes
|
|
712
|
-
|
|
713
|
-
1. **Reusing old migration timestamps**:
|
|
714
|
-
- ❌ **WRONG**: Reusing `20251104113047` if it's already been pushed
|
|
715
|
-
- ✅ **CORRECT**: Generate new timestamp: `date +%Y%m%d%H%M%S` → `20251104113510`
|
|
716
|
-
- Always create a NEW file with a NEW timestamp for each migration
|
|
717
|
-
|
|
718
|
-
2. **Wrong permission format**:
|
|
719
|
-
- ❌ **WRONG**: `'create:dishes'` or `'read:meals'`
|
|
720
|
-
- ✅ **CORRECT**: `'create:page.dishes'` or `'read:page.meals'`
|
|
721
|
-
- Always use `'operation:page.{pageName}'` format, not `'operation:resource'`
|
|
722
|
-
- The format must match exactly what `rbac_permissions_get()` returns
|
|
723
|
-
|
|
724
|
-
3. **Missing page_id parameter**: Always provide the page name as the last parameter (e.g., `'dishes'`, `'meals'`, `'distribution'`)
|
|
725
|
-
|
|
726
|
-
4. **Using CHARACTER VARYING instead of TEXT for string parameters**:
|
|
727
|
-
- ❌ **WRONG**: `p_unit_id CHARACTER VARYING` or `p_dish_name VARCHAR`
|
|
728
|
-
- ✅ **CORRECT**: `p_unit_id TEXT` or `p_dish_name TEXT`
|
|
729
|
-
- **CRITICAL**: All string parameters MUST use `TEXT`, NOT `CHARACTER VARYING` or `VARCHAR`
|
|
730
|
-
- Having both TEXT and CHARACTER VARYING versions causes "Could not choose the best candidate function" errors
|
|
731
|
-
- Application code calls functions with TEXT parameters, so functions must accept TEXT
|
|
732
|
-
- Even though database columns may use CHARACTER VARYING, function parameters should use TEXT
|
|
733
|
-
|
|
734
|
-
5. **Creating duplicate function versions**:
|
|
735
|
-
- ❌ **WRONG**: Creating both `app_cake_unit_update(TEXT, ...)` and `app_cake_unit_update(CHARACTER VARYING, ...)`
|
|
736
|
-
- ✅ **CORRECT**: Only create `app_cake_unit_update(TEXT, ...)`
|
|
737
|
-
- Before creating a new function, check if a version already exists
|
|
738
|
-
- If updating a function, use `CREATE OR REPLACE FUNCTION` to update the existing version
|
|
739
|
-
- If you need to change parameter types, drop the old version first: `DROP FUNCTION IF EXISTS ... CASCADE;`
|
|
740
|
-
|
|
741
|
-
6. **Ambiguous column references**:
|
|
742
|
-
- ❌ **WRONG**: `SELECT mealtype_name FROM cake_mealtype`
|
|
743
|
-
- ✅ **CORRECT**: `SELECT cake_mealtype.mealtype_name FROM cake_mealtype`
|
|
744
|
-
- Always fully qualify table names when there might be ambiguity
|
|
745
|
-
- **MANDATORY**: When using JOINs, always use table aliases and prefix ALL column references
|
|
746
|
-
- Common ambiguous columns: `organisation_id`, `created_by`, `updated_by`, `created_at`, `updated_at`
|
|
747
|
-
- See "Avoiding Ambiguous Column References" section below for detailed guidance
|
|
748
|
-
|
|
749
|
-
7. **Not checking existing migrations**: Before creating a new migration, check if a similar one already exists to avoid duplicates
|
|
750
|
-
|
|
751
|
-
### Updating Existing Functions
|
|
752
|
-
|
|
753
|
-
1. **Use `CREATE OR REPLACE FUNCTION`** - Ensures idempotency
|
|
754
|
-
2. **Preserve backward compatibility** - Add new parameters with defaults
|
|
755
|
-
3. **Version changes** - Update function name if breaking changes (e.g., `_v2`)
|
|
756
|
-
4. **Document changes** - Add comments explaining changes
|
|
757
|
-
5. **Regenerate types**: Run `npm run generate-types` after function changes to update TypeScript types
|
|
758
|
-
|
|
759
|
-
### Deprecating Functions
|
|
760
|
-
|
|
761
|
-
1. **Add deprecation notice**:
|
|
762
|
-
```sql
|
|
763
|
-
COMMENT ON FUNCTION old_function IS 'DEPRECATED: Use new_function instead';
|
|
764
|
-
```
|
|
765
|
-
|
|
766
|
-
2. **Keep function** - Don't delete immediately, allow migration period
|
|
767
|
-
|
|
768
|
-
3. **Update references** - Update all callers before removing
|
|
769
|
-
|
|
770
|
-
## Avoiding Ambiguous Column References
|
|
771
|
-
|
|
772
|
-
### Overview
|
|
773
|
-
|
|
774
|
-
Ambiguous column reference errors occur when PostgreSQL cannot determine which table a column belongs to in a query with JOINs. This is a common source of silent failures in RPC functions.
|
|
775
|
-
|
|
776
|
-
### Mandatory Rules
|
|
777
|
-
|
|
778
|
-
1. **Always use table aliases in JOINs**: Never write JOINs without table aliases
|
|
779
|
-
2. **Fully qualify ALL column references**: Every column in SELECT, WHERE, ORDER BY, GROUP BY, and HAVING clauses must be prefixed with its table alias
|
|
780
|
-
3. **Common ambiguous columns**: The following columns exist in multiple tables and MUST always be prefixed:
|
|
781
|
-
- `organisation_id`
|
|
782
|
-
- `created_by`, `updated_by`
|
|
783
|
-
- `created_at`, `updated_at`
|
|
784
|
-
- `event_id` and its variations (e.g., `dish_event_id`, `meal_event_id`)
|
|
785
|
-
|
|
786
|
-
### Correct Patterns
|
|
787
|
-
|
|
788
|
-
```sql
|
|
789
|
-
-- ✅ CORRECT: All columns properly prefixed with table aliases
|
|
790
|
-
SELECT
|
|
791
|
-
d.dish_id,
|
|
792
|
-
d.dish_name,
|
|
793
|
-
d.organisation_id,
|
|
794
|
-
d.created_at,
|
|
795
|
-
mt.mealtype_name,
|
|
796
|
-
e.event_name,
|
|
797
|
-
e.organisation_id AS event_organisation_id
|
|
798
|
-
FROM cake_dish d
|
|
799
|
-
LEFT JOIN cake_mealtype mt ON d.dish_mealtype_id = mt.mealtype_id
|
|
800
|
-
LEFT JOIN event e ON d.dish_event_id = e.event_id
|
|
801
|
-
WHERE d.dish_event_id = p_event_id
|
|
802
|
-
AND d.organisation_id = p_organisation_id
|
|
803
|
-
ORDER BY d.dish_code, mt.mealtype_name;
|
|
804
|
-
|
|
805
|
-
-- ✅ CORRECT: CTEs with proper aliases
|
|
806
|
-
WITH distribution_items AS (
|
|
807
|
-
SELECT
|
|
808
|
-
d.item_id,
|
|
809
|
-
d.collection_date,
|
|
810
|
-
SUM(d.required_quantity) as total_quantity
|
|
811
|
-
FROM data_cake_distribution_list(p_event_id, p_user_id, p_organisation_id) d
|
|
812
|
-
GROUP BY d.item_id, d.collection_date
|
|
813
|
-
)
|
|
814
|
-
SELECT
|
|
815
|
-
di.item_id,
|
|
816
|
-
di.collection_date,
|
|
817
|
-
di.total_quantity
|
|
818
|
-
FROM distribution_items di
|
|
819
|
-
WHERE di.item_id = p_item_id;
|
|
820
|
-
```
|
|
821
|
-
|
|
822
|
-
### Incorrect Patterns
|
|
823
|
-
|
|
824
|
-
```sql
|
|
825
|
-
-- ❌ WRONG: Missing table prefixes in SELECT
|
|
826
|
-
SELECT
|
|
827
|
-
dish_id,
|
|
828
|
-
dish_name,
|
|
829
|
-
organisation_id, -- AMBIGUOUS: Could be from cake_dish or event
|
|
830
|
-
mealtype_name
|
|
831
|
-
FROM cake_dish d
|
|
832
|
-
LEFT JOIN cake_mealtype mt ON d.dish_mealtype_id = mt.mealtype_id
|
|
833
|
-
LEFT JOIN event e ON d.dish_event_id = e.event_id;
|
|
834
|
-
|
|
835
|
-
-- ❌ WRONG: Missing table prefix in WHERE clause
|
|
836
|
-
SELECT d.dish_id, d.dish_name
|
|
837
|
-
FROM cake_dish d
|
|
838
|
-
LEFT JOIN event e ON d.dish_event_id = e.event_id
|
|
839
|
-
WHERE organisation_id = p_organisation_id; -- AMBIGUOUS: Which table?
|
|
840
|
-
|
|
841
|
-
-- ❌ WRONG: Missing table prefix in ORDER BY
|
|
842
|
-
SELECT d.dish_id, d.dish_name, e.event_name
|
|
843
|
-
FROM cake_dish d
|
|
844
|
-
LEFT JOIN event e ON d.dish_event_id = e.event_id
|
|
845
|
-
ORDER BY created_at; -- AMBIGUOUS: Which table's created_at?
|
|
846
|
-
|
|
847
|
-
-- ❌ WRONG: SELECT INTO with multiple columns but wrong variable count
|
|
848
|
-
SELECT d.dish_code, d.dish_name, mt.mealtype_name
|
|
849
|
-
INTO v_mealtype_name -- WRONG: Only one variable for three columns
|
|
850
|
-
FROM cake_dish d
|
|
851
|
-
LEFT JOIN cake_mealtype mt ON d.dish_mealtype_id = mt.mealtype_id;
|
|
852
|
-
```
|
|
853
|
-
|
|
854
|
-
### SELECT INTO Statements
|
|
855
|
-
|
|
856
|
-
When using `SELECT ... INTO`, ensure:
|
|
857
|
-
1. The number of columns matches the number of variables
|
|
858
|
-
2. All columns are properly prefixed with table aliases
|
|
859
|
-
3. Use separate variables for each column
|
|
860
|
-
|
|
861
|
-
```sql
|
|
862
|
-
-- ✅ CORRECT: Proper SELECT INTO with multiple variables
|
|
863
|
-
DECLARE
|
|
864
|
-
v_dish_code TEXT;
|
|
865
|
-
v_dish_name TEXT;
|
|
866
|
-
v_mealtype_name TEXT;
|
|
867
|
-
v_updated_at TIMESTAMPTZ;
|
|
868
|
-
BEGIN
|
|
869
|
-
SELECT
|
|
870
|
-
d.dish_code,
|
|
871
|
-
d.dish_name,
|
|
872
|
-
mt.mealtype_name,
|
|
873
|
-
d.updated_at
|
|
874
|
-
INTO
|
|
875
|
-
v_dish_code,
|
|
876
|
-
v_dish_name,
|
|
877
|
-
v_mealtype_name,
|
|
878
|
-
v_updated_at
|
|
879
|
-
FROM cake_dish d
|
|
880
|
-
LEFT JOIN cake_mealtype mt ON d.dish_mealtype_id = mt.mealtype_id
|
|
881
|
-
WHERE d.dish_id = p_dish_id;
|
|
882
|
-
END;
|
|
883
|
-
```
|
|
884
|
-
|
|
885
|
-
### CTEs and Subqueries
|
|
886
|
-
|
|
887
|
-
When using CTEs (Common Table Expressions) or subqueries:
|
|
888
|
-
1. Use descriptive aliases for CTEs
|
|
889
|
-
2. Fully qualify all column references within CTEs
|
|
890
|
-
3. When referencing CTEs in the main query, use the CTE alias
|
|
891
|
-
|
|
892
|
-
```sql
|
|
893
|
-
-- ✅ CORRECT: CTE with proper aliases
|
|
894
|
-
WITH unit_diners AS (
|
|
895
|
-
SELECT
|
|
896
|
-
d.diner_unit_id,
|
|
897
|
-
d.diner_diettype_id,
|
|
898
|
-
SUM(COALESCE(d.diner_adult, 0)) as adults,
|
|
899
|
-
SUM(COALESCE(d.diner_youth, 0)) as youth
|
|
900
|
-
FROM cake_diner d
|
|
901
|
-
INNER JOIN event_units eu ON d.diner_unit_id = eu.unit_id
|
|
902
|
-
WHERE (d.diner_adult > 0 OR d.diner_youth > 0)
|
|
903
|
-
GROUP BY d.diner_unit_id, d.diner_diettype_id
|
|
904
|
-
)
|
|
905
|
-
SELECT
|
|
906
|
-
ud.diner_unit_id,
|
|
907
|
-
ud.adults,
|
|
908
|
-
ud.youth
|
|
909
|
-
FROM unit_diners ud
|
|
910
|
-
WHERE ud.diner_unit_id = p_unit_id;
|
|
911
|
-
```
|
|
912
|
-
|
|
913
|
-
### Table Alias Naming Conventions
|
|
914
|
-
|
|
915
|
-
Use short, descriptive aliases:
|
|
916
|
-
- `d` for `cake_dish`
|
|
917
|
-
- `r` for `cake_recipe`
|
|
918
|
-
- `m` for `cake_meal`
|
|
919
|
-
- `mt` for `cake_mealtype`
|
|
920
|
-
- `i` for `cake_item`
|
|
921
|
-
- `dt` for `cake_diettype`
|
|
922
|
-
- `e` for `event`
|
|
923
|
-
- `u` for `cake_unit`
|
|
924
|
-
- `mp` for `cake_mealplan`
|
|
925
|
-
|
|
926
|
-
### UPDATE Statements
|
|
927
|
-
|
|
928
|
-
For UPDATE statements, the WHERE clause should reference the table being updated:
|
|
929
|
-
|
|
930
|
-
```sql
|
|
931
|
-
-- ✅ CORRECT: WHERE clause uses table name or alias
|
|
932
|
-
UPDATE cake_dish
|
|
933
|
-
SET dish_name = p_dish_name,
|
|
934
|
-
updated_by = p_user_id,
|
|
935
|
-
updated_at = now()
|
|
936
|
-
WHERE dish_id = p_dish_id; -- dish_id is unambiguous (primary key)
|
|
937
|
-
|
|
938
|
-
-- ✅ CORRECT: When updating with JOIN, qualify all columns
|
|
939
|
-
UPDATE cake_dish d
|
|
940
|
-
SET d.dish_name = p_dish_name
|
|
941
|
-
FROM cake_mealtype mt
|
|
942
|
-
WHERE d.dish_mealtype_id = mt.mealtype_id
|
|
943
|
-
AND d.dish_id = p_dish_id;
|
|
944
|
-
```
|
|
945
|
-
|
|
946
|
-
### Testing for Ambiguous References
|
|
947
|
-
|
|
948
|
-
Before deploying, test your function:
|
|
949
|
-
1. Call the function with valid parameters
|
|
950
|
-
2. Check PostgreSQL logs for "ambiguous column reference" errors
|
|
951
|
-
3. Verify all column references are prefixed in JOINs
|
|
952
|
-
4. Test with multiple tables that share column names
|
|
953
|
-
|
|
954
|
-
## Common Patterns
|
|
955
|
-
|
|
956
|
-
### Pattern 1: Simple Data Retrieval
|
|
957
|
-
|
|
958
|
-
```sql
|
|
959
|
-
CREATE OR REPLACE FUNCTION data_entity_list(
|
|
960
|
-
p_organisation_id UUID,
|
|
961
|
-
p_user_id UUID DEFAULT auth.uid()
|
|
962
|
-
)
|
|
963
|
-
RETURNS TABLE(id UUID, name TEXT)
|
|
964
|
-
LANGUAGE plpgsql
|
|
965
|
-
SECURITY DEFINER
|
|
966
|
-
SET search_path TO 'public'
|
|
967
|
-
AS $$
|
|
968
|
-
BEGIN
|
|
969
|
-
-- Super admin check
|
|
970
|
-
IF EXISTS(SELECT 1 FROM rbac_global_roles WHERE user_id = p_user_id AND role = 'super_admin') THEN
|
|
971
|
-
RETURN QUERY SELECT id, name FROM entity;
|
|
972
|
-
RETURN;
|
|
973
|
-
END IF;
|
|
974
|
-
|
|
975
|
-
-- Organisation check
|
|
976
|
-
IF NOT EXISTS(SELECT 1 FROM rbac_organisation_roles WHERE user_id = p_user_id AND organisation_id = p_organisation_id) THEN
|
|
977
|
-
RETURN;
|
|
978
|
-
END IF;
|
|
979
|
-
|
|
980
|
-
-- Return data
|
|
981
|
-
RETURN QUERY
|
|
982
|
-
SELECT id, name
|
|
983
|
-
FROM entity
|
|
984
|
-
WHERE organisation_id = p_organisation_id;
|
|
985
|
-
END;
|
|
986
|
-
$$;
|
|
987
|
-
```
|
|
988
|
-
|
|
989
|
-
### Pattern 2: Permission Check
|
|
990
|
-
|
|
991
|
-
```sql
|
|
992
|
-
CREATE OR REPLACE FUNCTION rbac_check_permission(
|
|
993
|
-
p_user_id UUID,
|
|
994
|
-
p_permission TEXT,
|
|
995
|
-
p_organisation_id UUID
|
|
996
|
-
)
|
|
997
|
-
RETURNS BOOLEAN
|
|
998
|
-
LANGUAGE plpgsql
|
|
999
|
-
SECURITY DEFINER
|
|
1000
|
-
SET search_path TO 'public'
|
|
1001
|
-
AS $$
|
|
1002
|
-
DECLARE
|
|
1003
|
-
v_has_permission BOOLEAN := false;
|
|
1004
|
-
BEGIN
|
|
1005
|
-
-- Super admin has all permissions
|
|
1006
|
-
IF EXISTS(SELECT 1 FROM rbac_global_roles WHERE user_id = p_user_id AND role = 'super_admin') THEN
|
|
1007
|
-
RETURN true;
|
|
1008
|
-
END IF;
|
|
1009
|
-
|
|
1010
|
-
-- Check permission
|
|
1011
|
-
SELECT EXISTS(
|
|
1012
|
-
SELECT 1 FROM rbac_page_permissions pp
|
|
1013
|
-
JOIN rbac_organisation_roles ror ON pp.organisation_id = ror.organisation_id
|
|
1014
|
-
WHERE ror.user_id = p_user_id
|
|
1015
|
-
AND ror.organisation_id = p_organisation_id
|
|
1016
|
-
AND pp.operation = split_part(p_permission, ':', 1)
|
|
1017
|
-
AND pp.allowed = true
|
|
1018
|
-
) INTO v_has_permission;
|
|
1019
|
-
|
|
1020
|
-
RETURN COALESCE(v_has_permission, false);
|
|
1021
|
-
END;
|
|
1022
|
-
$$;
|
|
1023
|
-
```
|
|
1024
|
-
|
|
1025
|
-
### Pattern 3: Complex Calculation
|
|
1026
|
-
|
|
1027
|
-
```sql
|
|
1028
|
-
CREATE OR REPLACE FUNCTION app_cake_distribution_calculate(
|
|
1029
|
-
p_event_id TEXT,
|
|
1030
|
-
p_user_id UUID DEFAULT auth.uid(),
|
|
1031
|
-
p_organisation_id UUID DEFAULT NULL
|
|
1032
|
-
)
|
|
1033
|
-
RETURNS TABLE(...)
|
|
1034
|
-
LANGUAGE plpgsql
|
|
1035
|
-
SECURITY DEFINER
|
|
1036
|
-
SET search_path TO 'public'
|
|
1037
|
-
AS $$
|
|
1038
|
-
DECLARE
|
|
1039
|
-
v_is_super_admin BOOLEAN;
|
|
1040
|
-
BEGIN
|
|
1041
|
-
-- Security checks
|
|
1042
|
-
...
|
|
1043
|
-
|
|
1044
|
-
-- Use CTEs for complex logic
|
|
1045
|
-
WITH event_units AS (
|
|
1046
|
-
SELECT unit_id FROM cake_unit WHERE unit_event_id = p_event_id
|
|
1047
|
-
),
|
|
1048
|
-
unit_diners AS (
|
|
1049
|
-
SELECT ... FROM cake_diner WHERE diner_unit_id IN (SELECT unit_id FROM event_units)
|
|
1050
|
-
)
|
|
1051
|
-
SELECT ...;
|
|
1052
|
-
END;
|
|
1053
|
-
$$;
|
|
1054
|
-
```
|
|
1055
|
-
|
|
1056
|
-
## Summary Checklist
|
|
1057
|
-
|
|
1058
|
-
When creating or reviewing an RPC function, ensure:
|
|
1059
|
-
|
|
1060
|
-
### Function Structure
|
|
1061
|
-
- ✅ Follows naming convention: `<family>_<domain>_<verb>`
|
|
1062
|
-
- ✅ Uses `SECURITY DEFINER`
|
|
1063
|
-
- ✅ Sets `search_path TO 'public'`
|
|
1064
|
-
- ✅ Validates all inputs
|
|
1065
|
-
- ✅ Checks super_admin status (if applicable)
|
|
1066
|
-
- ✅ Validates organisation membership (if applicable)
|
|
1067
|
-
- ✅ Validates event access (if event-scoped)
|
|
1068
|
-
- ✅ Uses proper error handling with `EXCEPTION WHEN OTHERS`
|
|
1069
|
-
- ✅ Returns empty on error (fail-secure)
|
|
1070
|
-
- ✅ Has documentation comments
|
|
1071
|
-
- ✅ Uses descriptive parameter names (`p_` prefix)
|
|
1072
|
-
- ✅ Uses descriptive variable names (`v_` prefix)
|
|
1073
|
-
- ✅ Has appropriate return type
|
|
1074
|
-
- ✅ Includes `GRANT EXECUTE` statement
|
|
1075
|
-
- ✅ Tested with various scenarios
|
|
1076
|
-
|
|
1077
|
-
### ⚠️ Critical Parameter Type Requirements
|
|
1078
|
-
- ✅ **String parameters use TEXT**: All string parameters MUST use `TEXT`, NOT `CHARACTER VARYING` or `VARCHAR`
|
|
1079
|
-
- ✅ **No duplicate function versions**: Only one version of each function exists (TEXT version, not CHARACTER VARYING)
|
|
1080
|
-
- ✅ **Numeric parameters use correct types**: `DOUBLE PRECISION` for decimals, `INTEGER` for whole numbers, `SMALLINT` for small integers
|
|
1081
|
-
- ✅ **Why TEXT?**: Application code calls with TEXT parameters; having both TEXT and CHARACTER VARYING versions causes ambiguity errors
|
|
1082
|
-
|
|
1083
|
-
### ⚠️ Critical Permission Format
|
|
1084
|
-
- ✅ **Permission format is correct**: `'operation:page.{pageName}'` (e.g., `'create:page.dishes'`, `'read:page.meals'`)
|
|
1085
|
-
- ✅ **NOT using wrong format**: `'operation:resource'` (e.g., `'create:dishes'`, `'read:meals'`)
|
|
1086
|
-
- ✅ **Page name parameter provided**: Last parameter is the page name (e.g., `'dishes'`, `'meals'`)
|
|
1087
|
-
- ✅ **Permission format matches rbac_permissions_get output**: Verify by checking existing working migrations
|
|
1088
|
-
|
|
1089
|
-
### ⚠️ Migration File Requirements
|
|
1090
|
-
- ✅ **New timestamp generated**: Run `date +%Y%m%d%H%M%S` to get current timestamp
|
|
1091
|
-
- ✅ **New file created**: Never reuse timestamps from previous migrations
|
|
1092
|
-
- ✅ **File naming**: `YYYYMMDDHHMMSS_descriptive_name.sql`
|
|
1093
|
-
- ✅ **No ambiguous column references**: Fully qualify table names (e.g., `cake_mealtype.mealtype_name`)
|
|
1094
|
-
|
|
1095
|
-
### ⚠️ Column Reference Requirements
|
|
1096
|
-
- ✅ **All column references in JOINs are fully qualified with table aliases**: Every column in SELECT, WHERE, ORDER BY, GROUP BY, HAVING must have table prefix
|
|
1097
|
-
- ✅ **No ambiguous column references in WHERE, ORDER BY, GROUP BY, HAVING clauses**: All columns must be prefixed with table alias
|
|
1098
|
-
- ✅ **Table aliases used consistently and meaningfully**: Use short, descriptive aliases (e.g., `d` for dish, `r` for recipe)
|
|
1099
|
-
- ✅ **SELECT INTO statements match variable count**: Number of columns must match number of variables
|
|
1100
|
-
|
|
1101
|
-
## References
|
|
1102
|
-
|
|
1103
|
-
- [RBAC System Documentation](../core-concepts/rbac-system.md)
|
|
1104
|
-
- [Database Schema Requirements](./database-schema-requirements.md)
|
|
1105
|
-
- [Security Architecture](./rbac-security-architecture.md)
|
|
1106
|
-
|