ai-flow-dev 2.7.0 → 2.8.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.
Files changed (171) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +573 -570
  3. package/package.json +74 -74
  4. package/prompts/backend/flow-build-phase-0.md +535 -535
  5. package/prompts/backend/flow-build-phase-1.md +626 -626
  6. package/prompts/backend/flow-build-phase-10.md +340 -340
  7. package/prompts/backend/flow-build-phase-2.md +573 -573
  8. package/prompts/backend/flow-build-phase-3.md +834 -834
  9. package/prompts/backend/flow-build-phase-4.md +554 -554
  10. package/prompts/backend/flow-build-phase-5.md +703 -703
  11. package/prompts/backend/flow-build-phase-6.md +524 -524
  12. package/prompts/backend/flow-build-phase-7.md +1001 -1001
  13. package/prompts/backend/flow-build-phase-8.md +1407 -1407
  14. package/prompts/backend/flow-build-phase-9.md +477 -477
  15. package/prompts/backend/flow-build.md +137 -137
  16. package/prompts/backend/flow-check-review.md +656 -20
  17. package/prompts/backend/flow-check-test.md +526 -14
  18. package/prompts/backend/flow-check.md +717 -67
  19. package/prompts/backend/flow-commit.md +88 -119
  20. package/prompts/backend/flow-docs-sync.md +354 -354
  21. package/prompts/backend/flow-finish.md +919 -0
  22. package/prompts/backend/flow-release.md +949 -0
  23. package/prompts/backend/flow-work-feature.md +61 -61
  24. package/prompts/backend/flow-work-fix.md +46 -46
  25. package/prompts/backend/flow-work-refactor.md +48 -48
  26. package/prompts/backend/flow-work-resume.md +34 -34
  27. package/prompts/backend/flow-work.md +1098 -1286
  28. package/prompts/desktop/flow-build-phase-0.md +359 -359
  29. package/prompts/desktop/flow-build-phase-1.md +295 -295
  30. package/prompts/desktop/flow-build-phase-10.md +357 -357
  31. package/prompts/desktop/flow-build-phase-2.md +282 -282
  32. package/prompts/desktop/flow-build-phase-3.md +291 -291
  33. package/prompts/desktop/flow-build-phase-4.md +308 -308
  34. package/prompts/desktop/flow-build-phase-5.md +269 -269
  35. package/prompts/desktop/flow-build-phase-6.md +350 -350
  36. package/prompts/desktop/flow-build-phase-7.md +297 -297
  37. package/prompts/desktop/flow-build-phase-8.md +541 -541
  38. package/prompts/desktop/flow-build-phase-9.md +439 -439
  39. package/prompts/desktop/flow-build.md +156 -156
  40. package/prompts/desktop/flow-check-review.md +656 -20
  41. package/prompts/desktop/flow-check-test.md +526 -14
  42. package/prompts/desktop/flow-check.md +717 -67
  43. package/prompts/desktop/flow-commit.md +88 -119
  44. package/prompts/desktop/flow-docs-sync.md +354 -354
  45. package/prompts/desktop/flow-finish.md +919 -0
  46. package/prompts/desktop/flow-release.md +662 -0
  47. package/prompts/desktop/flow-work-feature.md +61 -61
  48. package/prompts/desktop/flow-work-fix.md +46 -46
  49. package/prompts/desktop/flow-work-refactor.md +48 -48
  50. package/prompts/desktop/flow-work-resume.md +34 -34
  51. package/prompts/desktop/flow-work.md +1202 -1390
  52. package/prompts/frontend/flow-build-phase-0.md +425 -425
  53. package/prompts/frontend/flow-build-phase-1.md +626 -626
  54. package/prompts/frontend/flow-build-phase-10.md +33 -33
  55. package/prompts/frontend/flow-build-phase-2.md +573 -573
  56. package/prompts/frontend/flow-build-phase-3.md +782 -782
  57. package/prompts/frontend/flow-build-phase-4.md +554 -554
  58. package/prompts/frontend/flow-build-phase-5.md +703 -703
  59. package/prompts/frontend/flow-build-phase-6.md +524 -524
  60. package/prompts/frontend/flow-build-phase-7.md +1001 -1001
  61. package/prompts/frontend/flow-build-phase-8.md +872 -872
  62. package/prompts/frontend/flow-build-phase-9.md +94 -94
  63. package/prompts/frontend/flow-build.md +137 -137
  64. package/prompts/frontend/flow-check-review.md +656 -20
  65. package/prompts/frontend/flow-check-test.md +526 -14
  66. package/prompts/frontend/flow-check.md +717 -67
  67. package/prompts/frontend/flow-commit.md +88 -119
  68. package/prompts/frontend/flow-docs-sync.md +550 -550
  69. package/prompts/frontend/flow-finish.md +919 -0
  70. package/prompts/frontend/flow-release.md +519 -0
  71. package/prompts/frontend/flow-work-api.md +1547 -0
  72. package/prompts/frontend/flow-work-feature.md +61 -61
  73. package/prompts/frontend/flow-work-fix.md +38 -38
  74. package/prompts/frontend/flow-work-refactor.md +48 -48
  75. package/prompts/frontend/flow-work-resume.md +34 -34
  76. package/prompts/frontend/flow-work.md +1595 -1320
  77. package/prompts/mobile/flow-build-phase-0.md +425 -425
  78. package/prompts/mobile/flow-build-phase-1.md +626 -626
  79. package/prompts/mobile/flow-build-phase-10.md +32 -32
  80. package/prompts/mobile/flow-build-phase-2.md +573 -573
  81. package/prompts/mobile/flow-build-phase-3.md +782 -782
  82. package/prompts/mobile/flow-build-phase-4.md +554 -554
  83. package/prompts/mobile/flow-build-phase-5.md +703 -703
  84. package/prompts/mobile/flow-build-phase-6.md +524 -524
  85. package/prompts/mobile/flow-build-phase-7.md +1001 -1001
  86. package/prompts/mobile/flow-build-phase-8.md +888 -888
  87. package/prompts/mobile/flow-build-phase-9.md +90 -90
  88. package/prompts/mobile/flow-build.md +135 -135
  89. package/prompts/mobile/flow-check-review.md +656 -20
  90. package/prompts/mobile/flow-check-test.md +526 -14
  91. package/prompts/mobile/flow-check.md +717 -67
  92. package/prompts/mobile/flow-commit.md +88 -119
  93. package/prompts/mobile/flow-docs-sync.md +620 -620
  94. package/prompts/mobile/flow-finish.md +919 -0
  95. package/prompts/mobile/flow-release.md +751 -0
  96. package/prompts/mobile/flow-work-api.md +1500 -0
  97. package/prompts/mobile/flow-work-feature.md +61 -61
  98. package/prompts/mobile/flow-work-fix.md +46 -46
  99. package/prompts/mobile/flow-work-refactor.md +48 -48
  100. package/prompts/mobile/flow-work-resume.md +34 -34
  101. package/prompts/mobile/flow-work.md +1605 -1329
  102. package/prompts/shared/mermaid-guidelines.md +102 -102
  103. package/prompts/shared/scope-levels.md +114 -114
  104. package/prompts/shared/smart-skip-preflight.md +214 -214
  105. package/prompts/shared/story-points.md +55 -55
  106. package/prompts/shared/task-format.md +74 -74
  107. package/prompts/shared/task-summary-template.md +277 -277
  108. package/templates/AGENT.template.md +443 -443
  109. package/templates/backend/.clauderules.template +112 -112
  110. package/templates/backend/.cursorrules.template +102 -102
  111. package/templates/backend/README.template.md +2 -2
  112. package/templates/backend/ai-instructions.template.md +2 -2
  113. package/templates/backend/copilot-instructions.template.md +2 -2
  114. package/templates/backend/docs/api.template.md +320 -320
  115. package/templates/backend/docs/business-flows.template.md +97 -97
  116. package/templates/backend/docs/code-standards.template.md +2 -2
  117. package/templates/backend/docs/contributing.template.md +3 -3
  118. package/templates/backend/docs/data-model.template.md +520 -520
  119. package/templates/backend/docs/testing.template.md +2 -2
  120. package/templates/backend/project-brief.template.md +2 -2
  121. package/templates/backend/specs/configuration.template.md +2 -2
  122. package/templates/backend/specs/security.template.md +2 -2
  123. package/templates/desktop/.clauderules.template +112 -112
  124. package/templates/desktop/.cursorrules.template +102 -102
  125. package/templates/desktop/README.template.md +170 -170
  126. package/templates/desktop/ai-instructions.template.md +366 -366
  127. package/templates/desktop/copilot-instructions.template.md +140 -140
  128. package/templates/desktop/docs/docs/api.template.md +320 -320
  129. package/templates/desktop/docs/docs/architecture.template.md +724 -724
  130. package/templates/desktop/docs/docs/business-flows.template.md +102 -102
  131. package/templates/desktop/docs/docs/code-standards.template.md +792 -792
  132. package/templates/desktop/docs/docs/contributing.template.md +149 -149
  133. package/templates/desktop/docs/docs/data-model.template.md +520 -520
  134. package/templates/desktop/docs/docs/operations.template.md +720 -720
  135. package/templates/desktop/docs/docs/testing.template.md +722 -722
  136. package/templates/desktop/project-brief.template.md +150 -150
  137. package/templates/desktop/specs/specs/configuration.template.md +121 -121
  138. package/templates/desktop/specs/specs/security.template.md +392 -392
  139. package/templates/frontend/README.template.md +2 -2
  140. package/templates/frontend/ai-instructions.template.md +2 -2
  141. package/templates/frontend/docs/api-integration.template.md +362 -362
  142. package/templates/frontend/docs/components.template.md +2 -2
  143. package/templates/frontend/docs/error-handling.template.md +360 -360
  144. package/templates/frontend/docs/operations.template.md +107 -107
  145. package/templates/frontend/docs/performance.template.md +124 -124
  146. package/templates/frontend/docs/pwa.template.md +119 -119
  147. package/templates/frontend/docs/state-management.template.md +2 -2
  148. package/templates/frontend/docs/styling.template.md +2 -2
  149. package/templates/frontend/docs/testing.template.md +2 -2
  150. package/templates/frontend/project-brief.template.md +2 -2
  151. package/templates/frontend/specs/accessibility.template.md +95 -95
  152. package/templates/frontend/specs/configuration.template.md +2 -2
  153. package/templates/frontend/specs/security.template.md +175 -175
  154. package/templates/fullstack/README.template.md +252 -252
  155. package/templates/fullstack/ai-instructions.template.md +444 -444
  156. package/templates/fullstack/project-brief.template.md +157 -157
  157. package/templates/fullstack/specs/configuration.template.md +340 -340
  158. package/templates/mobile/README.template.md +167 -167
  159. package/templates/mobile/ai-instructions.template.md +196 -196
  160. package/templates/mobile/docs/app-store.template.md +135 -135
  161. package/templates/mobile/docs/architecture.template.md +63 -63
  162. package/templates/mobile/docs/native-features.template.md +94 -94
  163. package/templates/mobile/docs/navigation.template.md +59 -59
  164. package/templates/mobile/docs/offline-strategy.template.md +65 -65
  165. package/templates/mobile/docs/permissions.template.md +56 -56
  166. package/templates/mobile/docs/state-management.template.md +85 -85
  167. package/templates/mobile/docs/testing.template.md +109 -109
  168. package/templates/mobile/project-brief.template.md +69 -69
  169. package/templates/mobile/specs/build-configuration.template.md +91 -91
  170. package/templates/mobile/specs/deployment.template.md +92 -92
  171. package/templates/work.template.md +61 -47
