@appiq/flutter-workflow 1.2.0 โ 1.3.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.
- package/CHANGELOG.md +74 -0
- package/agents/claude/data-agent.md +21 -11
- package/agents/claude/initial-flow-agent.md +55 -0
- package/agents/data-agent.md +20 -13
- package/agents/initial-flow-agent.md +342 -0
- package/bin/cli.js +54 -1
- package/package.json +2 -2
- package/templates/additional_cubit_req.md +357 -0
- package/templates/additional_data_req.md +480 -0
- package/templates/additional_domain_req.md +431 -0
- package/templates/additional_ui_req.md +205 -0
package/bin/cli.js
CHANGED
@@ -54,7 +54,8 @@ const AGENTS = [
|
|
54
54
|
'domain-agent',
|
55
55
|
'data-agent',
|
56
56
|
'security-agent',
|
57
|
-
'test-agent'
|
57
|
+
'test-agent',
|
58
|
+
'initial-flow-agent'
|
58
59
|
];
|
59
60
|
|
60
61
|
program
|
@@ -144,6 +145,27 @@ program
|
|
144
145
|
const featuresDir = path.join(docsDir, 'features');
|
145
146
|
await fs.ensureDir(featuresDir);
|
146
147
|
|
148
|
+
// Copy additional requirement templates
|
149
|
+
const templatesDir = path.join(__dirname, '../templates');
|
150
|
+
const targetTemplatesDir = path.join(currentDir, 'docs', 'additional_requirements');
|
151
|
+
await fs.ensureDir(targetTemplatesDir);
|
152
|
+
|
153
|
+
const additionalTemplates = [
|
154
|
+
'additional_ui_req.md',
|
155
|
+
'additional_cubit_req.md',
|
156
|
+
'additional_domain_req.md',
|
157
|
+
'additional_data_req.md'
|
158
|
+
];
|
159
|
+
|
160
|
+
for (const template of additionalTemplates) {
|
161
|
+
const sourceTemplate = path.join(templatesDir, template);
|
162
|
+
const targetTemplate = path.join(targetTemplatesDir, template);
|
163
|
+
|
164
|
+
if (await fs.pathExists(sourceTemplate)) {
|
165
|
+
await fs.copy(sourceTemplate, targetTemplate);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
147
169
|
// Create sample feature documentation
|
148
170
|
const sampleFeatureContent = `---
|
149
171
|
name: SampleFeature
|
@@ -152,6 +174,7 @@ domain: open
|
|
152
174
|
data: open
|
153
175
|
security: open
|
154
176
|
test: open
|
177
|
+
initial_flow: open
|
155
178
|
status: open
|
156
179
|
---
|
157
180
|
|
@@ -168,6 +191,20 @@ Describe your feature here. This will be analyzed by the PO Agent to create deta
|
|
168
191
|
- Any technical considerations
|
169
192
|
- Dependencies
|
170
193
|
- Performance requirements
|
194
|
+
|
195
|
+
## Additional Requirements
|
196
|
+
After basic implementation, you can use additional requirement templates:
|
197
|
+
- docs/additional_requirements/additional_ui_req.md - Role-based UI and access control
|
198
|
+
- docs/additional_requirements/additional_cubit_req.md - Advanced state management and provider setup
|
199
|
+
- docs/additional_requirements/additional_domain_req.md - Complex business rules and domain logic
|
200
|
+
- docs/additional_requirements/additional_data_req.md - Supabase MCP integration and advanced data patterns
|
201
|
+
|
202
|
+
## Integration Setup
|
203
|
+
Use the Initial Flow Agent for:
|
204
|
+
- Dependency injection configuration
|
205
|
+
- Provider setup and initialization
|
206
|
+
- Integration testing and validation
|
207
|
+
- Error prevention and troubleshooting
|
171
208
|
`;
|
172
209
|
|
173
210
|
await fs.writeFile(
|
@@ -189,6 +226,7 @@ Describe your feature here. This will be analyzed by the PO Agent to create deta
|
|
189
226
|
|
190
227
|
console.log(chalk.gray('\\n๐ Created directories:'));
|
191
228
|
console.log(chalk.gray(' ๐ docs/features/ - Feature documentation and status tracking'));
|
229
|
+
console.log(chalk.gray(' ๐ docs/additional_requirements/ - Advanced requirement templates'));
|
192
230
|
|
193
231
|
console.log(chalk.bold.yellow('\\n๐ Next Steps:'));
|
194
232
|
console.log(chalk.gray('1. Create your feature documentation in docs/features/'));
|
@@ -204,6 +242,7 @@ Describe your feature here. This will be analyzed by the PO Agent to create deta
|
|
204
242
|
console.log(chalk.gray(' ๐๏ธ Data Agent - Backend integration specialist'));
|
205
243
|
console.log(chalk.gray(' ๐ Security Agent - Security and compliance expert'));
|
206
244
|
console.log(chalk.gray(' ๐งช Test Agent - Testing pyramid implementation'));
|
245
|
+
console.log(chalk.gray(' ๐ Initial Flow Agent - Provider setup and integration specialist'));
|
207
246
|
|
208
247
|
} catch (error) {
|
209
248
|
console.error(chalk.red('โ Installation failed:'), error.message);
|
@@ -292,6 +331,7 @@ domain: open
|
|
292
331
|
data: open
|
293
332
|
security: open
|
294
333
|
test: open
|
334
|
+
initial_flow: open
|
295
335
|
status: open
|
296
336
|
---
|
297
337
|
|
@@ -322,6 +362,19 @@ As a [user type], I want [functionality] so that [benefit].
|
|
322
362
|
- UI/UX requirements
|
323
363
|
- Screen designs
|
324
364
|
- User flow
|
365
|
+
|
366
|
+
## Additional Requirements (Optional)
|
367
|
+
Use these templates after basic implementation for advanced features:
|
368
|
+
- docs/additional_requirements/additional_ui_req.md - Role-based access control
|
369
|
+
- docs/additional_requirements/additional_cubit_req.md - Advanced state management
|
370
|
+
- docs/additional_requirements/additional_domain_req.md - Complex business logic
|
371
|
+
- docs/additional_requirements/additional_data_req.md - Supabase MCP integration
|
372
|
+
|
373
|
+
## Integration Setup
|
374
|
+
After implementation, use Initial Flow Agent for:
|
375
|
+
- Complete dependency injection setup
|
376
|
+
- Provider hierarchy configuration
|
377
|
+
- Integration testing and validation
|
325
378
|
`;
|
326
379
|
|
327
380
|
const fileName = name.toLowerCase().replace(/[^a-z0-9]/gi, '-');
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@appiq/flutter-workflow",
|
3
|
-
"version": "1.
|
4
|
-
"description": "๐ Professional Flutter development with AI-powered agents following Clean Architecture principles - Automated agent-based feature development system by AppIQ Solutions",
|
3
|
+
"version": "1.3.0",
|
4
|
+
"description": "๐ [BETA] Professional Flutter development with AI-powered agents following Clean Architecture principles - Automated agent-based feature development system by AppIQ Solutions",
|
5
5
|
"main": "bin/cli.js",
|
6
6
|
"bin": {
|
7
7
|
"appiq-workflow": "bin/cli.js"
|
@@ -0,0 +1,357 @@
|
|
1
|
+
# Additional Cubit Requirements - State Management Integration
|
2
|
+
|
3
|
+
This template defines additional state management requirements, provider setup, and integration patterns for your feature.
|
4
|
+
|
5
|
+
## State Management Architecture
|
6
|
+
|
7
|
+
### Cubit Integration Pattern
|
8
|
+
```dart
|
9
|
+
// Feature-specific state management structure
|
10
|
+
lib/features/{feature}/presentation/cubit/
|
11
|
+
โโโ {feature}_cubit.dart // Main cubit implementation
|
12
|
+
โโโ {feature}_state.dart // State definitions
|
13
|
+
โโโ {feature}_event.dart // Events (if using BLoC pattern)
|
14
|
+
```
|
15
|
+
|
16
|
+
### Global State Dependencies
|
17
|
+
- [ ] Authentication state integration
|
18
|
+
- [ ] User role state management
|
19
|
+
- [ ] Theme/settings state access
|
20
|
+
- [ ] Navigation state coordination
|
21
|
+
- [ ] Network connectivity state
|
22
|
+
- [ ] Offline/online state management
|
23
|
+
|
24
|
+
## Provider Setup Requirements
|
25
|
+
|
26
|
+
### Main App Provider Configuration
|
27
|
+
```dart
|
28
|
+
// Add to main.dart MultiBlocProvider
|
29
|
+
MultiBlocProvider(
|
30
|
+
providers: [
|
31
|
+
// Existing providers...
|
32
|
+
BlocProvider<{Feature}Cubit>(
|
33
|
+
create: (context) => GetIt.instance<{Feature}Cubit>(),
|
34
|
+
),
|
35
|
+
// Additional feature dependencies...
|
36
|
+
],
|
37
|
+
child: MyApp(),
|
38
|
+
)
|
39
|
+
```
|
40
|
+
|
41
|
+
### Dependency Injection Setup
|
42
|
+
```dart
|
43
|
+
// Add to dependency injection configuration
|
44
|
+
void configureDependencies() {
|
45
|
+
// Repository registration
|
46
|
+
getIt.registerLazySingleton<{Feature}Repository>(
|
47
|
+
() => {Feature}RepositoryImpl(
|
48
|
+
remoteDataSource: getIt(),
|
49
|
+
localDataSource: getIt(),
|
50
|
+
networkInfo: getIt(),
|
51
|
+
),
|
52
|
+
);
|
53
|
+
|
54
|
+
// Use case registration
|
55
|
+
getIt.registerLazySingleton(() => Get{Feature}UseCase(getIt()));
|
56
|
+
getIt.registerLazySingleton(() => Create{Feature}UseCase(getIt()));
|
57
|
+
getIt.registerLazySingleton(() => Update{Feature}UseCase(getIt()));
|
58
|
+
getIt.registerLazySingleton(() => Delete{Feature}UseCase(getIt()));
|
59
|
+
|
60
|
+
// Cubit registration
|
61
|
+
getIt.registerFactory<{Feature}Cubit>(
|
62
|
+
() => {Feature}Cubit(
|
63
|
+
get{Feature}UseCase: getIt(),
|
64
|
+
create{Feature}UseCase: getIt(),
|
65
|
+
update{Feature}UseCase: getIt(),
|
66
|
+
delete{Feature}UseCase: getIt(),
|
67
|
+
),
|
68
|
+
);
|
69
|
+
}
|
70
|
+
```
|
71
|
+
|
72
|
+
## State Initialization Requirements
|
73
|
+
|
74
|
+
### Initial State Setup
|
75
|
+
```dart
|
76
|
+
class {Feature}Cubit extends Cubit<{Feature}State> {
|
77
|
+
{Feature}Cubit({
|
78
|
+
required this.get{Feature}UseCase,
|
79
|
+
required this.create{Feature}UseCase,
|
80
|
+
required this.update{Feature}UseCase,
|
81
|
+
required this.delete{Feature}UseCase,
|
82
|
+
}) : super(const {Feature}State.initial());
|
83
|
+
|
84
|
+
// Initialize feature data on cubit creation
|
85
|
+
Future<void> initialize() async {
|
86
|
+
emit(state.copyWith(status: {Feature}Status.loading));
|
87
|
+
|
88
|
+
try {
|
89
|
+
final result = await get{Feature}UseCase.call(NoParams());
|
90
|
+
result.fold(
|
91
|
+
(failure) => emit(state.copyWith(
|
92
|
+
status: {Feature}Status.error,
|
93
|
+
errorMessage: failure.message,
|
94
|
+
)),
|
95
|
+
(data) => emit(state.copyWith(
|
96
|
+
status: {Feature}Status.loaded,
|
97
|
+
items: data,
|
98
|
+
)),
|
99
|
+
);
|
100
|
+
} catch (e) {
|
101
|
+
emit(state.copyWith(
|
102
|
+
status: {Feature}Status.error,
|
103
|
+
errorMessage: 'Unexpected error occurred',
|
104
|
+
));
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
```
|
109
|
+
|
110
|
+
### Widget Integration Pattern
|
111
|
+
```dart
|
112
|
+
class {Feature}Page extends StatefulWidget {
|
113
|
+
@override
|
114
|
+
_State createState() => _State();
|
115
|
+
}
|
116
|
+
|
117
|
+
class _State extends State<{Feature}Page> {
|
118
|
+
late {Feature}Cubit cubit;
|
119
|
+
|
120
|
+
@override
|
121
|
+
void initState() {
|
122
|
+
super.initState();
|
123
|
+
cubit = context.read<{Feature}Cubit>();
|
124
|
+
// Initialize cubit data
|
125
|
+
cubit.initialize();
|
126
|
+
}
|
127
|
+
|
128
|
+
@override
|
129
|
+
Widget build(BuildContext context) {
|
130
|
+
return BlocConsumer<{Feature}Cubit, {Feature}State>(
|
131
|
+
listener: (context, state) {
|
132
|
+
// Handle side effects (navigation, snackbars, etc.)
|
133
|
+
if (state.status == {Feature}Status.error) {
|
134
|
+
ScaffoldMessenger.of(context).showSnackBar(
|
135
|
+
SnackBar(content: Text(state.errorMessage ?? 'Error occurred')),
|
136
|
+
);
|
137
|
+
}
|
138
|
+
},
|
139
|
+
builder: (context, state) {
|
140
|
+
return Scaffold(
|
141
|
+
body: _buildBody(state),
|
142
|
+
);
|
143
|
+
},
|
144
|
+
);
|
145
|
+
}
|
146
|
+
}
|
147
|
+
```
|
148
|
+
|
149
|
+
## Common Integration Issues & Solutions
|
150
|
+
|
151
|
+
### Issue 1: Cubit Not Initialized
|
152
|
+
**Problem**: `BlocProvider.of() called with a context that does not contain a Cubit`
|
153
|
+
**Solution**:
|
154
|
+
```dart
|
155
|
+
// Ensure proper provider hierarchy
|
156
|
+
MaterialApp(
|
157
|
+
home: MultiBlocProvider(
|
158
|
+
providers: [
|
159
|
+
BlocProvider<{Feature}Cubit>(
|
160
|
+
create: (context) => GetIt.instance<{Feature}Cubit>(),
|
161
|
+
),
|
162
|
+
],
|
163
|
+
child: {Feature}Page(),
|
164
|
+
),
|
165
|
+
)
|
166
|
+
```
|
167
|
+
|
168
|
+
### Issue 2: Duplicate Cubit Registration
|
169
|
+
**Problem**: Multiple registrations of the same cubit type
|
170
|
+
**Solution**:
|
171
|
+
```dart
|
172
|
+
// Use registerFactory for cubits (new instance per request)
|
173
|
+
getIt.registerFactory<{Feature}Cubit>(() => {Feature}Cubit(...));
|
174
|
+
|
175
|
+
// Or check if already registered
|
176
|
+
if (!getIt.isRegistered<{Feature}Cubit>()) {
|
177
|
+
getIt.registerFactory<{Feature}Cubit>(() => {Feature}Cubit(...));
|
178
|
+
}
|
179
|
+
```
|
180
|
+
|
181
|
+
### Issue 3: State Not Persisting Across Navigation
|
182
|
+
**Problem**: State resets when navigating between screens
|
183
|
+
**Solution**:
|
184
|
+
```dart
|
185
|
+
// Use singleton registration for state that should persist
|
186
|
+
getIt.registerLazySingleton<{Feature}Cubit>(() => {Feature}Cubit(...));
|
187
|
+
|
188
|
+
// Or use global provider at app level
|
189
|
+
class MyApp extends StatelessWidget {
|
190
|
+
@override
|
191
|
+
Widget build(BuildContext context) {
|
192
|
+
return MultiBlocProvider(
|
193
|
+
providers: [
|
194
|
+
BlocProvider<{Feature}Cubit>(
|
195
|
+
create: (context) => GetIt.instance<{Feature}Cubit>(),
|
196
|
+
),
|
197
|
+
],
|
198
|
+
child: MaterialApp(...),
|
199
|
+
);
|
200
|
+
}
|
201
|
+
}
|
202
|
+
```
|
203
|
+
|
204
|
+
## Cross-Feature State Communication
|
205
|
+
|
206
|
+
### Feature-to-Feature State Updates
|
207
|
+
```dart
|
208
|
+
class {Feature}Cubit extends Cubit<{Feature}State> {
|
209
|
+
final AuthenticationCubit authCubit;
|
210
|
+
final UserRoleCubit userRoleCubit;
|
211
|
+
late StreamSubscription authSubscription;
|
212
|
+
|
213
|
+
{Feature}Cubit({
|
214
|
+
required this.authCubit,
|
215
|
+
required this.userRoleCubit,
|
216
|
+
// ... other dependencies
|
217
|
+
}) : super(const {Feature}State.initial()) {
|
218
|
+
// Listen to authentication changes
|
219
|
+
authSubscription = authCubit.stream.listen((authState) {
|
220
|
+
if (authState is! AuthenticatedState) {
|
221
|
+
// Clear feature data on logout
|
222
|
+
emit(const {Feature}State.initial());
|
223
|
+
}
|
224
|
+
});
|
225
|
+
}
|
226
|
+
|
227
|
+
@override
|
228
|
+
Future<void> close() {
|
229
|
+
authSubscription.cancel();
|
230
|
+
return super.close();
|
231
|
+
}
|
232
|
+
}
|
233
|
+
```
|
234
|
+
|
235
|
+
### Global State Access Pattern
|
236
|
+
```dart
|
237
|
+
// Access other cubits from within a cubit
|
238
|
+
void updateBasedOnUserRole() {
|
239
|
+
final userRole = userRoleCubit.state.role;
|
240
|
+
|
241
|
+
switch (userRole) {
|
242
|
+
case UserRole.admin:
|
243
|
+
loadAdminData();
|
244
|
+
break;
|
245
|
+
case UserRole.manager:
|
246
|
+
loadManagerData();
|
247
|
+
break;
|
248
|
+
case UserRole.user:
|
249
|
+
loadUserData();
|
250
|
+
break;
|
251
|
+
}
|
252
|
+
}
|
253
|
+
```
|
254
|
+
|
255
|
+
## Performance Optimization
|
256
|
+
|
257
|
+
### Selective State Updates
|
258
|
+
```dart
|
259
|
+
// Use copyWith efficiently to avoid unnecessary rebuilds
|
260
|
+
emit(state.copyWith(
|
261
|
+
status: {Feature}Status.loading,
|
262
|
+
// Only update changed fields
|
263
|
+
));
|
264
|
+
|
265
|
+
// Use state comparison to prevent duplicate emissions
|
266
|
+
void updateItems(List<{Entity}> newItems) {
|
267
|
+
if (!listEquals(state.items, newItems)) {
|
268
|
+
emit(state.copyWith(items: newItems));
|
269
|
+
}
|
270
|
+
}
|
271
|
+
```
|
272
|
+
|
273
|
+
### Memory Management
|
274
|
+
```dart
|
275
|
+
class {Feature}Cubit extends Cubit<{Feature}State> {
|
276
|
+
final List<StreamSubscription> _subscriptions = [];
|
277
|
+
|
278
|
+
void addSubscription(StreamSubscription subscription) {
|
279
|
+
_subscriptions.add(subscription);
|
280
|
+
}
|
281
|
+
|
282
|
+
@override
|
283
|
+
Future<void> close() {
|
284
|
+
// Cancel all subscriptions
|
285
|
+
for (final subscription in _subscriptions) {
|
286
|
+
subscription.cancel();
|
287
|
+
}
|
288
|
+
_subscriptions.clear();
|
289
|
+
return super.close();
|
290
|
+
}
|
291
|
+
}
|
292
|
+
```
|
293
|
+
|
294
|
+
## Testing Integration
|
295
|
+
|
296
|
+
### Cubit Testing Setup
|
297
|
+
```dart
|
298
|
+
// Test setup with proper mocking
|
299
|
+
class MockAuthCubit extends MockCubit<AuthState> implements AuthCubit {}
|
300
|
+
class MockUserRoleCubit extends MockCubit<UserRoleState> implements UserRoleCubit {}
|
301
|
+
|
302
|
+
void main() {
|
303
|
+
late {Feature}Cubit cubit;
|
304
|
+
late MockAuthCubit mockAuthCubit;
|
305
|
+
late MockUserRoleCubit mockUserRoleCubit;
|
306
|
+
|
307
|
+
setUp(() {
|
308
|
+
mockAuthCubit = MockAuthCubit();
|
309
|
+
mockUserRoleCubit = MockUserRoleCubit();
|
310
|
+
|
311
|
+
cubit = {Feature}Cubit(
|
312
|
+
authCubit: mockAuthCubit,
|
313
|
+
userRoleCubit: mockUserRoleCubit,
|
314
|
+
// ... other dependencies
|
315
|
+
);
|
316
|
+
});
|
317
|
+
|
318
|
+
tearDown(() {
|
319
|
+
cubit.close();
|
320
|
+
});
|
321
|
+
}
|
322
|
+
```
|
323
|
+
|
324
|
+
## Integration Checklist
|
325
|
+
|
326
|
+
### Provider Setup
|
327
|
+
- [ ] Cubit registered in dependency injection
|
328
|
+
- [ ] Provider added to MultiBlocProvider
|
329
|
+
- [ ] Dependencies properly injected
|
330
|
+
- [ ] Initialization logic implemented
|
331
|
+
|
332
|
+
### State Management
|
333
|
+
- [ ] Initial state properly defined
|
334
|
+
- [ ] State transitions implemented
|
335
|
+
- [ ] Error handling added
|
336
|
+
- [ ] Loading states managed
|
337
|
+
|
338
|
+
### Cross-Feature Integration
|
339
|
+
- [ ] Authentication state integration
|
340
|
+
- [ ] User role state access
|
341
|
+
- [ ] Global state dependencies resolved
|
342
|
+
- [ ] Navigation state coordination
|
343
|
+
|
344
|
+
### Performance & Memory
|
345
|
+
- [ ] Efficient state updates implemented
|
346
|
+
- [ ] Memory leaks prevented (subscriptions canceled)
|
347
|
+
- [ ] Unnecessary rebuilds minimized
|
348
|
+
- [ ] State persistence strategy defined
|
349
|
+
|
350
|
+
### Testing
|
351
|
+
- [ ] Unit tests for cubit logic
|
352
|
+
- [ ] Integration tests with providers
|
353
|
+
- [ ] Mock implementations for dependencies
|
354
|
+
- [ ] Error scenario testing
|
355
|
+
|
356
|
+
## Notes
|
357
|
+
Add any feature-specific state management requirements, custom integration patterns, or special initialization needs.
|