@bluealba/platform-cli 1.0.1 → 1.1.0

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 (52) hide show
  1. package/dist/index.js +278 -15
  2. package/docs/404.mdx +5 -0
  3. package/docs/architecture/api-explorer.mdx +478 -0
  4. package/docs/architecture/architecture-diagrams.mdx +12 -0
  5. package/docs/architecture/authentication-system.mdx +903 -0
  6. package/docs/architecture/authorization-system.mdx +886 -0
  7. package/docs/architecture/bootstrap.mdx +1442 -0
  8. package/docs/architecture/gateway-architecture.mdx +845 -0
  9. package/docs/architecture/multi-tenancy.mdx +1150 -0
  10. package/docs/architecture/overview.mdx +776 -0
  11. package/docs/architecture/scheduler.mdx +818 -0
  12. package/docs/architecture/shell.mdx +885 -0
  13. package/docs/architecture/ui-extension-points.mdx +781 -0
  14. package/docs/architecture/user-states.mdx +794 -0
  15. package/docs/development/overview.mdx +21 -0
  16. package/docs/development/workflow.mdx +914 -0
  17. package/docs/getting-started/core-concepts.mdx +892 -0
  18. package/docs/getting-started/installation.mdx +780 -0
  19. package/docs/getting-started/overview.mdx +83 -0
  20. package/docs/getting-started/quick-start.mdx +940 -0
  21. package/docs/guides/adding-documentation-sites.mdx +1367 -0
  22. package/docs/guides/creating-services.mdx +1736 -0
  23. package/docs/guides/creating-ui-modules.mdx +1860 -0
  24. package/docs/guides/identity-providers.mdx +1007 -0
  25. package/docs/guides/mermaid-diagrams.mdx +212 -0
  26. package/docs/guides/using-feature-flags.mdx +1059 -0
  27. package/docs/guides/working-with-rooms.mdx +566 -0
  28. package/docs/index.mdx +57 -0
  29. package/docs/platform-cli/commands.mdx +604 -0
  30. package/docs/platform-cli/overview.mdx +195 -0
  31. package/package.json +5 -2
  32. package/skills/ba-platform/platform-cli.skill.md +26 -0
  33. package/skills/ba-platform/platform.skill.md +35 -0
  34. package/templates/application-monorepo-template/gitignore +95 -0
  35. package/templates/bootstrap-service-template/Dockerfile.development +1 -1
  36. package/templates/bootstrap-service-template/gitignore +57 -0
  37. package/templates/bootstrap-service-template/package.json +1 -1
  38. package/templates/bootstrap-service-template/src/main.ts +6 -16
  39. package/templates/customization-ui-module-template/Dockerfile.development +1 -1
  40. package/templates/customization-ui-module-template/gitignore +73 -0
  41. package/templates/nestjs-service-module-template/Dockerfile.development +1 -1
  42. package/templates/nestjs-service-module-template/gitignore +56 -0
  43. package/templates/platform-init-template/{{platformName}}-core/gitignore +97 -0
  44. package/templates/platform-init-template/{{platformName}}-core/local/.env.example +1 -1
  45. package/templates/platform-init-template/{{platformName}}-core/local/platform-docker-compose.yml +1 -1
  46. package/templates/platform-init-template/{{platformName}}-core/local/{{platformName}}-core-docker-compose.yml +0 -1
  47. package/templates/react-ui-module-template/Dockerfile +1 -1
  48. package/templates/react-ui-module-template/Dockerfile.development +1 -3
  49. package/templates/react-ui-module-template/caddy/Caddyfile +1 -1
  50. package/templates/react-ui-module-template/gitignore +72 -0
  51. package/templates/react-ui-module-template/Dockerfile_nginx +0 -11
  52. package/templates/react-ui-module-template/nginx/default.conf +0 -23