@@ -0,0 +1,1500 @@
1
+ ---
2
+ description: Analyze OpenAPI specification to extract complete module metadata for mobile CRUD generation (React Native)
3
+ ---
4
+
5
+ # API Module Analyzer (Sub-Prompt - Mobile)
6
+
7
+ **YOU ARE AN EXPERT API ANALYZER specialized in extracting comprehensive metadata from OpenAPI specifications for React Native mobile code generation.**
8
+
9
+ ## ⚠️ IMPORTANT: Internal Sub-Prompt
10
+
11
+ **DO NOT invoke this prompt directly.** This is an internal sub-prompt called by `/flow-work`.
12
+
13
+ **To use API Module Analysis (mobile), run:**
14
+
15
+ ```bash
16
+ /flow-work api <module-name>
17
+ # Example: /flow-work api users
18
+ ```
19
+
20
+ **Why not call directly?**
21
+
22
+ - `/flow-work` manages URL cache (`.ai-flow/cache/api-config.json`)
23
+ - `/flow-work` handles connection errors with interactive retry
24
+ - `/flow-work` validates URL before analysis
25
+ - This sub-prompt expects a **pre-validated URL** as input
26
+
27
+ **Architecture:**
28
+
29
+ - `flow-work` = Orchestrator (stateful, manages cache)
30
+ - `flow-work-api` = Analyzer (stateless, pure function)
31
+
32
+ ---
33
+
34
+ ## Invocation Context
35
+
36
+ This sub-prompt is automatically invoked by `/flow-work` when the pattern `api [module-name]` is detected.
37
+
38
+ ## Purpose
39
+
40
+ Parse OpenAPI backend specification and return structured analysis data that `flow-work` will use to:
41
+
42
+ 1. Generate detailed `work.md` with field specifications
43
+ 2. Execute CRUD implementation with mobile-specific patterns (React Native)
44
+ 3. Ensure type-safety between mobile app and backend
45
+
46
+ **⚠️ CRITICAL: Do NOT create separate analysis files**
47
+
48
+ - This sub-prompt ONLY returns a JSON object (`OpenAPIAnalysisResult`)
49
+ - NO files like `.ai-flow/analysis/*.md` or `.ai-flow/work/[task]/analysis.md` should be created
50
+ - The parent prompt (`flow-work`) handles all file creation (only `work.md` and `status.json`)
51
+ - All analysis data is stored in memory and used to populate `work.md`
52
+
53
+ ---
54
+
55
+ ## Input Parameters
56
+
57
+ Received from parent prompt (flow-work):
58
+
59
+ ```typescript
60
+ interface ApiModuleInput {
61
+ module: string; // 'users', 'organizations', 'audit-logs'
62
+ apiUrl?: string; // Override default OpenAPI endpoint
63
+ }
64
+ ```
65
+
66
+ **Default API URL**: `http://localhost:3001/api/docs-json`
67
+ **Override**: User can specify `--api-url=http://other-host:3000/api/docs`
68
+
69
+ ---
70
+
71
+ ## Phase 0: API Analysis (Automatic)
72
+
73
+ ### 0.1. Fetch OpenAPI Specification (Robust)
74
+
75
+ **CRITICAL: Handle connection errors, timeouts, and network issues.**
76
+
77
+ ```typescript
78
+ async function fetchOpenAPISpec(url: string): Promise<OpenAPISpec> {
79
+ try {
80
+ const controller = new AbortController();
81
+ const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s timeout
82
+
83
+ const response = await fetch(url, {
84
+ signal: controller.signal,
85
+ headers: { Accept: 'application/json' },
86
+ });
87
+
88
+ clearTimeout(timeoutId);
89
+
90
+ if (!response.ok) {
91
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
92
+ }
93
+
94
+ const spec = await response.json();
95
+
96
+ // Validate OpenAPI version
97
+ if (!spec.openapi && !spec.swagger) {
98
+ throw new Error('Invalid OpenAPI/Swagger specification');
99
+ }
100
+
101
+ return spec;
102
+ } catch (error) {
103
+ if (error.name === 'AbortError') {
104
+ throw new Error('API documentation server timeout. Ensure backend is running.');
105
+ }
106
+
107
+ if (error.message.includes('Network request failed')) {
108
+ throw new Error('Network error. Check device connectivity or backend URL.');
109
+ }
110
+
111
+ throw error;
112
+ }
113
+ }
114
+ ```
115
+
116
+ **IF fetch fails:**
117
+
118
+ ```
119
+ ❌ Failed to fetch OpenAPI spec from http://localhost:3001/api/docs-json
120
+
121
+ Error: API documentation server timeout. Ensure backend is running.
122
+
123
+ Options:
124
+ A) Retry with different URL
125
+ B) Use cached spec (if available)
126
+ C) Proceed with manual type definitions
127
+ D) Cancel
128
+
129
+ Your choice: _
130
+ ```
131
+
132
+ **IF successful, show spec version:**
133
+
134
+ ```
135
+ ✅ OpenAPI Specification Loaded
136
+
137
+ Version: OpenAPI 3.0.3
138
+ Title: CROSS Mobile API
139
+ Paths: 45 endpoints detected
140
+ Schemas: 32 types available
141
+
142
+ Proceeding with analysis...
143
+ ```
144
+
145
+ ### 0.2. Extract Module Endpoints (Filtered)
146
+
147
+ **CRITICAL: Extract ONLY the target module endpoints. Do NOT extract all API modules.**
148
+
149
+ Identify all endpoints for the specified module:
150
+
151
+ ```typescript
152
+ // Example for "users" module
153
+ const targetModule = 'users'; // From user input
154
+
155
+ const moduleEndpoints = filterEndpoints(spec.paths, {
156
+ tags: [capitalizeFirst(targetModule)], // ['Users']
157
+ pathPrefix: `/api/${targetModule}`, // '/api/users'
158
+ });
159
+
160
+ // Result:
161
+ {
162
+ list: 'GET /api/users',
163
+ create: 'POST /api/users',
164
+ get: 'GET /api/users/{id}',
165
+ update: 'PUT /api/users/{id}',
166
+ delete: 'DELETE /api/users/{id}',
167
+ // Additional endpoints:
168
+ getMe: 'GET /api/users/me',
169
+ updateMe: 'PUT /api/users/me',
170
+ changePassword: 'PUT /api/users/me/password',
171
+ }
172
+ ```
173
+
174
+ **⚠️ IMPORTANT**: Do NOT include endpoints from other modules like `/api/organizations`, `/api/audit-logs`, etc. Only the target module.
175
+
176
+ ### 0.3. Detect Pagination Response Format
177
+
178
+ **Analyze the response schema for list endpoints:**
179
+
180
+ ```typescript
181
+ function detectPaginationFormat(endpoint: OpenAPIEndpoint): PaginationFormat {
182
+ const responseSchema = endpoint.responses['200'].schema;
183
+
184
+ // Check if response is object with data/items property
185
+ if (responseSchema.type === 'object') {
186
+ if (responseSchema.properties?.items && responseSchema.properties?.total) {
187
+ return {
188
+ type: 'object',
189
+ dataKey: 'items',
190
+ totalKey: 'total',
191
+ pageKey: responseSchema.properties.page ? 'page' : null,
192
+ };
193
+ }
194
+
195
+ if (responseSchema.properties?.data && responseSchema.properties?.meta) {
196
+ return {
197
+ type: 'object',
198
+ dataKey: 'data',
199
+ totalKey: 'meta.total',
200
+ pageKey: 'meta.page',
201
+ };
202
+ }
203
+ }
204
+
205
+ // Response is array directly
206
+ if (responseSchema.type === 'array') {
207
+ return {
208
+ type: 'array',
209
+ dataKey: null,
210
+ totalKey: null, // Client-side pagination only
211
+ };
212
+ }
213
+
214
+ throw new Error('Unable to detect pagination format from OpenAPI schema');
215
+ }
216
+ ```
217
+
218
+ ### 0.4. Extract Complete Field Specifications (Detailed)
219
+
220
+ **For EACH endpoint, extract FULL field specifications:**
221
+
222
+ ```typescript
223
+ interface FieldSpec {
224
+ name: string;
225
+ type: 'string' | 'number' | 'boolean' | 'date' | 'enum' | 'array' | 'object';
226
+ required: boolean;
227
+ nullable: boolean;
228
+ validation?: {
229
+ min?: number;
230
+ max?: number;
231
+ pattern?: string;
232
+ format?: 'email' | 'url' | 'uuid' | 'date-time';
233
+ enum?: string[];
234
+ };
235
+ relation?: {
236
+ entity: string;
237
+ type: 'one-to-one' | 'many-to-one' | 'one-to-many' | 'many-to-many';
238
+ populated: boolean; // Si el backend devuelve el objeto completo
239
+ displayField: string; // Campo a mostrar (e.g., "name", "email")
240
+ };
241
+ default?: any;
242
+ description?: string;
243
+ }
244
+ ```
245
+
246
+ **Extract from OpenAPI schema:**
247
+
248
+ ```typescript
249
+ // Example extraction
250
+ const userSchema = spec.components.schemas.UserResponseDto;
251
+
252
+ const fields: FieldSpec[] = Object.entries(userSchema.properties).map(([name, prop]) => ({
253
+ name,
254
+ type: mapOpenAPIType(prop.type, prop.format),
255
+ required: userSchema.required?.includes(name) ?? false,
256
+ nullable: prop.nullable ?? false,
257
+ validation: extractValidation(prop),
258
+ relation: detectRelation(name, prop, spec),
259
+ default: prop.default,
260
+ description: prop.description,
261
+ }));
262
+
263
+ // Helper: Detect relations
264
+ function detectRelation(fieldName: string, prop: any, spec: OpenAPISpec) {
265
+ // Pattern 1: Field ends with "Id" → Foreign Key
266
+ if (fieldName.endsWith('Id') && prop.type === 'string') {
267
+ const entityName = fieldName.slice(0, -2); // "roleId" → "role"
268
+ return {
269
+ entity: entityName,
270
+ type: 'many-to-one',
271
+ populated: false,
272
+ displayField: 'name', // Default assumption
273
+ };
274
+ }
275
+
276
+ // Pattern 2: Field is object with $ref → Populated relation
277
+ if (prop.$ref) {
278
+ const refSchema = resolveRef(prop.$ref, spec);
279
+ return {
280
+ entity: extractEntityName(prop.$ref),
281
+ type: 'many-to-one',
282
+ populated: true,
283
+ displayField: detectDisplayField(refSchema), // Smart detection
284
+ };
285
+ }
286
+
287
+ // Pattern 3: Array of objects → One-to-many or Many-to-many
288
+ if (prop.type === 'array' && prop.items?.$ref) {
289
+ return {
290
+ entity: extractEntityName(prop.items.$ref),
291
+ type: 'one-to-many', // or 'many-to-many' based on naming
292
+ populated: true,
293
+ displayField: 'name',
294
+ };
295
+ }
296
+
297
+ return null;
298
+ }
299
+
300
+ // Helper: Detect which field to display (smart heuristic)
301
+ function detectDisplayField(schema: any): string {
302
+ const commonDisplayFields = ['name', 'title', 'label', 'email', 'username'];
303
+ for (const field of commonDisplayFields) {
304
+ if (schema.properties?.[field]) return field;
305
+ }
306
+ return 'id'; // Fallback
307
+ }
308
+ ```
309
+
310
+ ### 0.5. Categorize Fields by Usage
311
+
312
+ **Auto-categorize fields based on patterns:**
313
+
314
+ ```typescript
315
+ function categorizeField(field: FieldSpec, dto: 'response' | 'create' | 'update'): FieldCategory {
316
+ const autoGeneratedPatterns = ['id', 'createdAt', 'updatedAt', 'deletedAt', 'version'];
317
+ const readOnlyPatterns = ['lastLoginAt', 'emailVerifiedAt', '_count', 'computed'];
318
+ const metadataPatterns = ['metadata', 'config', 'settings'];
319
+
320
+ // Auto-generated (never editable)
321
+ if (autoGeneratedPatterns.includes(field.name)) {
322
+ return {
323
+ category: 'auto-generated',
324
+ showInList: field.name === 'id' ? false : true, // Mobile uses "List" not "Table"
325
+ showInForm: false,
326
+ showInDetails: true,
327
+ editable: false,
328
+ };
329
+ }
330
+
331
+ // Read-only (show but not editable)
332
+ if (readOnlyPatterns.some((p) => field.name.includes(p))) {
333
+ return {
334
+ category: 'read-only',
335
+ showInList: true,
336
+ showInForm: false,
337
+ showInDetails: true,
338
+ editable: false,
339
+ };
340
+ }
341
+
342
+ // Metadata (advanced users only)
343
+ if (metadataPatterns.includes(field.name)) {
344
+ return {
345
+ category: 'metadata',
346
+ showInList: false,
347
+ showInForm: false, // Or in advanced section
348
+ showInDetails: true,
349
+ editable: true,
350
+ };
351
+ }
352
+
353
+ // Editable (normal fields)
354
+ return {
355
+ category: 'editable',
356
+ showInList: true,
357
+ showInForm: dto === 'response' ? false : true,
358
+ showInDetails: true,
359
+ editable: dto === 'update' ? true : false,
360
+ };
361
+ }
362
+ ```
363
+
364
+ ### 0.6. Extract DTOs and Schemas
365
+
366
+ Analyze `components.schemas` to extract:
367
+
368
+ ```typescript
369
+ interface ModuleSchemas {
370
+ response: Schema; // UserResponseDto
371
+ create: Schema; // CreateUserDto
372
+ update: Schema; // UpdateUserDto
373
+ filters: QueryParams; // page, limit, search, etc.
374
+ }
375
+ ```
376
+
377
+ ### 0.7. Detect Features
378
+
379
+ Auto-detect capabilities:
380
+
381
+ ```yaml
382
+ Features_Detected:
383
+ pagination:
384
+ enabled: true/false
385
+ params: [page, limit]
386
+ response_format: "array" | "{ data, meta }"
387
+
388
+ search:
389
+ enabled: true/false
390
+ params: [search, filter_field_1, filter_field_2]
391
+
392
+ sorting:
393
+ enabled: true/false
394
+ params: [sortBy, order]
395
+
396
+ authentication:
397
+ type: bearer
398
+ required: true
399
+
400
+ authorization:
401
+ roles: [ROOT, OWNER, ADMIN]
402
+ permissions: ['user:read', 'user:write']
403
+
404
+ soft_delete:
405
+ enabled: true/false
406
+ status_field: "status" | "deletedAt"
407
+ ```
408
+
409
+ ### 0.8. Analyze Relationships (Smart Depth)
410
+
411
+ **Extract ONLY direct relationships (depth 1) to avoid analyzing unnecessary modules.**
412
+
413
+ Detect foreign keys and relations:
414
+
415
+ ```typescript
416
+ function extractRelevantRelationships(
417
+ targetModule: string,
418
+ spec: OpenAPISpec,
419
+ maxDepth: number = 1
420
+ ): Relationships[] {
421
+ const targetSchemas = getModuleSchemas(spec, targetModule);
422
+ const relationships: Relationships[] = [];
423
+
424
+ // Only analyze target module schemas
425
+ targetSchemas.forEach(schema => {
426
+ Object.entries(schema.properties).forEach(([fieldName, prop]) => {
427
+ // Detect foreign key (e.g., roleId)
428
+ if (fieldName.endsWith('Id') && prop.type === 'string') {
429
+ const relatedEntity = fieldName.slice(0, -2); // 'roleId' → 'role'
430
+
431
+ relationships.push({
432
+ field: fieldName,
433
+ relatedEntity: capitalizeFirst(relatedEntity),
434
+ type: 'many-to-one',
435
+ foreignKey: fieldName,
436
+ endpoint: `/api/${relatedEntity}s`, // Pluralize
437
+ displayField: 'name', // Default assumption
438
+ populated: false,
439
+ });
440
+ }
441
+
442
+ // Detect populated relation (e.g., role: { $ref: '#/components/schemas/Role' })
443
+ if (prop.$ref) {
444
+ const relatedEntity = extractEntityName(prop.$ref);
445
+
446
+ relationships.push({
447
+ field: fieldName,
448
+ relatedEntity,
449
+ type: 'many-to-one',
450
+ foreignKey: `${fieldName}Id`,
451
+ endpoint: `/api/${fieldName}s`,
452
+ displayField: detectDisplayField(resolveRef(prop.$ref, spec)),
453
+ populated: true,
454
+ });
455
+ }
456
+
457
+ // Detect array relations (e.g., organizations: [{ $ref: '...' }])
458
+ if (prop.type === 'array' && prop.items?.$ref) {
459
+ const relatedEntity = extractEntityName(prop.items.$ref);
460
+
461
+ relationships.push({
462
+ field: fieldName,
463
+ relatedEntity,
464
+ type: 'one-to-many', // or 'many-to-many'
465
+ foreignKey: `${targetModule}Id`,
466
+ endpoint: `/api/${fieldName}`,
467
+ displayField: 'name',
468
+ populated: true,
469
+ });
470
+ }
471
+ });
472
+ });
473
+
474
+ return relationships;
475
+ }
476
+
477
+ // Result for "users" module:
478
+ {
479
+ role: {
480
+ field: 'roleId',
481
+ relatedEntity: 'Role',
482
+ type: "many-to-one",
483
+ foreignKey: "roleId",
484
+ endpoint: "/api/roles",
485
+ displayField: "name",
486
+ populated: false,
487
+ },
488
+ organization: {
489
+ field: 'organizationId',
490
+ relatedEntity: 'Organization',
491
+ type: "many-to-one",
492
+ foreignKey: "organizationId",
493
+ endpoint: "/api/organizations",
494
+ displayField: "name",
495
+ populated: false,
496
+ }
497
+ }
498
+ ```
499
+
500
+ **✅ Only extract schemas for related entities (Role, Organization)**
501
+ **❌ Do NOT extract full CRUD endpoints for related modules**
502
+ **❌ Do NOT analyze deep nested relations (maxDepth = 1)**
503
+
504
+ ---
505
+
506
+ ## Phase 0.9: Current Implementation Audit (CRITICAL)
507
+
508
+ **Compare OpenAPI specification with existing mobile code to detect gaps and errors.**
509
+
510
+ ### Step 1: Check if Feature Exists
511
+
512
+ ```typescript
513
+ const featurePath = `src/features/${targetModule}`;
514
+ const featureExists = await fileExists(featurePath);
515
+
516
+ if (!featureExists) {
517
+ return {
518
+ status: 'NOT_IMPLEMENTED',
519
+ action: 'FULL_IMPLEMENTATION',
520
+ message: `Feature directory does not exist. Full implementation required.`,
521
+ };
522
+ }
523
+ ```
524
+
525
+ ### Step 2: Scan Existing Files
526
+
527
+ ```typescript
528
+ const existingFiles = {
529
+ types: await glob(`${featurePath}/types/**/*.ts`),
530
+ schemas: await glob(`${featurePath}/schemas/**/*.ts`),
531
+ services: await glob(`${featurePath}/services/**/*.ts`),
532
+ hooks: await glob(`${featurePath}/hooks/**/*.ts`),
533
+ components: await glob(`${featurePath}/components/**/*.tsx`),
534
+ screens: await glob(`${featurePath}/screens/**/*.tsx`), // Mobile uses "screens" not "pages"
535
+ tests: await glob(`${featurePath}/**/*.test.{ts,tsx}`),
536
+ };
537
+ ```
538
+
539
+ ### Step 3: Compare Types with OpenAPI Schemas
540
+
541
+ ```typescript
542
+ async function auditTypes(
543
+ openapiSchemas: Schema[],
544
+ existingTypeFiles: string[]
545
+ ): Promise<TypeAuditResult> {
546
+ const audit = {
547
+ matching: [],
548
+ missing: [],
549
+ incorrect: [],
550
+ };
551
+
552
+ for (const schema of openapiSchemas) {
553
+ const typeFile = existingTypeFiles.find(
554
+ (f) => f.includes(schema.name) || f.includes('entities.ts')
555
+ );
556
+
557
+ if (!typeFile) {
558
+ audit.missing.push({
559
+ schema: schema.name,
560
+ action: 'CREATE',
561
+ reason: 'Type definition not found',
562
+ });
563
+ continue;
564
+ }
565
+
566
+ // Parse existing type
567
+ const fileContent = await readFile(typeFile);
568
+ const existingType = parseTypeScriptInterface(fileContent, schema.name);
569
+
570
+ if (!existingType) {
571
+ audit.missing.push({
572
+ schema: schema.name,
573
+ action: 'CREATE',
574
+ reason: `Type not found in ${typeFile}`,
575
+ });
576
+ continue;
577
+ }
578
+
579
+ // Compare fields
580
+ const fieldComparison = compareFields(existingType.fields, schema.properties);
581
+
582
+ if (fieldComparison.hasDifferences) {
583
+ audit.incorrect.push({
584
+ schema: schema.name,
585
+ file: typeFile,
586
+ issues: [
587
+ ...fieldComparison.missingFields.map((f) => `Missing field: ${f}`),
588
+ ...fieldComparison.extraFields.map((f) => `Extra field: ${f}`),
589
+ ...fieldComparison.typeMismatches.map(
590
+ (m) => `Type mismatch for ${m.field}: expected ${m.expected}, got ${m.actual}`
591
+ ),
592
+ ],
593
+ action: 'UPDATE',
594
+ });
595
+ } else {
596
+ audit.matching.push(schema.name);
597
+ }
598
+ }
599
+
600
+ return audit;
601
+ }
602
+ ```
603
+
604
+ ### Step 4: Compare Endpoints with Hooks
605
+
606
+ ```typescript
607
+ async function auditHooks(
608
+ openapiEndpoints: Endpoint[],
609
+ existingHookFiles: string[]
610
+ ): Promise<HookAuditResult> {
611
+ const audit = {
612
+ implemented: [],
613
+ missing: [],
614
+ incorrect: [],
615
+ };
616
+
617
+ // Expected hooks based on endpoints
618
+ const expectedHooks = {
619
+ list: openapiEndpoints.find((e) => e.method === 'GET' && !e.path.includes('{')),
620
+ get: openapiEndpoints.find((e) => e.method === 'GET' && e.path.includes('{id}')),
621
+ create: openapiEndpoints.find((e) => e.method === 'POST'),
622
+ update: openapiEndpoints.find((e) => e.method === 'PUT'),
623
+ delete: openapiEndpoints.find((e) => e.method === 'DELETE'),
624
+ };
625
+
626
+ for (const [hookType, endpoint] of Object.entries(expectedHooks)) {
627
+ if (!endpoint) continue;
628
+
629
+ const expectedHookName = `use${capitalizeFirst(targetModule)}${capitalizeFirst(hookType === 'list' ? '' : hookType)}`;
630
+ const hookFile = existingHookFiles.find((f) => f.includes(expectedHookName));
631
+
632
+ if (!hookFile) {
633
+ audit.missing.push({
634
+ endpoint: `${endpoint.method} ${endpoint.path}`,
635
+ expectedHook: expectedHookName,
636
+ action: 'CREATE',
637
+ });
638
+ continue;
639
+ }
640
+
641
+ // Analyze hook implementation
642
+ const hookContent = await readFile(hookFile);
643
+ const hookAnalysis = analyzeHookCode(hookContent);
644
+
645
+ const issues = [];
646
+
647
+ if (!hookAnalysis.hasQueryKey) {
648
+ issues.push('Missing query key constant');
649
+ }
650
+
651
+ if (!hookAnalysis.isTypeSafe) {
652
+ issues.push('Uses `any` type or missing type annotations');
653
+ }
654
+
655
+ if (!hookAnalysis.hasErrorHandling) {
656
+ issues.push('Missing onError handler');
657
+ }
658
+
659
+ if (
660
+ hookAnalysis.hasCacheInvalidation === false &&
661
+ ['create', 'update', 'delete'].includes(hookType)
662
+ ) {
663
+ issues.push('Missing cache invalidation on success');
664
+ }
665
+
666
+ if (issues.length > 0) {
667
+ audit.incorrect.push({
668
+ hook: expectedHookName,
669
+ file: hookFile,
670
+ issues,
671
+ action: 'FIX',
672
+ });
673
+ } else {
674
+ audit.implemented.push(expectedHookName);
675
+ }
676
+ }
677
+
678
+ return audit;
679
+ }
680
+ ```
681
+
682
+ ### Step 5: Audit UI Components (Mobile-Specific)
683
+
684
+ ```typescript
685
+ async function auditComponents(
686
+ targetModule: string,
687
+ existingComponents: string[]
688
+ ): Promise<ComponentAuditResult> {
689
+ const expectedComponents = [
690
+ `${capitalizeFirst(targetModule)}List.tsx`, // FlatList component
691
+ `${capitalizeFirst(targetModule)}BottomSheet.tsx`, // Mobile uses Bottom Sheet instead of Drawer
692
+ `${capitalizeFirst(targetModule)}Form.tsx`,
693
+ `Delete${capitalizeFirst(targetModule)}Modal.tsx`, // Mobile uses Modal instead of Dialog
694
+ `${capitalizeFirst(targetModule)}Filters.tsx`,
695
+ ];
696
+
697
+ const audit = {
698
+ complete: [],
699
+ missing: [],
700
+ nonStandard: [],
701
+ };
702
+
703
+ for (const expectedComponent of expectedComponents) {
704
+ const componentFile = existingComponents.find((c) => c.endsWith(expectedComponent));
705
+
706
+ if (!componentFile) {
707
+ audit.missing.push({
708
+ component: expectedComponent,
709
+ action: 'CREATE',
710
+ });
711
+ continue;
712
+ }
713
+
714
+ // Analyze component quality
715
+ const componentContent = await readFile(componentFile);
716
+ const componentAnalysis = analyzeComponentCode(componentContent);
717
+
718
+ const issues = [];
719
+
720
+ if (expectedComponent.includes('List') && !componentAnalysis.usesFlatList) {
721
+ issues.push('Should use FlatList (React Native standard)');
722
+ }
723
+
724
+ if (expectedComponent.includes('Form') && !componentAnalysis.usesReactHookForm) {
725
+ issues.push('Should use React Hook Form (project standard)');
726
+ }
727
+
728
+ if (expectedComponent.includes('Form') && !componentAnalysis.usesZodValidation) {
729
+ issues.push('Missing Zod validation');
730
+ }
731
+
732
+ if (!componentAnalysis.hasLoadingStates) {
733
+ issues.push('Missing loading states (ActivityIndicator)');
734
+ }
735
+
736
+ if (!componentAnalysis.hasErrorHandling) {
737
+ issues.push('Missing error handling');
738
+ }
739
+
740
+ if (issues.length > 0) {
741
+ audit.nonStandard.push({
742
+ component: expectedComponent,
743
+ file: componentFile,
744
+ issues,
745
+ action: 'REFACTOR',
746
+ });
747
+ } else {
748
+ audit.complete.push(expectedComponent);
749
+ }
750
+ }
751
+
752
+ return audit;
753
+ }
754
+ ```
755
+
756
+ ### Step 6: Generate Implementation Status Report
757
+
758
+ ```typescript
759
+ function generateStatusReport(audits: AllAudits): ImplementationStatusReport {
760
+ const totalItems =
761
+ audits.types.missing.length +
762
+ audits.types.matching.length +
763
+ audits.types.incorrect.length +
764
+ audits.hooks.missing.length +
765
+ audits.hooks.implemented.length +
766
+ audits.hooks.incorrect.length +
767
+ audits.components.missing.length +
768
+ audits.components.complete.length +
769
+ audits.components.nonStandard.length;
770
+
771
+ const completeItems =
772
+ audits.types.matching.length +
773
+ audits.hooks.implemented.length +
774
+ audits.components.complete.length;
775
+
776
+ const score = Math.round((completeItems / totalItems) * 100);
777
+
778
+ let strategy: ImplementationStrategy;
779
+ if (score < 30) {
780
+ strategy = 'FULL_NEW';
781
+ } else if (score < 70) {
782
+ strategy = 'REFACTOR_COMPLETE';
783
+ } else {
784
+ strategy = 'MINOR_FIXES';
785
+ }
786
+
787
+ return {
788
+ score,
789
+ strategy,
790
+ audits,
791
+ summary: generateSummaryText(audits, score, strategy),
792
+ };
793
+ }
794
+ ```
795
+
796
+ **Report Output (Mobile):**
797
+
798
+ ```
799
+ 📊 Current Implementation Status: Users Module (Mobile)
800
+
801
+ 🗂️ Feature Structure:
802
+ ✅ Directory exists: src/features/users/
803
+
804
+ 📦 Types & Schemas:
805
+ ✅ UserResponseDto (matching OpenAPI)
806
+ ⚠️ CreateUserDto (missing fields: roleId, organizationId)
807
+ ❌ UpdateUserDto (not found - needs creation)
808
+
809
+ 🔧 Zod Schemas:
810
+ ❌ No validation schemas found
811
+
812
+ 🌐 API Services:
813
+ ✅ users.service.ts exists
814
+ ⚠️ Missing endpoints: PUT /users/{id}, DELETE /users/{id}
815
+
816
+ 🪝 Hooks:
817
+ ✅ useUsers (correct, type-safe, has query key)
818
+ ❌ useUserMutations (not found)
819
+ ❌ useCreateUser, useUpdateUser, useDeleteUser (not found)
820
+
821
+ 🎨 UI Components (Mobile):
822
+ ⚠️ UsersList.tsx (exists but doesn't use FlatList optimally - needs refactor)
823
+ ❌ UsersBottomSheet.tsx (not found)
824
+ ❌ UserForm.tsx (not found)
825
+ ❌ DeleteUserModal.tsx (not found)
826
+ ❌ UserFilters.tsx (not found)
827
+
828
+ 📱 Screens:
829
+ ⚠️ UsersScreen.tsx (exists but incomplete)
830
+
831
+ 🧪 Tests:
832
+ ❌ No tests found
833
+
834
+ 📊 Implementation Score: 35/100
835
+
836
+ 💡 Recommendation: REFACTOR + COMPLETE
837
+ - Update 1 existing type (CreateUserDto)
838
+ - Create 1 missing type (UpdateUserDto)
839
+ - Create all validation schemas (3 schemas)
840
+ - Add 2 missing API endpoints
841
+ - Create mutation hooks (3 hooks)
842
+ - Refactor existing list component
843
+ - Create 4 missing components
844
+ - Add comprehensive tests
845
+
846
+ ⏱️ Estimated: 13 SP / 8-10 hours
847
+ ```
848
+
849
+ ---
850
+
851
+ ## Phase 0.5: Project Standards Detection (Mobile-Specific)
852
+
853
+ **CRITICAL: Auto-detect React Native project stack and patterns.**
854
+
855
+ ### 1. Read package.json Dependencies
856
+
857
+ ```typescript
858
+ const packageJson = await readFile('package.json');
859
+ const { dependencies, devDependencies } = JSON.parse(packageJson);
860
+
861
+ // Detect installed libraries (React Native ecosystem)
862
+ const stack = {
863
+ ui: detectUILibrary(dependencies), // react-native-paper, @rneui, native-base
864
+ list: detectListComponent(dependencies), // FlatList (built-in), SectionList, FlashList
865
+ forms: detectFormsLibrary(dependencies), // react-hook-form
866
+ validation: detectValidation(dependencies), // zod, yup
867
+ query: detectDataFetching(dependencies), // @tanstack/react-query
868
+ state: detectStateManagement(dependencies), // zustand, redux, recoil
869
+ navigation: detectNavigation(dependencies), // @react-navigation/native
870
+ notifications: detectToasts(dependencies), // react-native-toast-message
871
+ };
872
+ ```
873
+
874
+ ### 2. Analyze Existing Components (Reference Pattern)
875
+
876
+ ```typescript
877
+ // Search for existing CRUD modules as reference
878
+ const existingModules = await searchFiles('src/features/**/components/**/*.tsx');
879
+
880
+ // Detect patterns from existing code:
881
+ const patterns = {
882
+ list: detectListComponent(existingModules), // FlatList | SectionList | FlashList
883
+ bottomSheet: detectBottomSheetPattern(existingModules), // @gorhom/bottom-sheet | Modal
884
+ filters: detectFiltersPattern(existingModules), // Collapsible | Bottom Sheet | Always Visible
885
+ formLayout: detectFormLayout(existingModules), // Single scroll | Sections
886
+ permissionGuards: detectAuthPattern(existingModules), // useAuth | usePermissions | role checks
887
+ };
888
+ ```
889
+
890
+ ### 3. Deep UI Pattern Extraction (Mobile-Specific)
891
+
892
+ **Extract EXACT design patterns from existing mobile code:**
893
+
894
+ ```typescript
895
+ // Analyze existing list components
896
+ const existingLists = await glob('src/features/**/components/*List.tsx');
897
+ const existingForms = await glob('src/features/**/components/*Form.tsx');
898
+ const existingBottomSheets = await glob('src/features/**/components/*BottomSheet.tsx');
899
+ const existingModals = await glob('src/features/**/components/*Modal.tsx');
900
+
901
+ const extractedDefaults = {
902
+ pagination: {
903
+ pageSize: detectMode(existingLists.map((l) => extractPaginationSize(l))), // Mode = 20 (mobile shows more)
904
+ initialLoad: detectMode(existingLists.map((l) => extractInitialLoad(l))), // 20
905
+ },
906
+ debounce: {
907
+ search: detectMode(existingHooks.map((h) => extractDebounceTime(h))), // 300ms
908
+ },
909
+ list: {
910
+ keyExtractor: detectMode(existingLists.map((l) => extractKeyPattern(l))), // (item) => item.id
911
+ windowSize: detectMode(existingLists.map((l) => extractWindowSize(l))), // 10
912
+ maxToRenderPerBatch: 10,
913
+ updateCellsBatchingPeriod: 50,
914
+ },
915
+ queryOptions: {
916
+ staleTime: detectMode(existingHooks.map((h) => extractStaleTime(h))),
917
+ gcTime: detectMode(existingHooks.map((h) => extractGcTime(h))),
918
+ retry: 1,
919
+ },
920
+ };
921
+
922
+ // Deep UI Pattern Analysis (Mobile)
923
+ const uiPatterns = {
924
+ list: {
925
+ contentContainerStyle: extractMode(existingLists, (code) =>
926
+ extractStyleProp(code, 'contentContainerStyle')
927
+ ),
928
+ itemSeparator: extractMode(existingLists, (code) =>
929
+ extractComponent(code, 'ItemSeparatorComponent')
930
+ ),
931
+ emptyComponent: extractMode(existingLists, (code) =>
932
+ extractComponent(code, 'ListEmptyComponent')
933
+ ),
934
+ headerComponent: extractMode(existingLists, (code) =>
935
+ extractComponent(code, 'ListHeaderComponent')
936
+ ),
937
+ footerComponent: extractMode(existingLists, (code) =>
938
+ extractComponent(code, 'ListFooterComponent')
939
+ ),
940
+ loadingIndicator: extractMode(existingLists, (code) => extractLoadingIndicator(code)),
941
+ },
942
+ form: {
943
+ layout: detectMode(existingForms.map((f) => detectFormLayout(f))), // 'scroll-view' | 'keyboard-avoiding'
944
+ spacing: detectMode(existingForms.map((f) => extractFieldSpacing(f))), // 16, 20, 24
945
+ textInputMode: detectMode(existingForms.map((f) => extractTextInputMode(f))), // 'outlined' | 'flat'
946
+ labelPosition: detectMode(existingForms.map((f) => extractLabelPosition(f))), // 'top' | 'floating'
947
+ buttonAlignment: detectMode(existingForms.map((f) => extractButtonAlignment(f))), // 'bottom' | 'inline'
948
+ validationDisplay: detectMode(existingForms.map((f) => extractValidationStyle(f))), // 'inline' | 'bottom'
949
+ },
950
+ bottomSheet: {
951
+ snapPoints: detectMode(existingBottomSheets.map((bs) => extractSnapPoints(bs))), // ['25%', '50%', '90%']
952
+ index: detectMode(existingBottomSheets.map((bs) => extractInitialIndex(bs))), // 1 (start at 50%)
953
+ enablePanDownToClose: true, // Most common
954
+ backdropComponent: detectMode(existingBottomSheets.map((bs) => extractBackdrop(bs))),
955
+ },
956
+ modal: {
957
+ animationType: detectMode(existingModals.map((m) => extractAnimationType(m))), // 'slide' | 'fade'
958
+ presentationStyle: detectMode(existingModals.map((m) => extractPresentationStyle(m))), // 'pageSheet' | 'formSheet'
959
+ transparent: detectMode(existingModals.map((m) => extractTransparent(m))), // true/false
960
+ },
961
+ reusableComponents: {
962
+ statusBadge: findComponent('StatusBadge'),
963
+ roleChip: findComponent('RoleChip'),
964
+ emptyState: findComponent('EmptyState'),
965
+ loadingSkeleton: findComponent('LoadingSkeleton'),
966
+ },
967
+ };
968
+
969
+ // Helper functions (mobile-specific)
970
+ function extractMode<T>(files: string[], extractor: (code: string) => T): T {
971
+ const values = files.map((f) => extractor(readFileSync(f, 'utf-8')));
972
+ return statisticalMode(values); // Most common value
973
+ }
974
+
975
+ function extractTextInputMode(code: string): 'outlined' | 'flat' {
976
+ const match = code.match(/<TextInput[^>]+mode="([^"]+)"/);
977
+ return (match?.[1] as any) || 'outlined';
978
+ }
979
+
980
+ function extractFormLayout(code: string): 'scroll-view' | 'keyboard-avoiding' | 'section-list' {
981
+ if (code.includes('<KeyboardAvoidingView')) {
982
+ return 'keyboard-avoiding';
983
+ }
984
+ if (code.includes('<SectionList')) {
985
+ return 'section-list';
986
+ }
987
+ return 'scroll-view';
988
+ }
989
+
990
+ function extractStyleProp(code: string, prop: string): string {
991
+ const styleMatch = code.match(new RegExp(`${prop}=\\{([^}]+)\\}`));
992
+ return styleMatch?.[1]?.trim() || 'not-found';
993
+ }
994
+ ```
995
+
996
+ ### 4. Reference Components for Consistency
997
+
998
+ Identify existing components to use as templates:
999
+
1000
+ ```typescript
1001
+ const referenceComponents = {
1002
+ list: 'src/features/organizations/components/OrganizationsList.tsx',
1003
+ screen: 'src/features/organizations/screens/OrganizationsScreen.tsx',
1004
+ hooks: 'src/features/users/hooks/useUsers.ts',
1005
+ mutations: 'src/features/users/hooks/useUserMutations.ts',
1006
+ navigation: 'src/navigation/MainNavigator.tsx',
1007
+ bottomSheet: 'src/components/common/BottomSheet.tsx',
1008
+ };
1009
+ ```
1010
+
1011
+ ---
1012
+
1013
+ ## Phase 1: Analysis Summary (Show Only - Mobile)
1014
+
1015
+ Present detected configuration, API analysis, and implementation audit to user:
1016
+
1017
+ ```
1018
+ 🔍 Project Stack Detected (Mobile):
1019
+
1020
+ UI: React Native Paper v5.11.0
1021
+ List: FlatList (React Native built-in) + FlashList v1.6.0 ✅
1022
+ Forms: React Hook Form v7.50.0 + Zod v3.22.4 ✅
1023
+ Data: TanStack Query v5.20.0 ✅
1024
+ State: Zustand v4.5.0 ✅
1025
+ Navigation: React Navigation v6.1.0 ✅
1026
+ Toasts: react-native-toast-message v2.1.7 ✅
1027
+
1028
+ 📐 UX Standards (from existing code):
1029
+ ✅ CRUD Pattern: Bottom Sheet (snap points: 25%, 50%, 90%)
1030
+ ✅ List: FlatList with pull-to-refresh, infinite scroll
1031
+ ✅ Filters: Bottom Sheet with Apply/Reset buttons
1032
+ ✅ Forms: React Hook Form + Zod validation (inline errors)
1033
+ ✅ Delete: Modal with confirmation (destructive style)
1034
+ ✅ Permissions: Hook-based (useAuthStore + role checks)
1035
+
1036
+ 📊 API Module Analysis: Users
1037
+
1038
+ Endpoints Found:
1039
+ ✅ GET /api/users (List with pagination)
1040
+ ✅ POST /api/users (Create)
1041
+ ✅ GET /api/users/{id} (Read)
1042
+ ✅ PUT /api/users/{id} (Update)
1043
+ ✅ DELETE /api/users/{id} (Delete)
1044
+
1045
+ Entity Schema:
1046
+ Fields (8): id, email, firstName, lastName, status, role, createdAt, updatedAt
1047
+ Required: email, firstName, lastName, roleId
1048
+ Enums: status (active, pending, suspended)
1049
+ Relations (1): role → /api/roles (many-to-one, display: name)
1050
+
1051
+ Features:
1052
+ ✅ Server-side pagination (page, limit, max: 100)
1053
+ ✅ Search (by name, email)
1054
+ ✅ Filters (roleId, status)
1055
+ ✅ Authentication (Bearer JWT)
1056
+ ✅ Role-based access (ROOT, OWNER, ADMIN)
1057
+
1058
+ ✅ All standards locked. Module will match existing patterns.
1059
+
1060
+ Analysis complete. Returning data to flow-work orchestrator...
1061
+ ```
1062
+
1063
+ ---
1064
+
1065
+ ## 📤 OUTPUT Format (CRITICAL)
1066
+
1067
+ **This sub-prompt MUST return a structured JSON object that flow-work can consume.**
1068
+
1069
+ ### OpenAPIAnalysisResult Interface (Mobile)
1070
+
1071
+ ```typescript
1072
+ interface OpenAPIAnalysisResult {
1073
+ // Meta
1074
+ success: boolean;
1075
+ module: string;
1076
+ apiUrl: string;
1077
+ timestamp: string; // ISO 8601
1078
+
1079
+ // Implementation Audit
1080
+ implementationAudit: {
1081
+ status: 'NOT_IMPLEMENTED' | 'PARTIAL' | 'COMPLETE';
1082
+ score: number; // 0-100
1083
+ strategy: 'FULL_NEW' | 'REFACTOR_COMPLETE' | 'MINOR_FIXES';
1084
+ types: {
1085
+ matching: string[];
1086
+ missing: Array<{ schema: string; action: string; reason: string }>;
1087
+ incorrect: Array<{
1088
+ schema: string;
1089
+ file: string;
1090
+ issues: string[];
1091
+ action: string;
1092
+ }>;
1093
+ };
1094
+ hooks: {
1095
+ implemented: string[];
1096
+ missing: Array<{
1097
+ endpoint: string;
1098
+ expectedHook: string;
1099
+ action: string;
1100
+ }>;
1101
+ incorrect: Array<{
1102
+ hook: string;
1103
+ file: string;
1104
+ issues: string[];
1105
+ action: string;
1106
+ }>;
1107
+ };
1108
+ components: {
1109
+ complete: string[];
1110
+ missing: Array<{ component: string; action: string }>;
1111
+ nonStandard: Array<{
1112
+ component: string;
1113
+ file: string;
1114
+ issues: string[];
1115
+ action: string;
1116
+ }>;
1117
+ };
1118
+ actionItems: string[]; // Human-readable list
1119
+ };
1120
+
1121
+ // Project Standards (detected - mobile)
1122
+ projectStandards: {
1123
+ stack: {
1124
+ ui: string; // 'react-native-paper v5.11.0'
1125
+ list: string; // 'FlatList (React Native) + FlashList v1.6.0'
1126
+ forms: string; // 'react-hook-form v7.50.0'
1127
+ validation: string; // 'zod v3.22.4'
1128
+ query: string; // '@tanstack/react-query v5.20.0'
1129
+ state: string; // 'zustand v4.5.0'
1130
+ navigation: string; // '@react-navigation/native v6.1.0'
1131
+ notifications: string; // 'react-native-toast-message v2.1.7'
1132
+ };
1133
+ patterns: {
1134
+ crudPattern: string; // 'bottom-sheet' | 'modal' | 'full-screen'
1135
+ bottomSheetSnapPoints: string[]; // ['25%', '50%', '90%']
1136
+ listComponent: string; // 'FlatList' | 'FlashList' | 'SectionList'
1137
+ filterUI: string; // 'bottom-sheet' | 'modal'
1138
+ formLayout: string; // 'scroll-view' | 'keyboard-avoiding'
1139
+ deleteConfirmation: string; // 'modal'
1140
+ };
1141
+ defaults: {
1142
+ pagination: {
1143
+ pageSize: number; // 20 (mobile typically loads more)
1144
+ initialLoad: number; // 20
1145
+ };
1146
+ debounce: {
1147
+ search: number; // 300ms
1148
+ };
1149
+ list: {
1150
+ windowSize: number; // 10
1151
+ maxToRenderPerBatch: number; // 10
1152
+ updateCellsBatchingPeriod: number; // 50
1153
+ };
1154
+ caching: {
1155
+ staleTime: number; // 30000ms (30s)
1156
+ gcTime: number; // 300000ms (5min)
1157
+ retry: number; // 1 for mutations
1158
+ };
1159
+ };
1160
+ referenceComponents: {
1161
+ list: string; // 'src/features/organizations/components/OrganizationsList.tsx'
1162
+ screen: string; // 'src/features/organizations/screens/OrganizationsScreen.tsx'
1163
+ hooks: string; // 'src/features/users/hooks/useUsers.ts'
1164
+ mutations: string; // 'src/features/users/hooks/useUserMutations.ts'
1165
+ };
1166
+ };
1167
+
1168
+ // OpenAPI Analysis
1169
+ openapi: {
1170
+ version: string; // '3.0.3'
1171
+ title: string; // 'CROSS Mobile API'
1172
+ totalPaths: number; // 45
1173
+ totalSchemas: number; // 32
1174
+ };
1175
+
1176
+ // Module Endpoints
1177
+ endpoints: Array<{
1178
+ method: string; // 'GET', 'POST', 'PUT', 'DELETE', 'PATCH'
1179
+ path: string; // '/api/users'
1180
+ operationId: string; // 'getUsers'
1181
+ summary: string; // 'List all users with pagination'
1182
+ tags: string[]; // ['Users']
1183
+ parameters: Array<{
1184
+ name: string; // 'page'
1185
+ in: string; // 'query'
1186
+ required: boolean;
1187
+ schema: {
1188
+ type: string;
1189
+ default?: any;
1190
+ enum?: any[];
1191
+ };
1192
+ }>;
1193
+ requestBody?: {
1194
+ required: boolean;
1195
+ schema: string; // 'CreateUserDto' (schema name)
1196
+ };
1197
+ responses: {
1198
+ [statusCode: string]: {
1199
+ description: string;
1200
+ schema?: string; // 'UserResponseDto' or 'PaginatedResponse<UserResponseDto>'
1201
+ };
1202
+ };
1203
+ }>;
1204
+
1205
+ // Entity Schemas (DTOs)
1206
+ schemas: {
1207
+ response: {
1208
+ name: string; // 'UserResponseDto'
1209
+ fields: FieldSpec[];
1210
+ };
1211
+ create: {
1212
+ name: string; // 'CreateUserDto'
1213
+ fields: FieldSpec[];
1214
+ };
1215
+ update: {
1216
+ name: string; // 'UpdateUserDto'
1217
+ fields: FieldSpec[];
1218
+ };
1219
+ };
1220
+
1221
+ // Field Specifications
1222
+ fields: FieldSpec[]; // All unique fields across DTOs
1223
+
1224
+ // Detected Features
1225
+ features: {
1226
+ pagination: {
1227
+ enabled: boolean;
1228
+ params: string[]; // ['page', 'limit']
1229
+ responseFormat: 'array' | 'object';
1230
+ dataKey?: string; // 'items' | 'data'
1231
+ totalKey?: string; // 'total' | 'meta.total'
1232
+ maxPageSize?: number; // 100
1233
+ };
1234
+ search: {
1235
+ enabled: boolean;
1236
+ params: string[]; // ['search', 'q']
1237
+ };
1238
+ sorting: {
1239
+ enabled: boolean;
1240
+ params: string[]; // ['sortBy', 'order']
1241
+ fields?: string[]; // Sortable fields
1242
+ };
1243
+ filtering: {
1244
+ enabled: boolean;
1245
+ fields: string[]; // ['status', 'roleId']
1246
+ };
1247
+ authentication: {
1248
+ type: 'bearer' | 'apiKey' | 'oauth2';
1249
+ required: boolean;
1250
+ };
1251
+ authorization: {
1252
+ roles: string[]; // ['ROOT', 'OWNER', 'ADMIN']
1253
+ permissions?: string[]; // ['user:read', 'user:write']
1254
+ };
1255
+ softDelete: {
1256
+ enabled: boolean;
1257
+ field?: string; // 'deletedAt' | 'status'
1258
+ };
1259
+ };
1260
+
1261
+ // Relationships
1262
+ relationships: Array<{
1263
+ field: string; // 'roleId' or 'role'
1264
+ relatedEntity: string; // 'Role'
1265
+ type: 'many-to-one' | 'one-to-many' | 'many-to-many' | 'one-to-one';
1266
+ foreignKey: string; // 'roleId'
1267
+ endpoint?: string; // '/api/roles'
1268
+ displayField: string; // 'name' (field to display in UI)
1269
+ populated: boolean; // true if backend returns full object
1270
+ }>;
1271
+
1272
+ // Complexity Analysis
1273
+ complexity: {
1274
+ level: 'SIMPLE' | 'MEDIUM' | 'COMPLEX';
1275
+ estimatedFiles: number; // 18-20
1276
+ estimatedSP: number; // 8
1277
+ estimatedHours: number; // 5-6
1278
+ factors: {
1279
+ endpoints: number; // 5
1280
+ relations: number; // 2
1281
+ customEndpoints: number; // 0
1282
+ validationRules: number; // 15
1283
+ };
1284
+ };
1285
+
1286
+ // Validation & Warnings
1287
+ warnings: string[]; // Issues detected (missing endpoints, inconsistent naming, etc.)
1288
+ suggestions: string[]; // Recommendations
1289
+ }
1290
+
1291
+ interface FieldSpec {
1292
+ name: string; // 'email'
1293
+ type: 'string' | 'number' | 'boolean' | 'date' | 'enum' | 'array' | 'object' | 'uuid';
1294
+ required: boolean;
1295
+ nullable: boolean;
1296
+ validation?: {
1297
+ min?: number;
1298
+ max?: number;
1299
+ pattern?: string;
1300
+ format?: 'email' | 'url' | 'uuid' | 'date-time' | 'password';
1301
+ enum?: string[];
1302
+ };
1303
+ relation?: {
1304
+ entity: string; // 'Role'
1305
+ type: 'many-to-one' | 'one-to-many' | 'many-to-many';
1306
+ foreignKey: string; // 'roleId'
1307
+ populated: boolean;
1308
+ displayField: string; // 'name'
1309
+ };
1310
+ category: 'auto-generated' | 'read-only' | 'editable' | 'metadata';
1311
+ usage: {
1312
+ showInList: boolean; // Mobile uses "list" not "table"
1313
+ showInForm: boolean; // In create/edit forms
1314
+ showInDetails: boolean;
1315
+ editable: boolean; // Can be edited after creation
1316
+ };
1317
+ default?: any;
1318
+ description?: string;
1319
+
1320
+ // DTO specific
1321
+ inResponseDto: boolean;
1322
+ inCreateDto: boolean;
1323
+ inUpdateDto: boolean;
1324
+ }
1325
+ ```
1326
+
1327
+ ### Return Format
1328
+
1329
+ ```json
1330
+ {
1331
+ "success": true,
1332
+ "module": "users",
1333
+ "apiUrl": "http://localhost:3001/api/docs-json",
1334
+ "timestamp": "2026-03-04T10:30:00-03:00",
1335
+ "projectStandards": {
1336
+ /* ... mobile-specific */
1337
+ },
1338
+ "openapi": {
1339
+ /* ... */
1340
+ },
1341
+ "endpoints": [
1342
+ /* ... */
1343
+ ],
1344
+ "schemas": {
1345
+ /* ... */
1346
+ },
1347
+ "fields": [
1348
+ /* ... */
1349
+ ],
1350
+ "features": {
1351
+ /* ... */
1352
+ },
1353
+ "relationships": [
1354
+ /* ... */
1355
+ ],
1356
+ "complexity": {
1357
+ /* ... */
1358
+ },
1359
+ "warnings": [],
1360
+ "suggestions": []
1361
+ }
1362
+ ```
1363
+
1364
+ ---
1365
+
1366
+ ## Best Practices Reference (For flow-work - Mobile)
1367
+
1368
+ **These patterns should be enforced by flow-work during mobile code generation:**
1369
+
1370
+ ### 1. Use FlatList or FlashList (React Native Standard)
1371
+
1372
+ ```typescript
1373
+ // ✅ CORRECT: Use FlatList with optimization
1374
+ import { FlatList, ActivityIndicator } from 'react-native';
1375
+
1376
+ <FlatList
1377
+ data={users}
1378
+ keyExtractor={(item) => item.id}
1379
+ renderItem={({ item }) => <UserListItem user={item} />}
1380
+ onEndReached={loadMore}
1381
+ onEndReachedThreshold={0.3}
1382
+ refreshing={isRefreshing}
1383
+ onRefresh={refetch}
1384
+ ListEmptyComponent={<EmptyState />}
1385
+ ListFooterComponent={isLoading ? <ActivityIndicator /> : null}
1386
+ windowSize={10}
1387
+ maxToRenderPerBatch={10}
1388
+ updateCellsBatchingPeriod={50}
1389
+ />
1390
+
1391
+ // ❌ WRONG: Don't use ScrollView with map for long lists
1392
+ // <ScrollView>{users.map(user => <UserItem user={user} />)}</ScrollView>
1393
+ ```
1394
+
1395
+ ### 2. Query Key Management
1396
+
1397
+ ```typescript
1398
+ // ✅ CORRECT: Export query key constant
1399
+ export const USERS_QUERY_KEY = 'users';
1400
+
1401
+ export const useUsers = (params: GetUsersParams) => {
1402
+ return useQuery({
1403
+ queryKey: [USERS_QUERY_KEY, params],
1404
+ queryFn: () => usersService.getUsers(params),
1405
+ });
1406
+ };
1407
+ ```
1408
+
1409
+ ### 3. Cache Invalidation Strategy (Broad)
1410
+
1411
+ ```typescript
1412
+ // ✅ CORRECT: Invalidate ALL related queries
1413
+ void queryClient.invalidateQueries({ queryKey: [USERS_QUERY_KEY] });
1414
+
1415
+ // ❌ WRONG: Too specific (misses cached list queries)
1416
+ // void queryClient.invalidateQueries({ queryKey: [USERS_QUERY_KEY, id] });
1417
+ ```
1418
+
1419
+ ### 4. Toast Message Standards (Mobile)
1420
+
1421
+ ```typescript
1422
+ // ✅ CREATE success
1423
+ Toast.show({
1424
+ type: 'success',
1425
+ text1: 'Usuario creado',
1426
+ text2: 'Email de bienvenida enviado',
1427
+ });
1428
+
1429
+ // ✅ UPDATE success
1430
+ Toast.show({
1431
+ type: 'success',
1432
+ text1: 'Usuario actualizado',
1433
+ });
1434
+
1435
+ // ✅ ERROR with status
1436
+ if (error.response?.status === 409) {
1437
+ Toast.show({
1438
+ type: 'error',
1439
+ text1: 'Error',
1440
+ text2: 'No puedes suspender al último OWNER activo',
1441
+ });
1442
+ }
1443
+ ```
1444
+
1445
+ ### 5. Loading States (Mobile)
1446
+
1447
+ ```typescript
1448
+ // ✅ Proper loading states for FlatList
1449
+ <FlatList
1450
+ data={data?.items ?? []}
1451
+ refreshing={isRefreshing} // Pull-to-refresh
1452
+ onRefresh={refetch}
1453
+ ListFooterComponent={
1454
+ isFetchingNextPage ? <ActivityIndicator /> : null
1455
+ }
1456
+ ListEmptyComponent={
1457
+ isLoading ? <LoadingSkeleton /> : <EmptyState />
1458
+ }
1459
+ />
1460
+ ```
1461
+
1462
+ ---
1463
+
1464
+ ## Error Handling
1465
+
1466
+ **If analysis fails at any step:**
1467
+
1468
+ ```json
1469
+ {
1470
+ "success": false,
1471
+ "module": "users",
1472
+ "error": "Failed to fetch OpenAPI spec",
1473
+ "details": "Connection timeout after 10 seconds",
1474
+ "suggestions": [
1475
+ "1. Ensure backend server is running and accessible from device",
1476
+ "2. Check network configuration (WiFi, mobile data)",
1477
+ "3. Verify API URL is correct (not localhost if testing on real device)",
1478
+ "4. Try --api-url=http://your-computer-ip:3001/api/docs-json"
1479
+ ]
1480
+ }
1481
+ ```
1482
+
1483
+ **flow-work should handle this by:**
1484
+
1485
+ 1. Showing error to user
1486
+ 2. Offering retry or manual mode
1487
+ 3. Logging error for debugging
1488
+
1489
+ ---
1490
+
1491
+ ## End of Sub-Prompt
1492
+
1493
+ **This prompt returns control to `flow-work` with the `OpenAPIAnalysisResult` data structure.**
1494
+
1495
+ Flow-work will use this data to:
1496
+
1497
+ - Generate detailed `work.md` (Phase 2)
1498
+ - Create branch with naming convention (Phase 3)
1499
+ - Execute implementation (Phase 3)
1500
+ - Validate and finalize (Phase 4)