@jmruthers/pace-core 0.5.120 → 0.5.123

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.
Files changed (239) hide show
  1. package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
  2. package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
  3. package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
  4. package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
  5. package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
  6. package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
  7. package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
  8. package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
  9. package/dist/{chunk-VKOCWWVY.js.map → chunk-CX5M4ZAG.js.map} +1 -1
  10. package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
  11. package/dist/chunk-DHMFMXFV.js.map +1 -0
  12. package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
  13. package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
  14. package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
  15. package/dist/chunk-GEVIB2UB.js.map +1 -0
  16. package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
  17. package/dist/chunk-IJOZZOGT.js.map +1 -0
  18. package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
  19. package/dist/chunk-M6DDYFUD.js.map +1 -0
  20. package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
  21. package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
  22. package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
  23. package/dist/chunk-XN6GWKMV.js.map +1 -0
  24. package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
  25. package/dist/chunk-ZBLK676C.js.map +1 -0
  26. package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
  27. package/dist/chunk-ZPJMYGEP.js.map +1 -0
  28. package/dist/components.d.ts +1 -1
  29. package/dist/components.js +11 -11
  30. package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
  31. package/dist/hooks.d.ts +1 -1
  32. package/dist/hooks.js +9 -8
  33. package/dist/hooks.js.map +1 -1
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +19 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/providers.d.ts +2 -2
  38. package/dist/providers.js +2 -3
  39. package/dist/rbac/index.js +7 -8
  40. package/dist/styles/index.d.ts +1 -1
  41. package/dist/styles/index.js +5 -3
  42. package/dist/theming/runtime.d.ts +73 -1
  43. package/dist/theming/runtime.js +5 -5
  44. package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
  45. package/dist/utils.d.ts +1 -1
  46. package/dist/utils.js +5 -5
  47. package/docs/api/classes/ColumnFactory.md +1 -1
  48. package/docs/api/classes/ErrorBoundary.md +1 -1
  49. package/docs/api/classes/InvalidScopeError.md +1 -1
  50. package/docs/api/classes/MissingUserContextError.md +1 -1
  51. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  52. package/docs/api/classes/PermissionDeniedError.md +1 -1
  53. package/docs/api/classes/PublicErrorBoundary.md +6 -6
  54. package/docs/api/classes/RBACAuditManager.md +1 -1
  55. package/docs/api/classes/RBACCache.md +1 -1
  56. package/docs/api/classes/RBACEngine.md +1 -1
  57. package/docs/api/classes/RBACError.md +1 -1
  58. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  59. package/docs/api/classes/SecureSupabaseClient.md +6 -6
  60. package/docs/api/classes/StorageUtils.md +1 -1
  61. package/docs/api/enums/FileCategory.md +1 -1
  62. package/docs/api/interfaces/AggregateConfig.md +1 -1
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  77. package/docs/api/interfaces/FileMetadata.md +1 -1
  78. package/docs/api/interfaces/FileReference.md +1 -1
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  84. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  85. package/docs/api/interfaces/InputProps.md +1 -1
  86. package/docs/api/interfaces/LabelProps.md +1 -1
  87. package/docs/api/interfaces/LoginFormProps.md +1 -1
  88. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  89. package/docs/api/interfaces/NavigationContextType.md +1 -1
  90. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  91. package/docs/api/interfaces/NavigationItem.md +1 -1
  92. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  93. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  94. package/docs/api/interfaces/Organisation.md +1 -1
  95. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  96. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  97. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  98. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  99. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  100. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  101. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  102. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  103. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  104. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  105. package/docs/api/interfaces/PaletteData.md +1 -1
  106. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  107. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  108. package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
  109. package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
  110. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
  111. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  112. package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
  113. package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
  114. package/docs/api/interfaces/RBACConfig.md +1 -1
  115. package/docs/api/interfaces/RBACLogger.md +1 -1
  116. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  118. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  119. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  120. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  121. package/docs/api/interfaces/RouteConfig.md +1 -1
  122. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  123. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  124. package/docs/api/interfaces/StorageConfig.md +1 -1
  125. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  126. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  127. package/docs/api/interfaces/StorageListOptions.md +1 -1
  128. package/docs/api/interfaces/StorageListResult.md +1 -1
  129. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  130. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  131. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  132. package/docs/api/interfaces/StyleImport.md +1 -1
  133. package/docs/api/interfaces/SwitchProps.md +1 -1
  134. package/docs/api/interfaces/ToastActionElement.md +1 -1
  135. package/docs/api/interfaces/ToastProps.md +1 -1
  136. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  137. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  138. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  139. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  140. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  141. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  142. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  143. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  145. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  146. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  147. package/docs/api/interfaces/UserEventAccess.md +1 -1
  148. package/docs/api/interfaces/UserMenuProps.md +1 -1
  149. package/docs/api/interfaces/UserProfile.md +1 -1
  150. package/docs/api/modules.md +140 -30
  151. package/docs/best-practices/README.md +1 -1
  152. package/docs/implementation-guides/datatable-filtering.md +313 -0
  153. package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
  154. package/docs/implementation-guides/hierarchical-datatable.md +850 -0
  155. package/docs/implementation-guides/large-datasets.md +281 -0
  156. package/docs/implementation-guides/performance.md +403 -0
  157. package/docs/implementation-guides/public-pages.md +4 -4
  158. package/docs/migration/quick-migration-guide.md +320 -0
  159. package/docs/rbac/quick-start.md +16 -16
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
  162. package/docs/troubleshooting/debugging.md +1117 -0
  163. package/docs/troubleshooting/migration.md +918 -0
  164. package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
  165. package/examples/public-pages/PublicEventPage.tsx +41 -41
  166. package/examples/public-pages/PublicPageApp.tsx +33 -33
  167. package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
  168. package/package.json +4 -4
  169. package/src/__tests__/hooks/usePermissions.test.ts +265 -0
  170. package/src/components/DataTable/DataTable.test.tsx +9 -38
  171. package/src/components/DataTable/DataTable.tsx +0 -7
  172. package/src/components/DataTable/components/DataTableCore.tsx +66 -136
  173. package/src/components/DataTable/components/DataTableModals.tsx +25 -22
  174. package/src/components/DataTable/components/EditableRow.tsx +118 -42
  175. package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
  176. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
  177. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
  178. package/src/components/DataTable/utils/exportUtils.ts +3 -2
  179. package/src/components/DataTable/utils/flexibleImport.ts +27 -6
  180. package/src/components/Dialog/Dialog.tsx +1 -1
  181. package/src/components/Dialog/README.md +24 -24
  182. package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
  183. package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
  184. package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
  185. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
  186. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
  187. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
  188. package/src/components/PublicLayout/EventLogo.tsx +175 -0
  189. package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
  190. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
  191. package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
  192. package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
  193. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
  194. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
  195. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
  196. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
  197. package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
  198. package/src/examples/PublicEventPage.tsx +41 -41
  199. package/src/examples/PublicPageApp.tsx +33 -33
  200. package/src/examples/PublicPageUsageExample.tsx +30 -30
  201. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  202. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
  203. package/src/hooks/index.ts +1 -1
  204. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  205. package/src/hooks/public/usePublicRouteParams.ts +21 -4
  206. package/src/hooks/useEventTheme.test.ts +119 -43
  207. package/src/hooks/useEventTheme.ts +84 -55
  208. package/src/index.ts +3 -1
  209. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
  210. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  211. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  212. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
  213. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  214. package/src/rbac/secureClient.ts +4 -2
  215. package/src/services/EventService.ts +0 -66
  216. package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
  217. package/src/styles/index.ts +1 -1
  218. package/src/theming/__tests__/parseEventColours.test.ts +209 -0
  219. package/src/theming/parseEventColours.ts +123 -0
  220. package/src/theming/runtime.ts +3 -0
  221. package/src/types/__tests__/file-reference.test.ts +447 -0
  222. package/src/types/database.generated.ts +1515 -424
  223. package/src/utils/formatDate.test.ts +11 -11
  224. package/src/utils/formatting.ts +3 -2
  225. package/dist/chunk-BHWIUEYH.js.map +0 -1
  226. package/dist/chunk-FKFHZUGF.js.map +0 -1
  227. package/dist/chunk-GZRXOUBE.js.map +0 -1
  228. package/dist/chunk-HFBOFZ3Z.js.map +0 -1
  229. package/dist/chunk-QPI2CCBA.js.map +0 -1
  230. package/dist/chunk-SMJZMKYN.js.map +0 -1
  231. package/dist/chunk-TDNI6ZWL.js.map +0 -1
  232. package/src/styles/semantic.css +0 -24
  233. /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
  234. /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
  235. /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
  236. /package/dist/{chunk-CGURJ27Z.js.map → chunk-4MXVZVNS.js.map} +0 -0
  237. /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
  238. /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
  239. /package/dist/{chunk-NZ32EONV.js.map → chunk-QWNJCQXZ.js.map} +0 -0