@@ -0,0 +1,794 @@
1
+ ---
2
+ title: User States
3
+ description: User-specific state storage mechanism for persisting user preferences, configurations, and application settings
4
+ ---
5
+
6
+ import { Card, CardGrid, Aside, Tabs, TabItem } from '@astrojs/starlight/components';
7
+
8
+ **User States** provide a key-value storage mechanism for applications to persist user-specific information such as preferences, configurations, and parameters. This enables personalized user experiences that persist across sessions.
9
+
10
+ ## Overview
11
+
12
+ User States allow applications to store and retrieve user-specific data:
13
+
14
+ <CardGrid stagger>
15
+ <Card title="Key-Value Storage" icon="seti:db">
16
+ Simple key-value pairs scoped to user and application
17
+ </Card>
18
+
19
+ <Card title="Persistent Storage" icon="seti:lock">
20
+ Data persists across sessions and survives browser refreshes
21
+ </Card>
22
+
23
+ <Card title="Application-Scoped" icon="seti:folder">
24
+ Values are isolated per application - no cross-app data leakage
25
+ </Card>
26
+
27
+ <Card title="React Hooks API" icon="seti:react">
28
+ Easy-to-use React hooks for UI applications
29
+ </Card>
30
+
31
+ <Card title="REST API" icon="random">
32
+ RESTful endpoints for backend services and non-React apps
33
+ </Card>
34
+
35
+ <Card title="Hierarchical Keys" icon="seti:text">
36
+ Support for namespaced keys using `::` separator
37
+ </Card>
38
+ </CardGrid>
39
+
40
+ ---
41
+
42
+ ## Common Use Cases
43
+
44
+ ### UI Preferences
45
+
46
+ Store user interface preferences:
47
+
48
+ - **Table views and filters**: Column visibility, sort order, pagination size
49
+ - **Layout preferences**: Sidebar collapsed/expanded, theme selection
50
+ - **View modes**: Grid vs list view, compact vs comfortable density
51
+ - **Recently used items**: Last selected entity, recent searches
52
+
53
+ ### Application Configuration
54
+
55
+ Persist application-specific settings:
56
+
57
+ - **Default values**: Default currency, language, timezone
58
+ - **Workflow preferences**: Auto-save frequency, confirmation dialogs
59
+ - **Display options**: Date format, number format
60
+ - **Feature flags**: Beta features enabled by user
61
+
62
+ ### User Context
63
+
64
+ Remember user context between sessions:
65
+
66
+ - **Last viewed entity**: Resume where user left off
67
+ - **Active filters**: Restore filters from last session
68
+ - **Draft data**: Auto-saved form inputs
69
+ - **Navigation state**: Remember last visited route per application
70
+
71
+ ---
72
+
73
+ ## Data Model
74
+
75
+ ### User State Structure
76
+
77
+ ```typescript
78
+ interface UserState {
79
+ id: number;
80
+ user: string; // User identifier (email/username)
81
+ application: string; // Application name
82
+ name: string; // Key name (supports :: hierarchy)
83
+ value: any; // JSON-serializable value
84
+ createdAt: Date;
85
+ updatedAt: Date;
86
+ }
87
+ ```
88
+
89
+ **Example**:
90
+
91
+ ```json
92
+ {
93
+ "id": 123,
94
+ "user": "john@acme.com",
95
+ "application": "crm",
96
+ "name": "ui::customers::table::columns",
97
+ "value": ["name", "email", "phone", "status"],
98
+ "createdAt": "2025-01-01T10:00:00Z",
99
+ "updatedAt": "2025-01-09T15:30:00Z"
100
+ }
101
+ ```
102
+
103
+ ### Hierarchical Keys
104
+
105
+ Keys support a namespace hierarchy using the `::` separator:
106
+
107
+ ```
108
+ application::feature::component::setting
109
+
110
+ Examples:
111
+ - ui::menu::collapsed
112
+ - ui::customers::table::pageSize
113
+ - ui::customers::table::filters
114
+ - ui::dashboard::widgets::visible
115
+ - ui::reports::default::currency
116
+ ```
117
+
118
+ **Benefits**:
119
+ - Organized, self-documenting keys
120
+ - Wildcard queries (e.g., `ui::customers::*`)
121
+ - Easy to reason about data structure
122
+ - Avoid key collisions
123
+
124
+ ---
125
+
126
+ ## Client-Side API (React)
127
+
128
+ For React-based micro-frontends, use the `useUserState` hook:
129
+
130
+ ### Basic Usage
131
+
132
+ ```typescript
133
+ import { useUserState } from '@bluealba-public/pae-ui-react-core';
134
+
135
+ function MyComponent() {
136
+ const { value, setValue, loading, error } = useUserState<boolean>(
137
+ 'ui::menu::collapsed'
138
+ );
139
+
140
+ return (
141
+ <div>
142
+ <MyMenu collapsed={error ? false : value} />
143
+ <Checkbox
144
+ checked={value}
145
+ onChange={(e) => setValue(e.target.checked)}
146
+ disabled={loading}
147
+ />
148
+ {error && <span>Error loading preference</span>}
149
+ </div>
150
+ );
151
+ }
152
+ ```
153
+
154
+ **Hook API**:
155
+
156
+ ```typescript
157
+ function useUserState<T>(key: string): {
158
+ value: T | null; // Current value (null if unset or loading)
159
+ setValue: (value: T) => Promise<void>; // Update value
160
+ loading: boolean; // True while fetching or updating
161
+ error: Error | null; // Error if fetch/update failed
162
+ }
163
+ ```
164
+
165
+ ### Automatic Context Inference
166
+
167
+ The hook automatically infers:
168
+ - **User**: From current authenticated user
169
+ - **Application**: From the micro-frontend's application context
170
+
171
+ No need to manually specify these - the platform handles it!
172
+
173
+ ### Type Safety
174
+
175
+ Use TypeScript generics for type-safe values:
176
+
177
+ ```typescript
178
+ interface TablePreferences {
179
+ pageSize: number;
180
+ sortBy: string;
181
+ sortOrder: 'asc' | 'desc';
182
+ visibleColumns: string[];
183
+ }
184
+
185
+ function CustomersTable() {
186
+ const { value: prefs, setValue } = useUserState<TablePreferences>(
187
+ 'ui::customers::table::preferences'
188
+ );
189
+
190
+ // prefs is typed as TablePreferences | null
191
+ const pageSize = prefs?.pageSize ?? 10;
192
+ const sortBy = prefs?.sortBy ?? 'name';
193
+
194
+ const updatePageSize = (newSize: number) => {
195
+ setValue({
196
+ ...prefs,
197
+ pageSize: newSize,
198
+ });
199
+ };
200
+
201
+ return <Table pageSize={pageSize} onPageSizeChange={updatePageSize} />;
202
+ }
203
+ ```
204
+
205
+ ### Loading States
206
+
207
+ Handle loading and error states:
208
+
209
+ ```typescript
210
+ function UserPreferences() {
211
+ const { value, setValue, loading, error } = useUserState<boolean>(
212
+ 'ui::darkMode'
213
+ );
214
+
215
+ if (loading) {
216
+ return <Spinner />;
217
+ }
218
+
219
+ if (error) {
220
+ return <ErrorMessage>Failed to load preferences</ErrorMessage>;
221
+ }
222
+
223
+ return (
224
+ <Switch
225
+ checked={value ?? false}
226
+ onChange={(checked) => setValue(checked)}
227
+ />
228
+ );
229
+ }
230
+ ```
231
+
232
+ ### Complex State Example
233
+
234
+ ```typescript
235
+ interface DashboardWidgets {
236
+ sales: { visible: boolean; position: number; };
237
+ orders: { visible: boolean; position: number; };
238
+ customers: { visible: boolean; position: number; };
239
+ revenue: { visible: boolean; position: number; };
240
+ }
241
+
242
+ function DashboardCustomizer() {
243
+ const { value: widgets, setValue } = useUserState<DashboardWidgets>(
244
+ 'ui::dashboard::widgets'
245
+ );
246
+
247
+ const toggleWidget = (widgetName: keyof DashboardWidgets) => {
248
+ setValue({
249
+ ...widgets,
250
+ [widgetName]: {
251
+ ...widgets[widgetName],
252
+ visible: !widgets[widgetName].visible,
253
+ },
254
+ });
255
+ };
256
+
257
+ const reorderWidget = (widgetName: keyof DashboardWidgets, newPosition: number) => {
258
+ setValue({
259
+ ...widgets,
260
+ [widgetName]: {
261
+ ...widgets[widgetName],
262
+ position: newPosition,
263
+ },
264
+ });
265
+ };
266
+
267
+ return (
268
+ <div>
269
+ {Object.entries(widgets ?? {}).map(([name, config]) => (
270
+ <WidgetControl
271
+ key={name}
272
+ name={name}
273
+ visible={config.visible}
274
+ position={config.position}
275
+ onToggle={() => toggleWidget(name as keyof DashboardWidgets)}
276
+ onReorder={(pos) => reorderWidget(name as keyof DashboardWidgets, pos)}
277
+ />
278
+ ))}
279
+ </div>
280
+ );
281
+ }
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Server-Side API (REST)
287
+
288
+ For backend services or non-React frontends, use the REST API:
289
+
290
+ ### Endpoints
291
+
292
+ <Tabs>
293
+ <TabItem label="List User States">
294
+ **GET** `/_/user-states/:application`
295
+
296
+ Retrieve all user states for the current user in a specific application.
297
+
298
+ **Path Parameters**:
299
+ - `application` - Application name (required)
300
+
301
+ **Authentication**: User is automatically determined from authenticated session
302
+
303
+ **Response**:
304
+ ```json
305
+ [
306
+ {
307
+ "id": 123,
308
+ "user": "john@acme.com",
309
+ "application": "crm",
310
+ "name": "ui::customers::table::columns",
311
+ "value": ["name", "email", "phone"]
312
+ },
313
+ {
314
+ "id": 124,
315
+ "user": "john@acme.com",
316
+ "application": "crm",
317
+ "name": "ui::customers::table::pageSize",
318
+ "value": 25
319
+ }
320
+ ]
321
+ ```
322
+ </TabItem>
323
+
324
+ <TabItem label="Get User State">
325
+ **GET** `/_/user-states/:application/:name`
326
+
327
+ Retrieve a specific user state by application and key name.
328
+
329
+ **Path Parameters**:
330
+ - `application` - Application name (required)
331
+ - `name` - State key name (required)
332
+
333
+ **Response**:
334
+ ```json
335
+ {
336
+ "id": 123,
337
+ "user": "john@acme.com",
338
+ "application": "crm",
339
+ "name": "ui::menu::collapsed",
340
+ "value": true
341
+ }
342
+ ```
343
+
344
+ **Returns `null` if not found**
345
+ </TabItem>
346
+
347
+ <TabItem label="Create User State">
348
+ **POST** `/_/user-states/:application/:name`
349
+
350
+ Create a new user state.
351
+
352
+ **Path Parameters**:
353
+ - `application` - Application name (required)
354
+ - `name` - State key name (required)
355
+
356
+ **Request Body**:
357
+ ```json
358
+ {
359
+ "value": true
360
+ }
361
+ ```
362
+
363
+ **Response**:
364
+ ```json
365
+ {
366
+ "id": 123,
367
+ "user": "john@acme.com",
368
+ "application": "crm",
369
+ "name": "ui::menu::collapsed",
370
+ "value": true
371
+ }
372
+ ```
373
+
374
+ **Error Responses**:
375
+ - `409 Conflict` - User state already exists (use PUT to update)
376
+ - `400 Bad Request` - Value is required
377
+ </TabItem>
378
+
379
+ <TabItem label="Update User State">
380
+ **PUT** `/_/user-states/:application/:name`
381
+
382
+ Update an existing user state.
383
+
384
+ **Path Parameters**:
385
+ - `application` - Application name (required)
386
+ - `name` - State key name (required)
387
+
388
+ **Request Body**:
389
+ ```json
390
+ {
391
+ "value": false
392
+ }
393
+ ```
394
+
395
+ **Response**:
396
+ ```json
397
+ {
398
+ "id": 123,
399
+ "user": "john@acme.com",
400
+ "application": "crm",
401
+ "name": "ui::menu::collapsed",
402
+ "value": false
403
+ }
404
+ ```
405
+
406
+ **Error Responses**:
407
+ - `404 Not Found` - User state does not exist (use POST to create)
408
+ - `400 Bad Request` - Value is required
409
+ </TabItem>
410
+
411
+ <TabItem label="Delete User State">
412
+ **DELETE** `/_/user-states/:application/:name`
413
+
414
+ Delete a specific user state.
415
+
416
+ **Path Parameters**:
417
+ - `application` - Application name (required)
418
+ - `name` - State key name (required)
419
+
420
+ **Response**: `204 No Content` (empty response on success)
421
+
422
+ **Error Response**:
423
+ - `404 Not Found` - User state does not exist
424
+ </TabItem>
425
+
426
+ <TabItem label="Delete All States for Application">
427
+ **DELETE** `/_/user-states/:application`
428
+
429
+ Delete all user states for the current user in a specific application.
430
+
431
+ **Path Parameters**:
432
+ - `application` - Application name (required)
433
+
434
+ **Response**:
435
+ ```json
436
+ {
437
+ "deletedCount": 12
438
+ }
439
+ ```
440
+ </TabItem>
441
+
442
+ <TabItem label="Admin: Delete All States for User">
443
+ **DELETE** `/_/user-states/admin/user/:username`
444
+
445
+ Admin endpoint to delete all user states for a specific user across all applications.
446
+
447
+ **Path Parameters**:
448
+ - `username` - Username (required)
449
+
450
+ **Response**:
451
+ ```json
452
+ {
453
+ "deletedCount": 45
454
+ }
455
+ ```
456
+
457
+ **Note**: This is an admin-only endpoint. Requires appropriate admin permissions.
458
+ </TabItem>
459
+ </Tabs>
460
+
461
+ ### cURL Examples
462
+
463
+ ```bash
464
+ # List all states for an application
465
+ curl -X GET "https://platform.com/_/user-states/crm" \
466
+ -H "Cookie: auth_token=..."
467
+
468
+ # Get a specific user state
469
+ curl -X GET "https://platform.com/_/user-states/crm/ui::menu::collapsed" \
470
+ -H "Cookie: auth_token=..."
471
+
472
+ # Create a new user state
473
+ curl -X POST "https://platform.com/_/user-states/crm/ui::menu::collapsed" \
474
+ -H "Content-Type: application/json" \
475
+ -H "Cookie: auth_token=..." \
476
+ -d '{
477
+ "value": true
478
+ }'
479
+
480
+ # Update an existing user state
481
+ curl -X PUT "https://platform.com/_/user-states/crm/ui::menu::collapsed" \
482
+ -H "Content-Type: application/json" \
483
+ -H "Cookie: auth_token=..." \
484
+ -d '{
485
+ "value": false
486
+ }'
487
+
488
+ # Delete a user state
489
+ curl -X DELETE "https://platform.com/_/user-states/crm/ui::menu::collapsed" \
490
+ -H "Cookie: auth_token=..."
491
+
492
+ # Delete all states for an application
493
+ curl -X DELETE "https://platform.com/_/user-states/crm" \
494
+ -H "Cookie: auth_token=..."
495
+
496
+ # Admin: Delete all states for a user
497
+ curl -X DELETE "https://platform.com/_/user-states/admin/user/john@acme.com" \
498
+ -H "Cookie: auth_token=..."
499
+ ```
500
+
501
+ ---
502
+
503
+ ## Advanced Patterns
504
+
505
+ ### Typed State Blueprint (Future Enhancement)
506
+
507
+ For large applications with many user states, a typed blueprint approach is planned:
508
+
509
+ ```typescript
510
+ // Define complete application user state schema
511
+ interface MyAppUserStateSchema {
512
+ 'ui': {
513
+ 'menu': {
514
+ 'collapsed': boolean;
515
+ };
516
+ 'customers': {
517
+ 'table': {
518
+ 'columns': string[];
519
+ 'pageSize': number;
520
+ 'filters': {
521
+ field: string;
522
+ operator: string;
523
+ value: any;
524
+ }[];
525
+ };
526
+ };
527
+ };
528
+ }
529
+
530
+ // Create typed blueprint
531
+ const MyAppUserState = createUserStateBlueprint<MyAppUserStateSchema>();
532
+
533
+ // Use with type safety
534
+ function Component() {
535
+ const { value, setValue } = MyAppUserState.useStateFor('ui::customers::table::filters');
536
+ // value is typed as the filter array
537
+ }
538
+ ```
539
+
540
+ <Aside type="note" title="Future Feature">
541
+ The typed blueprint API is planned for a future release and is not yet implemented.
542
+ </Aside>
543
+
544
+ ### Filtering States
545
+
546
+ Retrieve all states for an application and filter them client-side:
547
+
548
+ ```bash
549
+ # Get all states for an application
550
+ GET /_/user-states/crm
551
+
552
+ # Then filter the results in your code
553
+ const allStates = await fetch('/_/user-states/crm');
554
+ const tableStates = allStates.filter(state =>
555
+ state.name.includes('::table::')
556
+ );
557
+ ```
558
+
559
+ ### Default Values
560
+
561
+ Always provide sensible defaults:
562
+
563
+ ```typescript
564
+ function Component() {
565
+ const { value } = useUserState<number>('ui::table::pageSize');
566
+
567
+ // Use default if value is null (not set)
568
+ const pageSize = value ?? 10;
569
+
570
+ return <Table pageSize={pageSize} />;
571
+ }
572
+ ```
573
+
574
+ ### Optimistic Updates
575
+
576
+ Update UI immediately, sync in background:
577
+
578
+ ```typescript
579
+ function Component() {
580
+ const { value, setValue } = useUserState<boolean>('ui::menu::collapsed');
581
+ const [localValue, setLocalValue] = useState(value);
582
+
583
+ const toggle = async () => {
584
+ const newValue = !localValue;
585
+ setLocalValue(newValue); // Update UI immediately
586
+ await setValue(newValue); // Sync to server
587
+ };
588
+
589
+ return <Menu collapsed={localValue} onToggle={toggle} />;
590
+ }
591
+ ```
592
+
593
+ ---
594
+
595
+ ## Best Practices
596
+
597
+ <CardGrid>
598
+ <Card title="Use Hierarchical Keys" icon="seti:text">
599
+ Organize keys with `::` separator for clarity and maintainability
600
+ </Card>
601
+
602
+ <Card title="Provide Defaults" icon="approve-check">
603
+ Always handle null values with sensible defaults
604
+ </Card>
605
+
606
+ <Card title="Type Your Values" icon="seti:typescript">
607
+ Use TypeScript generics for type safety
608
+ </Card>
609
+
610
+ <Card title="Scope Appropriately" icon="seti:folder">
611
+ Use application-specific keys to avoid conflicts
612
+ </Card>
613
+
614
+ <Card title="Handle Errors Gracefully" icon="warning">
615
+ Don't break UX if user state fetch fails
616
+ </Card>
617
+
618
+ <Card title="Document State Keys" icon="document">
619
+ Maintain documentation of all user state keys used by your app
620
+ </Card>
621
+ </CardGrid>
622
+
623
+ ---
624
+
625
+ ## Security Considerations
626
+
627
+ <Aside type="caution" title="Security Best Practices">
628
+ - **Never store sensitive data**: Passwords, API keys, tokens should NOT be stored in user states
629
+ - **Validate on server**: Don't trust user state values blindly - validate them
630
+ - **Respect tenant boundaries**: User states are tenant-scoped, maintain this isolation
631
+ - **Size limits**: Avoid storing large objects - user states are for configuration, not data storage
632
+ - **Rate limiting**: Be mindful of update frequency to avoid overwhelming the API
633
+ </Aside>
634
+
635
+ ---
636
+
637
+ ## Performance Optimization
638
+
639
+ ### Batch Queries
640
+
641
+ When loading multiple states, fetch in parallel:
642
+
643
+ ```typescript
644
+ function Dashboard() {
645
+ const widgets = useUserState<WidgetConfig>('ui::dashboard::widgets');
646
+ const layout = useUserState<LayoutConfig>('ui::dashboard::layout');
647
+ const theme = useUserState<ThemeConfig>('ui::dashboard::theme');
648
+
649
+ // All three queries execute in parallel
650
+ if (widgets.loading || layout.loading || theme.loading) {
651
+ return <Loading />;
652
+ }
653
+
654
+ return <DashboardView widgets={widgets.value} layout={layout.value} theme={theme.value} />;
655
+ }
656
+ ```
657
+
658
+ ### Debounce Updates
659
+
660
+ For frequently changing values, debounce updates:
661
+
662
+ ```typescript
663
+ import { useDebouncedCallback } from 'use-debounce';
664
+
665
+ function SearchInput() {
666
+ const { value, setValue } = useUserState<string>('ui::search::lastQuery');
667
+ const [localValue, setLocalValue] = useState(value ?? '');
668
+
669
+ const debouncedSave = useDebouncedCallback((newValue: string) => {
670
+ setValue(newValue);
671
+ }, 1000);
672
+
673
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
674
+ const newValue = e.target.value;
675
+ setLocalValue(newValue);
676
+ debouncedSave(newValue);
677
+ };
678
+
679
+ return <input value={localValue} onChange={handleChange} />;
680
+ }
681
+ ```
682
+
683
+ ### Memoization
684
+
685
+ Memoize expensive computations based on user state:
686
+
687
+ ```typescript
688
+ function DataTable() {
689
+ const { value: columns } = useUserState<string[]>('ui::table::columns');
690
+
691
+ const processedData = useMemo(() => {
692
+ if (!columns) return [];
693
+ return data.map(row =>
694
+ Object.fromEntries(
695
+ Object.entries(row).filter(([key]) => columns.includes(key))
696
+ )
697
+ );
698
+ }, [data, columns]);
699
+
700
+ return <Table data={processedData} />;
701
+ }
702
+ ```
703
+
704
+ ---
705
+
706
+ ## Future Enhancements
707
+
708
+ Planned features for future releases:
709
+
710
+ ### Shared States
711
+
712
+ Allow users to share state with other users or groups:
713
+
714
+ - **Shared views**: Share table configurations with team members
715
+ - **Team preferences**: Group-level defaults
716
+ - **Template states**: Pre-configured states for new users
717
+
718
+ ### Admin UI
719
+
720
+ Administrative interface for managing user states:
721
+
722
+ - **Global user states view**: See all states across all users
723
+ - **User-specific view**: View and edit states for a specific user
724
+ - **Bulk operations**: Delete or update multiple states at once
725
+ - **Analytics**: Most common preferences, usage patterns
726
+
727
+ ### State Migrations
728
+
729
+ Version and migrate user state schemas:
730
+
731
+ - **Data versioning**: Track schema version with state data
732
+ - **Automatic migrations**: Migrate old state formats to new schemas
733
+ - **Migration hooks**: Application-defined migration logic
734
+ - **Rollback support**: Safely rollback breaking changes
735
+
736
+ ### State Synchronization
737
+
738
+ Real-time synchronization across devices:
739
+
740
+ - **WebSocket updates**: Push state changes to all user sessions
741
+ - **Conflict resolution**: Handle concurrent updates gracefully
742
+ - **Offline support**: Queue updates when offline, sync when reconnected
743
+
744
+ ---
745
+
746
+ ## Troubleshooting
747
+
748
+ ### State Not Persisting
749
+
750
+ **Check**:
751
+ 1. User is authenticated
752
+ 2. Application context is set correctly
753
+ 3. No network errors (check browser console)
754
+ 4. API endpoints are accessible
755
+
756
+ **Debug**:
757
+ ```typescript
758
+ const { value, setValue, error } = useUserState('my::key');
759
+
760
+ useEffect(() => {
761
+ console.log('User state:', { value, error });
762
+ }, [value, error]);
763
+ ```
764
+
765
+ ### State Not Loading
766
+
767
+ **Possible Causes**:
768
+ - User state never created (first time user)
769
+ - Wrong key name
770
+ - Application context mismatch
771
+
772
+ **Solution**: Always provide defaults
773
+ ```typescript
774
+ const { value } = useUserState<boolean>('ui::menu::collapsed');
775
+ const collapsed = value ?? false; // Default to false
776
+ ```
777
+
778
+ ### Type Errors
779
+
780
+ **Cause**: Mismatch between stored value type and TypeScript type.
781
+
782
+ **Solution**: Validate and transform stored values
783
+ ```typescript
784
+ const { value } = useUserState<number>('ui::pageSize');
785
+ const pageSize = typeof value === 'number' && value > 0 ? value : 10;
786
+ ```
787
+
788
+ ---
789
+
790
+ ## Next Steps
791
+
792
+ - **[API Explorer](/_/docs/architecture/api-explorer/)** - Testing user state API endpoints
793
+ - **[Shell Architecture](/_/docs/architecture/shell/)** - Using user states for Shell customization
794
+ - **[Getting Started with UI Development](/_/docs/development/ui-development/)** - Building UIs that use user states