ai-flow-dev 1.0.1
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/LICENSE +21 -0
- package/README.md +408 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +791 -0
- package/dist/cli.js.map +1 -0
- package/dist/fs-utils.d.ts +2 -0
- package/dist/fs-utils.d.ts.map +1 -0
- package/dist/fs-utils.js +46 -0
- package/dist/fs-utils.js.map +1 -0
- package/package.json +71 -0
- package/prompts/backend/flow-dev-feature.md +1318 -0
- package/prompts/backend/flow-dev-fix.md +903 -0
- package/prompts/backend/flow-dev-refactor.md +715 -0
- package/prompts/backend/flow-dev-review.md +401 -0
- package/prompts/backend/flow-dev-work.md +1129 -0
- package/prompts/backend/flow-docs-gen-phase-0.md +1840 -0
- package/prompts/backend/flow-docs-gen-phase-1.md +435 -0
- package/prompts/backend/flow-docs-gen-phase-2.md +460 -0
- package/prompts/backend/flow-docs-gen-phase-3.md +684 -0
- package/prompts/backend/flow-docs-gen-phase-4.md +516 -0
- package/prompts/backend/flow-docs-gen-phase-5.md +637 -0
- package/prompts/backend/flow-docs-gen-phase-6.md +465 -0
- package/prompts/backend/flow-docs-gen-phase-7.md +1207 -0
- package/prompts/backend/flow-docs-gen.md +820 -0
- package/prompts/backend/flow-docs-sync.md +526 -0
- package/prompts/backend/flow-project-init.md +248 -0
- package/prompts/backend/flow-project-roadmap.md +1159 -0
- package/prompts/frontend/flow-docs-gen-phase-0.md +494 -0
- package/prompts/frontend/flow-docs-gen-phase-1.md +449 -0
- package/prompts/frontend/flow-docs-gen-phase-2.md +983 -0
- package/prompts/frontend/flow-docs-gen-phase-3.md +685 -0
- package/prompts/frontend/flow-docs-gen-phase-4.md +480 -0
- package/prompts/frontend/flow-docs-gen-phase-5.md +483 -0
- package/prompts/frontend/flow-docs-gen-phase-6.md +570 -0
- package/prompts/frontend/flow-docs-gen-phase-7.md +582 -0
- package/prompts/frontend/flow-docs-gen.md +413 -0
- package/prompts/frontend/flow-docs-sync.md +561 -0
- package/prompts/mobile/flow-docs-gen-phase-0.md +387 -0
- package/prompts/mobile/flow-docs-gen-phase-1.md +530 -0
- package/prompts/mobile/flow-docs-gen-phase-2.md +584 -0
- package/prompts/mobile/flow-docs-gen-phase-3.md +659 -0
- package/prompts/mobile/flow-docs-gen-phase-4.md +363 -0
- package/prompts/mobile/flow-docs-gen-phase-5.md +369 -0
- package/prompts/mobile/flow-docs-gen-phase-6.md +490 -0
- package/prompts/mobile/flow-docs-gen-phase-7.md +407 -0
- package/prompts/mobile/flow-docs-gen.md +430 -0
- package/prompts/mobile/flow-docs-sync.md +634 -0
- package/templates/backend/.clauderules.template +111 -0
- package/templates/backend/.cursorrules.template +102 -0
- package/templates/backend/.env.example.template +122 -0
- package/templates/backend/README.template.md +200 -0
- package/templates/backend/ai-instructions.template.md +354 -0
- package/templates/backend/copilot-instructions.template.md +160 -0
- package/templates/backend/docs/api.template.md +251 -0
- package/templates/backend/docs/architecture.template.md +612 -0
- package/templates/backend/docs/business-flows.template.md +109 -0
- package/templates/backend/docs/code-standards.template.md +828 -0
- package/templates/backend/docs/contributing.template.md +163 -0
- package/templates/backend/docs/data-model.template.md +416 -0
- package/templates/backend/docs/operations.template.md +591 -0
- package/templates/backend/docs/testing.template.md +762 -0
- package/templates/backend/project-brief.template.md +176 -0
- package/templates/backend/specs/configuration.template.md +133 -0
- package/templates/backend/specs/security.template.md +422 -0
- package/templates/frontend/README.template.md +121 -0
- package/templates/frontend/ai-instructions.template.md +368 -0
- package/templates/frontend/docs/api-integration.template.md +390 -0
- package/templates/frontend/docs/components.template.md +567 -0
- package/templates/frontend/docs/error-handling.template.md +385 -0
- package/templates/frontend/docs/operations.template.md +123 -0
- package/templates/frontend/docs/performance.template.md +140 -0
- package/templates/frontend/docs/pwa.template.md +135 -0
- package/templates/frontend/docs/state-management.template.md +394 -0
- package/templates/frontend/docs/styling.template.md +779 -0
- package/templates/frontend/docs/testing.template.md +736 -0
- package/templates/frontend/project-brief.template.md +55 -0
- package/templates/frontend/specs/accessibility.template.md +111 -0
- package/templates/frontend/specs/configuration.template.md +520 -0
- package/templates/frontend/specs/security.template.md +197 -0
- package/templates/fullstack/README.template.md +282 -0
- package/templates/fullstack/ai-instructions.template.md +487 -0
- package/templates/fullstack/project-brief.template.md +197 -0
- package/templates/fullstack/specs/configuration.template.md +380 -0
- package/templates/mobile/AGENT.template.md +251 -0
- package/templates/mobile/README.template.md +195 -0
- package/templates/mobile/ai-instructions.template.md +221 -0
- package/templates/mobile/docs/app-store.template.md +163 -0
- package/templates/mobile/docs/architecture.template.md +100 -0
- package/templates/mobile/docs/native-features.template.md +137 -0
- package/templates/mobile/docs/navigation.template.md +81 -0
- package/templates/mobile/docs/offline-strategy.template.md +90 -0
- package/templates/mobile/docs/permissions.template.md +70 -0
- package/templates/mobile/docs/state-management.template.md +116 -0
- package/templates/mobile/docs/testing.template.md +146 -0
- package/templates/mobile/project-brief.template.md +97 -0
- package/templates/mobile/specs/build-configuration.template.md +116 -0
- package/templates/mobile/specs/deployment.template.md +114 -0
- package/templates/shared/AGENT.template.md +252 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Progressive Web App (PWA)
|
|
2
|
+
|
|
3
|
+
> PWA features and offline capabilities for {{PROJECT_NAME}}
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ๐ฏ PWA Strategy
|
|
8
|
+
|
|
9
|
+
**Service Worker:** {{SERVICE_WORKER_ENABLED}}
|
|
10
|
+
**Caching Strategy:** {{CACHING_STRATEGY}}
|
|
11
|
+
**Install Prompt:** {{INSTALL_PROMPT}}
|
|
12
|
+
**Offline Support:** {{OFFLINE_SUPPORT}}
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## ๐ง Service Worker
|
|
17
|
+
|
|
18
|
+
### Registration
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// registerServiceWorker.ts
|
|
22
|
+
if ('serviceWorker' in navigator) {
|
|
23
|
+
window.addEventListener('load', () => {
|
|
24
|
+
navigator.serviceWorker
|
|
25
|
+
.register('/sw.js')
|
|
26
|
+
.then((registration) => {
|
|
27
|
+
console.log('SW registered:', registration);
|
|
28
|
+
})
|
|
29
|
+
.catch((error) => {
|
|
30
|
+
console.error('SW registration failed:', error);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Service Worker Implementation
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
// public/sw.js
|
|
40
|
+
const CACHE_NAME = 'app-v1';
|
|
41
|
+
const urlsToCache = [
|
|
42
|
+
'/',
|
|
43
|
+
'/index.html',
|
|
44
|
+
'/assets/app.js',
|
|
45
|
+
'/assets/app.css',
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
// Install
|
|
49
|
+
self.addEventListener('install', (event) => {
|
|
50
|
+
event.waitUntil(
|
|
51
|
+
caches.open(CACHE_NAME).then((cache) => {
|
|
52
|
+
return cache.addAll(urlsToCache);
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Fetch (Cache-first strategy)
|
|
58
|
+
self.addEventListener('fetch', (event) => {
|
|
59
|
+
event.respondWith(
|
|
60
|
+
caches.match(event.request).then((response) => {
|
|
61
|
+
return response || fetch(event.request);
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## ๐ฑ Web App Manifest
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
// public/manifest.json
|
|
73
|
+
{
|
|
74
|
+
"name": "{{PROJECT_NAME}}",
|
|
75
|
+
"short_name": "{{PROJECT_SHORT_NAME}}",
|
|
76
|
+
"description": "{{PROJECT_DESCRIPTION}}",
|
|
77
|
+
"start_url": "/",
|
|
78
|
+
"display": "standalone",
|
|
79
|
+
"background_color": "#ffffff",
|
|
80
|
+
"theme_color": "#000000",
|
|
81
|
+
"icons": [
|
|
82
|
+
{
|
|
83
|
+
"src": "/icon-192.png",
|
|
84
|
+
"sizes": "192x192",
|
|
85
|
+
"type": "image/png"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"src": "/icon-512.png",
|
|
89
|
+
"sizes": "512x512",
|
|
90
|
+
"type": "image/png"
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## ๐ฒ Install Prompt
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// utils/installPrompt.ts
|
|
102
|
+
let deferredPrompt: BeforeInstallPromptEvent | null = null;
|
|
103
|
+
|
|
104
|
+
window.addEventListener('beforeinstallprompt', (e) => {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
deferredPrompt = e;
|
|
107
|
+
showInstallButton();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export function showInstallPrompt() {
|
|
111
|
+
if (deferredPrompt) {
|
|
112
|
+
deferredPrompt.prompt();
|
|
113
|
+
deferredPrompt.userChoice.then((choiceResult) => {
|
|
114
|
+
if (choiceResult.outcome === 'accepted') {
|
|
115
|
+
console.log('User accepted install');
|
|
116
|
+
}
|
|
117
|
+
deferredPrompt = null;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## ๐ Related Documents
|
|
126
|
+
|
|
127
|
+
- [Performance](performance.md) - PWA performance
|
|
128
|
+
- [Operations](operations.md) - PWA deployment
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
**Last Updated:** {{GENERATION_DATE}}
|
|
133
|
+
|
|
134
|
+
**PWA Features:** {{PWA_FEATURES}}
|
|
135
|
+
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
# State Management
|
|
2
|
+
|
|
3
|
+
> State management patterns and best practices for {{PROJECT_NAME}}
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ๐ฏ State Management Solution
|
|
8
|
+
|
|
9
|
+
**Solution:** {{STATE_MANAGEMENT}}
|
|
10
|
+
|
|
11
|
+
{{STATE_MANAGEMENT_DESCRIPTION}}
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ๐ State Categories
|
|
16
|
+
|
|
17
|
+
### 1. Server State (Remote Data)
|
|
18
|
+
|
|
19
|
+
**Managed by:** {{DATA_FETCHING}}
|
|
20
|
+
|
|
21
|
+
**Characteristics:**
|
|
22
|
+
- Fetched from APIs
|
|
23
|
+
- Cached and synchronized
|
|
24
|
+
- May be stale
|
|
25
|
+
- Shared across components
|
|
26
|
+
|
|
27
|
+
**Examples:**
|
|
28
|
+
- User data from `/api/user`
|
|
29
|
+
- Product listings
|
|
30
|
+
- Blog posts
|
|
31
|
+
|
|
32
|
+
**Pattern:**
|
|
33
|
+
```typescript
|
|
34
|
+
// Using {{DATA_FETCHING}}
|
|
35
|
+
const { data, isLoading, error, refetch } = useQuery({
|
|
36
|
+
queryKey: ['users', userId],
|
|
37
|
+
queryFn: () => fetchUser(userId)
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (isLoading) return <Spinner />;
|
|
41
|
+
if (error) return <Error message={error.message} />;
|
|
42
|
+
|
|
43
|
+
return <UserProfile user={data} />;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### 2. Client State (Local UI State)
|
|
49
|
+
|
|
50
|
+
**Managed by:** {{STATE_MANAGEMENT}}
|
|
51
|
+
|
|
52
|
+
**Characteristics:**
|
|
53
|
+
- Exists only in frontend
|
|
54
|
+
- Controls UI behavior
|
|
55
|
+
- Not persisted to server (usually)
|
|
56
|
+
|
|
57
|
+
**Examples:**
|
|
58
|
+
- Modal open/closed
|
|
59
|
+
- Theme (dark/light mode)
|
|
60
|
+
- Current tab selected
|
|
61
|
+
- Form validation errors
|
|
62
|
+
|
|
63
|
+
**Pattern:**
|
|
64
|
+
```typescript
|
|
65
|
+
// Using {{STATE_MANAGEMENT}}
|
|
66
|
+
{{CLIENT_STATE_EXAMPLE}}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### 3. URL State (Query Params & Routes)
|
|
72
|
+
|
|
73
|
+
**Managed by:** Router + URL
|
|
74
|
+
|
|
75
|
+
**Characteristics:**
|
|
76
|
+
- Persisted in URL
|
|
77
|
+
- Shareable via link
|
|
78
|
+
- Browser back/forward works
|
|
79
|
+
|
|
80
|
+
**Examples:**
|
|
81
|
+
- Search query: `?q=react`
|
|
82
|
+
- Filters: `?category=tech&sort=date`
|
|
83
|
+
- Pagination: `?page=3`
|
|
84
|
+
- Selected item: `/posts/123`
|
|
85
|
+
|
|
86
|
+
**Pattern:**
|
|
87
|
+
```typescript
|
|
88
|
+
// React Router
|
|
89
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
90
|
+
const query = searchParams.get('q') || '';
|
|
91
|
+
|
|
92
|
+
// Vue Router
|
|
93
|
+
const route = useRoute();
|
|
94
|
+
const query = route.query.q || '';
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### 4. Form State
|
|
100
|
+
|
|
101
|
+
**Managed by:** {{FORM_LIBRARY}}
|
|
102
|
+
|
|
103
|
+
**Characteristics:**
|
|
104
|
+
- Temporary, component-scoped
|
|
105
|
+
- Validation logic
|
|
106
|
+
- Reset on submit
|
|
107
|
+
|
|
108
|
+
**Pattern:**
|
|
109
|
+
```typescript
|
|
110
|
+
// Using {{FORM_LIBRARY}}
|
|
111
|
+
{{FORM_STATE_EXAMPLE}}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## ๐๏ธ State Architecture
|
|
117
|
+
|
|
118
|
+
### State Location Decision Tree
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Is data from server?
|
|
122
|
+
โโ YES โ Use {{DATA_FETCHING}} (server state)
|
|
123
|
+
โโ NO โ Is it global/shared?
|
|
124
|
+
โโ YES โ Use {{STATE_MANAGEMENT}} (global client state)
|
|
125
|
+
โโ NO โ Is it URL-related?
|
|
126
|
+
โโ YES โ Use router/query params (URL state)
|
|
127
|
+
โโ NO โ Use local component state
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## ๐จ {{STATE_MANAGEMENT}} Patterns
|
|
133
|
+
|
|
134
|
+
### Store Structure
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
{{STORE_STRUCTURE_EXAMPLE}}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Reading State
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
{{READ_STATE_EXAMPLE}}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Updating State
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
{{UPDATE_STATE_EXAMPLE}}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## ๐ Data Flow
|
|
155
|
+
|
|
156
|
+
### Unidirectional Data Flow
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
User Action
|
|
160
|
+
โ
|
|
161
|
+
Event Handler
|
|
162
|
+
โ
|
|
163
|
+
Update State (store/API)
|
|
164
|
+
โ
|
|
165
|
+
State Change
|
|
166
|
+
โ
|
|
167
|
+
Component Re-render
|
|
168
|
+
โ
|
|
169
|
+
Updated UI
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Example: Todo App
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// 1. User clicks "Add Todo"
|
|
176
|
+
<button onClick={() => addTodo(text)}>Add</button>
|
|
177
|
+
|
|
178
|
+
// 2. Action dispatched
|
|
179
|
+
const addTodo = (text: string) => {
|
|
180
|
+
// Update local state optimistically
|
|
181
|
+
setTodos([...todos, { id: Date.now(), text, done: false }]);
|
|
182
|
+
|
|
183
|
+
// Sync to server
|
|
184
|
+
api.createTodo({ text })
|
|
185
|
+
.catch(error => {
|
|
186
|
+
// Rollback on error
|
|
187
|
+
setTodos(todos);
|
|
188
|
+
showError(error);
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// 3. State updated โ Component re-renders
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## ๐ Performance Optimization
|
|
198
|
+
|
|
199
|
+
### 1. Avoid Over-Rendering
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// โ Bad - Every field change re-renders entire form
|
|
203
|
+
const FormContainer = () => {
|
|
204
|
+
const [formData, setFormData] = useState({ name: '', email: '', bio: '' });
|
|
205
|
+
|
|
206
|
+
return <Form data={formData} onChange={setFormData} />;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// โ
Good - Each field independent
|
|
210
|
+
const FormContainer = () => {
|
|
211
|
+
return (
|
|
212
|
+
<Form>
|
|
213
|
+
<NameField />
|
|
214
|
+
<EmailField />
|
|
215
|
+
<BioField />
|
|
216
|
+
</Form>
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 2. Selector Optimization
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// โ Bad - New array every render (breaks memoization)
|
|
225
|
+
const activeUsers = useStore(state => state.users.filter(u => u.active));
|
|
226
|
+
|
|
227
|
+
// โ
Good - Memoized selector
|
|
228
|
+
const selectActiveUsers = createSelector(
|
|
229
|
+
[(state) => state.users],
|
|
230
|
+
(users) => users.filter(u => u.active)
|
|
231
|
+
);
|
|
232
|
+
const activeUsers = useStore(selectActiveUsers);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 3. State Normalization
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// โ Bad - Nested, hard to update
|
|
239
|
+
const state = {
|
|
240
|
+
posts: [
|
|
241
|
+
{ id: 1, title: 'Post 1', author: { id: 10, name: 'Alice' } },
|
|
242
|
+
{ id: 2, title: 'Post 2', author: { id: 10, name: 'Alice' } }
|
|
243
|
+
]
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// โ
Good - Normalized
|
|
247
|
+
const state = {
|
|
248
|
+
posts: {
|
|
249
|
+
byId: {
|
|
250
|
+
1: { id: 1, title: 'Post 1', authorId: 10 },
|
|
251
|
+
2: { id: 2, title: 'Post 2', authorId: 10 }
|
|
252
|
+
},
|
|
253
|
+
allIds: [1, 2]
|
|
254
|
+
},
|
|
255
|
+
users: {
|
|
256
|
+
byId: {
|
|
257
|
+
10: { id: 10, name: 'Alice' }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## ๐ State Persistence
|
|
266
|
+
|
|
267
|
+
### Local Storage
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// Save state to localStorage
|
|
271
|
+
const saveState = (key: string, state: any) => {
|
|
272
|
+
localStorage.setItem(key, JSON.stringify(state));
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// Load state from localStorage
|
|
276
|
+
const loadState = (key: string) => {
|
|
277
|
+
const saved = localStorage.getItem(key);
|
|
278
|
+
return saved ? JSON.parse(saved) : null;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// Initialize store with persisted state
|
|
282
|
+
const useThemeStore = create(
|
|
283
|
+
persist(
|
|
284
|
+
(set) => ({
|
|
285
|
+
theme: 'light',
|
|
286
|
+
setTheme: (theme) => set({ theme })
|
|
287
|
+
}),
|
|
288
|
+
{ name: 'theme-storage' }
|
|
289
|
+
)
|
|
290
|
+
);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## ๐งช Testing State
|
|
296
|
+
|
|
297
|
+
### Unit Testing Store Logic
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
describe('TodoStore', () => {
|
|
301
|
+
it('adds todo', () => {
|
|
302
|
+
const { result } = renderHook(() => useTodoStore());
|
|
303
|
+
|
|
304
|
+
act(() => {
|
|
305
|
+
result.current.addTodo('Buy milk');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
expect(result.current.todos).toHaveLength(1);
|
|
309
|
+
expect(result.current.todos[0].text).toBe('Buy milk');
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Integration Testing with Components
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
test('displays todos from store', () => {
|
|
318
|
+
const todos = [
|
|
319
|
+
{ id: 1, text: 'Todo 1', done: false },
|
|
320
|
+
{ id: 2, text: 'Todo 2', done: true }
|
|
321
|
+
];
|
|
322
|
+
|
|
323
|
+
// Setup store state
|
|
324
|
+
useTodoStore.setState({ todos });
|
|
325
|
+
|
|
326
|
+
render(<TodoList />);
|
|
327
|
+
|
|
328
|
+
expect(screen.getByText('Todo 1')).toBeInTheDocument();
|
|
329
|
+
expect(screen.getByText('Todo 2')).toBeInTheDocument();
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## โ ๏ธ Common Pitfalls
|
|
336
|
+
|
|
337
|
+
### 1. Storing Derived Data
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
// โ Bad - Storing computed value
|
|
341
|
+
const state = {
|
|
342
|
+
todos: [...],
|
|
343
|
+
completedCount: 5 // Derived from todos
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// โ
Good - Compute on the fly
|
|
347
|
+
const state = {
|
|
348
|
+
todos: [...]
|
|
349
|
+
};
|
|
350
|
+
const completedCount = todos.filter(t => t.done).length;
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### 2. Mutating State Directly
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
// โ Bad - Direct mutation
|
|
357
|
+
state.user.name = 'Alice';
|
|
358
|
+
|
|
359
|
+
// โ
Good - Immutable update
|
|
360
|
+
setState({ user: { ...state.user, name: 'Alice' } });
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 3. Over-Using Global State
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
// โ Bad - Everything in global store
|
|
367
|
+
const globalState = {
|
|
368
|
+
modalOpen: false, // Should be local
|
|
369
|
+
currentTab: 'home', // Should be URL
|
|
370
|
+
formErrors: {}, // Should be form state
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// โ
Good - Only truly global data
|
|
374
|
+
const globalState = {
|
|
375
|
+
user: { ... },
|
|
376
|
+
theme: 'dark',
|
|
377
|
+
notifications: [...]
|
|
378
|
+
};
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## ๐ Related Documents
|
|
384
|
+
|
|
385
|
+
- [AI Instructions](../ai-instructions.md) - State management rules
|
|
386
|
+
- [Component Architecture](components.md) - Component/state interaction
|
|
387
|
+
- [API Integration](api-integration.md) - Server state patterns
|
|
388
|
+
- [Testing Strategy](testing.md) - Testing state logic
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
**Last Updated:** {{GENERATION_DATE}}
|
|
393
|
+
|
|
394
|
+
**Solution:** {{STATE_MANAGEMENT}}
|