@@ -0,0 +1,918 @@
1
+ # Migration Guide
2
+
3
+ This guide provides comprehensive migration strategies for upgrading `@jmruthers/pace-core` applications between versions and handling breaking changes.
4
+
5
+ ## Overview
6
+
7
+ Migration in `@jmruthers/pace-core` covers:
8
+
9
+ - **Version Upgrades**: Upgrading between major/minor versions
10
+ - **Breaking Changes**: Handling API changes and deprecations
11
+ - **Database Migrations**: Schema updates and data transformations
12
+ - **Configuration Updates**: Environment and build configuration changes
13
+ - **Dependency Updates**: Third-party library compatibility
14
+
15
+ ## Version Migration
16
+
17
+ ### 1. Major Version Migration (v1.x to v2.x)
18
+
19
+ ```typescript
20
+ // Before v2.0.0
21
+ import { useAuth, usePermissions } from '@jmruthers/pace-core';
22
+
23
+ function MyComponent() {
24
+ const { user, signIn, signOut } = useAuth();
25
+ const { hasPermission } = usePermissions();
26
+
27
+ return (
28
+ <div>
29
+ {user && <p>Welcome, {user.email}</p>}
30
+ {hasPermission('read:users') && <UserList />}
31
+ </div>
32
+ );
33
+ }
34
+
35
+ // After v2.0.0
36
+ import { useUnifiedAuth } from '@jmruthers/pace-core';
37
+ import { useCan } from '@jmruthers/pace-core/rbac';
38
+
39
+ function MyComponent() {
40
+ const { user, signIn, signOut } = useUnifiedAuth();
41
+ const { hasPermission } = useCan();
42
+
43
+ return (
44
+ <div>
45
+ {user && <p>Welcome, {user.email}</p>}
46
+ {hasPermission('read:users') && <UserList />}
47
+ </div>
48
+ );
49
+ }
50
+ ```
51
+
52
+ ### 2. Hook Migration Patterns
53
+
54
+ ```typescript
55
+ // Migration helper for gradual updates
56
+ function useLegacyAuth() {
57
+ const auth = useUnifiedAuth();
58
+
59
+ // Provide legacy API compatibility
60
+ return {
61
+ user: auth.user,
62
+ loading: auth.loading,
63
+ error: auth.error,
64
+ signIn: auth.signIn,
65
+ signOut: auth.signOut,
66
+ // Legacy methods
67
+ login: auth.signIn,
68
+ logout: auth.signOut,
69
+ isAuthenticated: !!auth.user,
70
+ };
71
+ }
72
+
73
+ // Migration helper for RBAC
74
+ import { useCan, usePermissions } from '@jmruthers/pace-core/rbac';
75
+
76
+ function useLegacyPermissions() {
77
+ const { hasPermission } = useCan();
78
+ const { permissions } = usePermissions();
79
+
80
+ return {
81
+ hasPermission,
82
+ permissions,
83
+ // Legacy methods
84
+ can: hasPermission,
85
+ userPermissions: permissions,
86
+ };
87
+ }
88
+ ```
89
+
90
+ ### 3. Component Migration
91
+
92
+ ```typescript
93
+ // Before: Old component API
94
+ <Button
95
+ variant="primary"
96
+ onClick={handleClick}
97
+ disabled={loading}
98
+ >
99
+ Submit
100
+ </Button>
101
+
102
+ // After: New component API
103
+ <Button
104
+ variant="primary"
105
+ onClick={handleClick}
106
+ disabled={loading}
107
+ loading={loading}
108
+ size="md"
109
+ >
110
+ Submit
111
+ </Button>
112
+ ```
113
+
114
+ ## Breaking Changes Migration
115
+
116
+ ### 1. Authentication API Changes
117
+
118
+ ```typescript
119
+ // Migration script for authentication changes
120
+ function migrateAuthAPI() {
121
+ // Old API
122
+ const oldAuth = {
123
+ user: null,
124
+ signIn: async (email: string, password: string) => {
125
+ // Old implementation
126
+ },
127
+ signOut: async () => {
128
+ // Old implementation
129
+ },
130
+ };
131
+
132
+ // New API
133
+ const newAuth = {
134
+ user: null,
135
+ signIn: async (credentials: { email: string; password: string }) => {
136
+ // New implementation
137
+ },
138
+ signOut: async () => {
139
+ // New implementation
140
+ },
141
+ // Additional methods
142
+ signUp: async (credentials: { email: string; password: string }) => {
143
+ // New signup implementation
144
+ },
145
+ resetPassword: async (email: string) => {
146
+ // New password reset implementation
147
+ },
148
+ };
149
+
150
+ return newAuth;
151
+ }
152
+
153
+ // Migration helper
154
+ function useAuthMigration() {
155
+ const auth = useUnifiedAuth();
156
+
157
+ // Provide backward compatibility
158
+ const legacySignIn = useCallback((email: string, password: string) => {
159
+ return auth.signIn({ email, password });
160
+ }, [auth.signIn]);
161
+
162
+ return {
163
+ ...auth,
164
+ // Legacy API
165
+ login: legacySignIn,
166
+ logout: auth.signOut,
167
+ };
168
+ }
169
+ ```
170
+
171
+ ### 2. Permission System Changes
172
+
173
+ ```typescript
174
+ // Migration script for permission changes
175
+ function migratePermissions() {
176
+ // Old permission format
177
+ const oldPermissions = [
178
+ 'read_users',
179
+ 'write_events',
180
+ 'delete_posts',
181
+ ];
182
+
183
+ // New permission format
184
+ const newPermissions = [
185
+ 'read:users',
186
+ 'write:events',
187
+ 'delete:posts',
188
+ ];
189
+
190
+ // Migration function
191
+ function migratePermissionFormat(oldPermission: string): string {
192
+ return oldPermission.replace('_', ':');
193
+ }
194
+
195
+ return {
196
+ oldPermissions,
197
+ newPermissions: oldPermissions.map(migratePermissionFormat),
198
+ migratePermissionFormat,
199
+ };
200
+ }
201
+
202
+ // Migration helper for permission checks
203
+ function usePermissionMigration() {
204
+ const rbac = useRBAC();
205
+
206
+ // Legacy permission check
207
+ const legacyHasPermission = useCallback((permission: string) => {
208
+ // Convert old format to new format
209
+ const newPermission = permission.replace('_', ':');
210
+ return rbac.hasPermission(newPermission);
211
+ }, [rbac]);
212
+
213
+ return {
214
+ ...rbac,
215
+ // Legacy API
216
+ can: legacyHasPermission,
217
+ hasAccess: legacyHasPermission,
218
+ };
219
+ }
220
+ ```
221
+
222
+ ### 3. Component Prop Changes
223
+
224
+ ```typescript
225
+ // Migration script for component prop changes
226
+ function migrateComponentProps() {
227
+ // Old Button props
228
+ const oldButtonProps = {
229
+ type: 'primary',
230
+ onClick: () => {},
231
+ disabled: false,
232
+ children: 'Click me',
233
+ };
234
+
235
+ // New Button props
236
+ const newButtonProps = {
237
+ variant: 'primary', // type -> variant
238
+ onClick: () => {},
239
+ disabled: false,
240
+ loading: false, // New prop
241
+ size: 'md', // New prop
242
+ children: 'Click me',
243
+ };
244
+
245
+ // Migration function
246
+ function migrateButtonProps(oldProps: any) {
247
+ return {
248
+ variant: oldProps.type,
249
+ onClick: oldProps.onClick,
250
+ disabled: oldProps.disabled,
251
+ loading: false, // Default value
252
+ size: 'md', // Default value
253
+ children: oldProps.children,
254
+ };
255
+ }
256
+
257
+ return {
258
+ oldButtonProps,
259
+ newButtonProps,
260
+ migrateButtonProps,
261
+ };
262
+ }
263
+ ```
264
+
265
+ ## Database Migration
266
+
267
+ ### 1. Schema Migration
268
+
269
+ ```sql
270
+ -- Migration script for database schema changes
271
+ -- 001_migrate_users_table.sql
272
+
273
+ -- Add new columns to users table
274
+ ALTER TABLE users
275
+ ADD COLUMN IF NOT EXISTS organisation_id UUID REFERENCES organisations(id),
276
+ ADD COLUMN IF NOT EXISTS role VARCHAR(50) DEFAULT 'user',
277
+ ADD COLUMN IF NOT EXISTS permissions JSONB DEFAULT '[]';
278
+
279
+ -- Create index for performance
280
+ CREATE INDEX IF NOT EXISTS idx_users_organisation_id ON users(organisation_id);
281
+ CREATE INDEX IF NOT EXISTS idx_users_role ON users(role);
282
+
283
+ -- Update existing users with default values
284
+ UPDATE users
285
+ SET
286
+ organisation_id = (SELECT id FROM organisations LIMIT 1),
287
+ role = 'user',
288
+ permissions = '[]'
289
+ WHERE organisation_id IS NULL;
290
+
291
+ -- Add constraints
292
+ ALTER TABLE users
293
+ ALTER COLUMN organisation_id SET NOT NULL,
294
+ ALTER COLUMN role SET NOT NULL;
295
+ ```
296
+
297
+ ### 2. Data Migration
298
+
299
+ ```typescript
300
+ // Migration script for data transformation
301
+ async function migrateUserData() {
302
+ const { supabase } = useSupabase();
303
+
304
+ // Get all users
305
+ const { data: users, error } = await supabase
306
+ .from('users')
307
+ .select('*');
308
+
309
+ if (error) {
310
+ console.error('Failed to fetch users:', error);
311
+ return;
312
+ }
313
+
314
+ // Transform user data
315
+ const migratedUsers = users.map(user => ({
316
+ ...user,
317
+ // Convert old permission format to new format
318
+ permissions: user.permissions?.map((permission: string) =>
319
+ permission.replace('_', ':')
320
+ ) || [],
321
+ // Add default role if missing
322
+ role: user.role || 'user',
323
+ // Add organisation if missing
324
+ organisation_id: user.organisation_id || 'default-org-id',
325
+ }));
326
+
327
+ // Update users in batches
328
+ const batchSize = 100;
329
+ for (let i = 0; i < migratedUsers.length; i += batchSize) {
330
+ const batch = migratedUsers.slice(i, i + batchSize);
331
+
332
+ const { error: updateError } = await supabase
333
+ .from('users')
334
+ .upsert(batch);
335
+
336
+ if (updateError) {
337
+ console.error(`Failed to update batch ${i / batchSize + 1}:`, updateError);
338
+ }
339
+ }
340
+
341
+ console.log('User data migration completed');
342
+ }
343
+ ```
344
+
345
+ ### 3. RLS Policy Migration
346
+
347
+ ```sql
348
+ -- Migration script for RLS policies
349
+ -- 002_migrate_rls_policies.sql
350
+
351
+ -- Drop old policies
352
+ DROP POLICY IF EXISTS "Users can view their own data" ON users;
353
+ DROP POLICY IF EXISTS "Users can update their own data" ON users;
354
+
355
+ -- Create new policies with organisation isolation
356
+ CREATE POLICY "Users can view their own organisation's data" ON users
357
+ FOR SELECT USING (
358
+ organisation_id = auth.jwt() ->> 'organisation_id'
359
+ );
360
+
361
+ CREATE POLICY "Users can update their own data" ON users
362
+ FOR UPDATE USING (
363
+ id = auth.uid() AND
364
+ organisation_id = auth.jwt() ->> 'organisation_id'
365
+ );
366
+
367
+ CREATE POLICY "Users can insert their own data" ON users
368
+ FOR INSERT WITH CHECK (
369
+ organisation_id = auth.jwt() ->> 'organisation_id'
370
+ );
371
+
372
+ -- Apply similar policies to other tables
373
+ -- events table
374
+ CREATE POLICY "Users can view their organisation's events" ON events
375
+ FOR SELECT USING (
376
+ organisation_id = auth.jwt() ->> 'organisation_id'
377
+ );
378
+
379
+ CREATE POLICY "Users can manage their organisation's events" ON events
380
+ FOR ALL USING (
381
+ organisation_id = auth.jwt() ->> 'organisation_id'
382
+ );
383
+ ```
384
+
385
+ ## Configuration Migration
386
+
387
+ ### 1. Environment Variables Migration
388
+
389
+ ```bash
390
+ # Migration script for environment variables
391
+ # old.env -> new.env
392
+
393
+ # Old environment variables
394
+ VITE_AUTH_URL=https://old-auth.example.com
395
+ VITE_API_KEY=old-api-key
396
+ VITE_DEBUG_MODE=true
397
+
398
+ # New environment variables
399
+ VITE_SUPABASE_URL=https://your-project.supabase.co
400
+ VITE_SUPABASE_ANON_KEY=your-anon-key
401
+ VITE_APP_ENV=development
402
+ VITE_DEBUG=false
403
+
404
+ # Migration script
405
+ #!/bin/bash
406
+ # migrate-env.sh
407
+
408
+ echo "Migrating environment variables..."
409
+
410
+ # Backup old environment file
411
+ cp .env .env.backup
412
+
413
+ # Create new environment file
414
+ cat > .env << EOF
415
+ # Supabase Configuration
416
+ VITE_SUPABASE_URL=${VITE_SUPABASE_URL:-https://your-project.supabase.co}
417
+ VITE_SUPABASE_ANON_KEY=${VITE_SUPABASE_ANON_KEY:-your-anon-key}
418
+
419
+ # Application Configuration
420
+ VITE_APP_ENV=${VITE_APP_ENV:-development}
421
+ VITE_DEBUG=${VITE_DEBUG:-false}
422
+
423
+ # Feature Flags
424
+ VITE_FEATURE_ANALYTICS=${VITE_FEATURE_ANALYTICS:-false}
425
+ VITE_FEATURE_BETA=${VITE_FEATURE_BETA:-false}
426
+
427
+ # Monitoring
428
+ VITE_SENTRY_DSN=${VITE_SENTRY_DSN:-}
429
+ VITE_ANALYTICS_ID=${VITE_ANALYTICS_ID:-}
430
+ EOF
431
+
432
+ echo "Environment migration completed"
433
+ ```
434
+
435
+ ### 2. Build Configuration Migration
436
+
437
+ ```typescript
438
+ // Migration script for build configuration
439
+ // vite.config.old.ts -> vite.config.ts
440
+
441
+ // Old configuration
442
+ export default defineConfig({
443
+ plugins: [react()],
444
+ build: {
445
+ outDir: 'build',
446
+ sourcemap: true,
447
+ },
448
+ define: {
449
+ global: 'globalThis',
450
+ },
451
+ });
452
+
453
+ // New configuration
454
+ export default defineConfig({
455
+ plugins: [react()],
456
+ build: {
457
+ target: 'es2015',
458
+ outDir: 'dist',
459
+ sourcemap: false, // Disable in production
460
+ minify: 'terser',
461
+ rollupOptions: {
462
+ output: {
463
+ manualChunks: {
464
+ vendor: ['react', 'react-dom'],
465
+ paceCore: ['@jmruthers/pace-core'],
466
+ supabase: ['@supabase/supabase-js'],
467
+ },
468
+ },
469
+ },
470
+ terserOptions: {
471
+ compress: {
472
+ drop_console: true,
473
+ drop_debugger: true,
474
+ },
475
+ },
476
+ },
477
+ define: {
478
+ __DEV__: JSON.stringify(process.env.NODE_ENV === 'development'),
479
+ },
480
+ optimizeDeps: {
481
+ include: ['@jmruthers/pace-core'],
482
+ },
483
+ });
484
+ ```
485
+
486
+ ### 3. Package.json Migration
487
+
488
+ ```json
489
+ // Migration script for package.json dependencies
490
+ // package.json.old -> package.json
491
+
492
+ {
493
+ "name": "my-app",
494
+ "version": "2.0.0",
495
+ "dependencies": {
496
+ // Old dependencies
497
+ "@jmruthers/pace-core": "^1.5.0",
498
+ "react": "^17.0.2",
499
+ "react-dom": "^17.0.2",
500
+
501
+ // New dependencies
502
+ "@jmruthers/pace-core": "^2.0.0",
503
+ "react": "^18.2.0",
504
+ "react-dom": "^18.2.0",
505
+ "@supabase/supabase-js": "^2.38.0",
506
+ "zod": "^3.22.0"
507
+ },
508
+ "devDependencies": {
509
+ // Old dev dependencies
510
+ "@types/react": "^17.0.0",
511
+ "@types/react-dom": "^17.0.0",
512
+
513
+ // New dev dependencies
514
+ "@types/react": "^18.2.0",
515
+ "@types/react-dom": "^18.2.0",
516
+ "@vitejs/plugin-react": "^4.0.0",
517
+ "vite": "^4.4.0",
518
+ "typescript": "^5.0.0"
519
+ },
520
+ "scripts": {
521
+ // Old scripts
522
+ "start": "react-scripts start",
523
+ "build": "react-scripts build",
524
+ "test": "react-scripts test",
525
+
526
+ // New scripts
527
+ "dev": "vite",
528
+ "build": "vite build",
529
+ "preview": "vite preview",
530
+ "test": "vitest",
531
+ "type-check": "tsc --noEmit"
532
+ }
533
+ }
534
+ ```
535
+
536
+ ## Migration Tools and Utilities
537
+
538
+ ### 1. Migration Helper Functions
539
+
540
+ ```typescript
541
+ // utils/migrationHelpers.ts
542
+ export class MigrationHelpers {
543
+ // Check if migration is needed
544
+ static needsMigration(currentVersion: string, targetVersion: string): boolean {
545
+ const current = this.parseVersion(currentVersion);
546
+ const target = this.parseVersion(targetVersion);
547
+
548
+ return current.major < target.major ||
549
+ (current.major === target.major && current.minor < target.minor);
550
+ }
551
+
552
+ // Parse version string
553
+ static parseVersion(version: string) {
554
+ const [major, minor, patch] = version.split('.').map(Number);
555
+ return { major, minor, patch };
556
+ }
557
+
558
+ // Migrate component props
559
+ static migrateComponentProps(oldProps: any, componentName: string) {
560
+ const migrations = {
561
+ Button: {
562
+ type: 'variant',
563
+ size: 'md',
564
+ loading: false,
565
+ },
566
+ DataTable: {
567
+ data: 'rows',
568
+ columns: 'columns',
569
+ pagination: 'enablePagination',
570
+ },
571
+ Form: {
572
+ onSubmit: 'onSubmit',
573
+ validation: 'schema',
574
+ },
575
+ };
576
+
577
+ const migration = migrations[componentName];
578
+ if (!migration) return oldProps;
579
+
580
+ const newProps = { ...oldProps };
581
+
582
+ Object.entries(migration).forEach(([oldKey, newKey]) => {
583
+ if (oldProps[oldKey] !== undefined) {
584
+ newProps[newKey] = oldProps[oldKey];
585
+ delete newProps[oldKey];
586
+ }
587
+ });
588
+
589
+ return newProps;
590
+ }
591
+
592
+ // Migrate permission format
593
+ static migratePermissionFormat(permission: string): string {
594
+ return permission.replace('_', ':');
595
+ }
596
+
597
+ // Migrate user data
598
+ static migrateUserData(user: any) {
599
+ return {
600
+ ...user,
601
+ permissions: user.permissions?.map(this.migratePermissionFormat) || [],
602
+ role: user.role || 'user',
603
+ organisation_id: user.organisation_id || 'default',
604
+ };
605
+ }
606
+
607
+ // Generate migration report
608
+ static generateMigrationReport(changes: any[]) {
609
+ return {
610
+ timestamp: new Date().toISOString(),
611
+ changes,
612
+ summary: {
613
+ total: changes.length,
614
+ breaking: changes.filter(c => c.breaking).length,
615
+ nonBreaking: changes.filter(c => !c.breaking).length,
616
+ },
617
+ };
618
+ }
619
+ }
620
+ ```
621
+
622
+ ### 2. Migration Validation
623
+
624
+ ```typescript
625
+ // utils/migrationValidation.ts
626
+ export class MigrationValidation {
627
+ // Validate component usage
628
+ static validateComponentUsage(componentName: string, props: any) {
629
+ const validations = {
630
+ Button: {
631
+ required: ['children'],
632
+ optional: ['variant', 'size', 'loading', 'disabled', 'onClick'],
633
+ deprecated: ['type'],
634
+ },
635
+ DataTable: {
636
+ required: ['data', 'columns'],
637
+ optional: ['pagination', 'sorting', 'filtering'],
638
+ deprecated: ['rows'],
639
+ },
640
+ };
641
+
642
+ const validation = validations[componentName];
643
+ if (!validation) return { valid: true, warnings: [] };
644
+
645
+ const warnings = [];
646
+
647
+ // Check for deprecated props
648
+ validation.deprecated.forEach(prop => {
649
+ if (props[prop] !== undefined) {
650
+ warnings.push(`Prop '${prop}' is deprecated in ${componentName}`);
651
+ }
652
+ });
653
+
654
+ // Check for missing required props
655
+ validation.required.forEach(prop => {
656
+ if (props[prop] === undefined) {
657
+ warnings.push(`Required prop '${prop}' is missing in ${componentName}`);
658
+ }
659
+ });
660
+
661
+ return {
662
+ valid: warnings.length === 0,
663
+ warnings,
664
+ };
665
+ }
666
+
667
+ // Validate hook usage
668
+ static validateHookUsage(hookName: string, args: any[]) {
669
+ const validations = {
670
+ useUnifiedAuth: {
671
+ args: 0,
672
+ description: 'No arguments required',
673
+ },
674
+ useRBAC: {
675
+ args: 0,
676
+ description: 'No arguments required',
677
+ },
678
+ useEvents: {
679
+ args: 0,
680
+ description: 'No arguments required',
681
+ },
682
+ };
683
+
684
+ const validation = validations[hookName];
685
+ if (!validation) return { valid: true, warnings: [] };
686
+
687
+ const warnings = [];
688
+
689
+ if (args.length !== validation.args) {
690
+ warnings.push(`${hookName} expects ${validation.args} arguments, got ${args.length}`);
691
+ }
692
+
693
+ return {
694
+ valid: warnings.length === 0,
695
+ warnings,
696
+ };
697
+ }
698
+
699
+ // Validate configuration
700
+ static validateConfiguration(config: any) {
701
+ const required = [
702
+ 'VITE_SUPABASE_URL',
703
+ 'VITE_SUPABASE_ANON_KEY',
704
+ ];
705
+
706
+ const warnings = [];
707
+
708
+ required.forEach(key => {
709
+ if (!config[key]) {
710
+ warnings.push(`Required environment variable '${key}' is missing`);
711
+ }
712
+ });
713
+
714
+ return {
715
+ valid: warnings.length === 0,
716
+ warnings,
717
+ };
718
+ }
719
+ }
720
+ ```
721
+
722
+ ### 3. Migration Testing
723
+
724
+ ```typescript
725
+ // utils/migrationTesting.ts
726
+ export class MigrationTesting {
727
+ // Test component migration
728
+ static testComponentMigration(componentName: string, oldProps: any, newProps: any) {
729
+ const migratedProps = MigrationHelpers.migrateComponentProps(oldProps, componentName);
730
+
731
+ const validation = MigrationValidation.validateComponentUsage(componentName, migratedProps);
732
+
733
+ return {
734
+ success: validation.valid,
735
+ warnings: validation.warnings,
736
+ oldProps,
737
+ newProps: migratedProps,
738
+ };
739
+ }
740
+
741
+ // Test hook migration
742
+ static testHookMigration(hookName: string, oldUsage: any, newUsage: any) {
743
+ const validation = MigrationValidation.validateHookUsage(hookName, newUsage.args);
744
+
745
+ return {
746
+ success: validation.valid,
747
+ warnings: validation.warnings,
748
+ oldUsage,
749
+ newUsage,
750
+ };
751
+ }
752
+
753
+ // Test data migration
754
+ static testDataMigration(oldData: any, newData: any) {
755
+ const migratedData = MigrationHelpers.migrateUserData(oldData);
756
+
757
+ return {
758
+ success: JSON.stringify(migratedData) === JSON.stringify(newData),
759
+ oldData,
760
+ newData: migratedData,
761
+ differences: this.findDifferences(oldData, migratedData),
762
+ };
763
+ }
764
+
765
+ // Find differences between objects
766
+ static findDifferences(obj1: any, obj2: any): Record<string, any> {
767
+ const differences: Record<string, any> = {};
768
+
769
+ const allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
770
+
771
+ allKeys.forEach(key => {
772
+ if (obj1[key] !== obj2[key]) {
773
+ differences[key] = {
774
+ old: obj1[key],
775
+ new: obj2[key],
776
+ };
777
+ }
778
+ });
779
+
780
+ return differences;
781
+ }
782
+ }
783
+ ```
784
+
785
+ ## Migration Best Practices
786
+
787
+ ### 1. Migration Checklist
788
+
789
+ - [ ] Review breaking changes documentation
790
+ - [ ] Create migration plan
791
+ - [ ] Set up staging environment
792
+ - [ ] Backup current data
793
+ - [ ] Test migration in staging
794
+ - [ ] Update dependencies
795
+ - [ ] Migrate configuration
796
+ - [ ] Update code for new APIs
797
+ - [ ] Test all functionality
798
+ - [ ] Deploy to production
799
+ - [ ] Monitor for issues
800
+ - [ ] Clean up old code
801
+
802
+ ### 2. Migration Strategy
803
+
804
+ ```typescript
805
+ // Migration strategy implementation
806
+ export class MigrationStrategy {
807
+ static async executeMigration(fromVersion: string, toVersion: string) {
808
+ console.log(`Starting migration from ${fromVersion} to ${toVersion}`);
809
+
810
+ // 1. Pre-migration checks
811
+ const preChecks = await this.performPreChecks();
812
+ if (!preChecks.success) {
813
+ throw new Error(`Pre-migration checks failed: ${preChecks.errors.join(', ')}`);
814
+ }
815
+
816
+ // 2. Backup current state
817
+ const backup = await this.createBackup();
818
+ console.log('Backup created:', backup.location);
819
+
820
+ // 3. Update dependencies
821
+ await this.updateDependencies(toVersion);
822
+
823
+ // 4. Migrate configuration
824
+ await this.migrateConfiguration();
825
+
826
+ // 5. Migrate code
827
+ await this.migrateCode();
828
+
829
+ // 6. Migrate data
830
+ await this.migrateData();
831
+
832
+ // 7. Post-migration validation
833
+ const validation = await this.validateMigration();
834
+ if (!validation.success) {
835
+ console.error('Migration validation failed:', validation.errors);
836
+ await this.rollback(backup);
837
+ throw new Error('Migration failed validation');
838
+ }
839
+
840
+ console.log('Migration completed successfully');
841
+ return { success: true, backup };
842
+ }
843
+
844
+ static async performPreChecks() {
845
+ const checks = [
846
+ this.checkDependencies(),
847
+ this.checkConfiguration(),
848
+ this.checkDataIntegrity(),
849
+ ];
850
+
851
+ const results = await Promise.all(checks);
852
+ const errors = results.flatMap(r => r.errors || []);
853
+
854
+ return {
855
+ success: errors.length === 0,
856
+ errors,
857
+ };
858
+ }
859
+
860
+ static async createBackup() {
861
+ // Implementation for creating backup
862
+ return {
863
+ location: '/backups/migration-backup-' + Date.now(),
864
+ timestamp: new Date().toISOString(),
865
+ };
866
+ }
867
+
868
+ static async rollback(backup: any) {
869
+ console.log('Rolling back to backup:', backup.location);
870
+ // Implementation for rollback
871
+ }
872
+ }
873
+ ```
874
+
875
+ ### 3. Rollback Strategy
876
+
877
+ ```typescript
878
+ // Rollback strategy implementation
879
+ export class RollbackStrategy {
880
+ static async rollbackMigration(backup: any) {
881
+ console.log('Starting rollback process...');
882
+
883
+ try {
884
+ // 1. Restore database
885
+ await this.restoreDatabase(backup.database);
886
+
887
+ // 2. Restore configuration
888
+ await this.restoreConfiguration(backup.config);
889
+
890
+ // 3. Restore code
891
+ await this.restoreCode(backup.code);
892
+
893
+ // 4. Restore dependencies
894
+ await this.restoreDependencies(backup.dependencies);
895
+
896
+ // 5. Validate rollback
897
+ const validation = await this.validateRollback();
898
+
899
+ if (validation.success) {
900
+ console.log('Rollback completed successfully');
901
+ return { success: true };
902
+ } else {
903
+ throw new Error('Rollback validation failed');
904
+ }
905
+ } catch (error) {
906
+ console.error('Rollback failed:', error);
907
+ throw error;
908
+ }
909
+ }
910
+
911
+ static async validateRollback() {
912
+ // Implementation for rollback validation
913
+ return { success: true };
914
+ }
915
+ }
916
+ ```
917
+
918
+ For more information about migrating your application, see the [Common Issues Guide](./common-issues.md) and [Debugging Guide](./debugging.md).