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,1547 @@
1
+ ---
2
+ description: Analyze OpenAPI specification to extract complete module metadata for frontend CRUD generation
3
+ ---
4
+
5
+ # API Module Analyzer (Sub-Prompt)
6
+
7
+ **YOU ARE AN EXPERT API ANALYZER specialized in extracting comprehensive metadata from OpenAPI specifications for frontend 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, 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 project-specific patterns
44
+ 3. Ensure type-safety between frontend 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, CORS, and timeouts.**
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('CORS')) {
108
+ throw new Error('CORS error. Backend must allow frontend origin.');
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 Backoffice 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
+ showInTable: field.name === 'id' ? false : true,
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
+ showInTable: 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
+ showInTable: 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
+ showInTable: 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 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
+ pages: await glob(`${featurePath}/pages/**/*.tsx`),
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
683
+
684
+ ```typescript
685
+ async function auditComponents(
686
+ targetModule: string,
687
+ existingComponents: string[]
688
+ ): Promise<ComponentAuditResult> {
689
+ const expectedComponents = [
690
+ `${capitalizeFirst(targetModule)}Table.tsx`,
691
+ `${capitalizeFirst(targetModule)}Drawer.tsx`,
692
+ `${capitalizeFirst(targetModule)}Form.tsx`,
693
+ `Delete${capitalizeFirst(targetModule)}Dialog.tsx`,
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('Table') && !componentAnalysis.usesMaterialReactTable) {
721
+ issues.push('Should use MaterialReactTable (project 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');
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:**
797
+
798
+ ```
799
+ 📊 Current Implementation Status: Users Module
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:
822
+ ⚠️ UsersTable.tsx (exists but doesn't use MaterialReactTable - needs refactor)
823
+ ❌ UserDrawer.tsx (not found)
824
+ ❌ UserForm.tsx (not found)
825
+ ❌ DeleteUserDialog.tsx (not found)
826
+ ❌ UserFilters.tsx (not found)
827
+
828
+ 📄 Pages:
829
+ ⚠️ UsersPage.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 table 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 (Automatic)
852
+
853
+ **CRITICAL: Auto-detect project stack and patterns to ensure consistency across all modules.**
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
862
+ const stack = {
863
+ ui: detectUILibrary(dependencies), // @mui/material, antd, chakra-ui, etc.
864
+ table: detectTableLibrary(dependencies), // material-react-table, @tanstack/react-table, @mui/x-data-grid
865
+ forms: detectFormsLibrary(dependencies), // react-hook-form, formik
866
+ validation: detectValidation(dependencies), // zod, yup, joi
867
+ query: detectDataFetching(dependencies), // @tanstack/react-query, swr, rtk-query
868
+ state: detectStateManagement(dependencies), // zustand, redux, recoil
869
+ notifications: detectToasts(dependencies), // sonner, react-toastify, notistack
870
+ };
871
+ ```
872
+
873
+ ### 2. Analyze Existing Components (Reference Pattern)
874
+
875
+ ```typescript
876
+ // Search for existing CRUD modules as reference
877
+ const existingModules = await searchFiles('src/features/**/components/**/*.tsx');
878
+
879
+ // Detect patterns from existing code:
880
+ const patterns = {
881
+ table: detectTableComponent(existingModules), // MaterialReactTable | DataGrid | TanStack
882
+ drawer: detectDrawerPattern(existingModules), // MUI Drawer | Dialog | Full Page
883
+ filters: detectFiltersPattern(existingModules), // Collapsible | Drawer | Always Visible
884
+ formLayout: detectFormLayout(existingModules), // Single form | Stepper | Tabs
885
+ permissionGuards: detectAuthPattern(existingModules), // useAuth | usePermissions | role checks
886
+ };
887
+ ```
888
+
889
+ ### 3. Deep UI Pattern Extraction (Enhanced)
890
+
891
+ **Extract EXACT design patterns from existing code (spacing, colors, typography, components):**
892
+
893
+ ```typescript
894
+ // Analyze existing table components
895
+ const existingTables = await glob('src/features/**/components/*Table.tsx');
896
+ const existingForms = await glob('src/features/**/components/*Form.tsx');
897
+ const existingDrawers = await glob('src/features/**/components/*Drawer.tsx');
898
+ const existingDialogs = await glob('src/features/**/components/*Dialog.tsx');
899
+
900
+ const extractedDefaults = {
901
+ pagination: {
902
+ pageSize: detectMode(existingTables.map((t) => extractPaginationSize(t))), // Mode = 10
903
+ pageSizeOptions: detectUnique(existingTables.map((t) => extractPaginationOptions(t))), // [10, 25, 50, 100]
904
+ },
905
+ debounce: {
906
+ search: detectMode(existingHooks.map((h) => extractDebounceTime(h))), // 300ms
907
+ },
908
+ table: {
909
+ density: detectMode(existingTables.map((t) => extractDensity(t))), // 'comfortable'
910
+ showProgressBars: true, // All tables use this
911
+ showAlertBanner: true,
912
+ enableRowActions: true,
913
+ positionActionsColumn: detectMode(existingTables.map((t) => extractActionsPosition(t))), // 'last'
914
+ },
915
+ queryOptions: {
916
+ staleTime: detectMode(existingHooks.map((h) => extractStaleTime(h))), // Most common value
917
+ gcTime: detectMode(existingHooks.map((h) => extractGcTime(h))),
918
+ retry: 1, // Default for mutations
919
+ },
920
+ };
921
+
922
+ // Deep UI Pattern Analysis
923
+ const uiPatterns = {
924
+ table: {
925
+ padding: extractMode(existingTables, (code) => extractSxProp(code, 'p')), // theme.spacing(2, 3)
926
+ headerColor: extractMode(existingTables, (code) => extractSxProp(code, 'backgroundColor')),
927
+ actionButtons: extractMode(existingTables, (code) => extractActionButtonStyle(code)),
928
+ emptyState: extractMode(existingTables, (code) => extractEmptyStateComponent(code)),
929
+ loading: extractMode(existingTables, (code) => extractLoadingComponent(code)),
930
+ },
931
+ form: {
932
+ layout: detectMode(existingForms.map((f) => detectFormLayout(f))), // 'single-column' | 'two-column'
933
+ maxWidth: detectMode(existingForms.map((f) => extractMaxWidth(f))), // '600px'
934
+ spacing: detectMode(existingForms.map((f) => extractFieldSpacing(f))), // theme.spacing(3)
935
+ textFieldVariant: detectMode(existingForms.map((f) => extractTextFieldVariant(f))), // 'outlined'
936
+ labelPosition: detectMode(existingForms.map((f) => extractLabelPosition(f))), // 'top'
937
+ buttonAlignment: detectMode(existingForms.map((f) => extractButtonAlignment(f))), // 'right'
938
+ validationDisplay: detectMode(existingForms.map((f) => extractValidationStyle(f))), // 'inline'
939
+ },
940
+ drawer: {
941
+ width: detectMode(existingDrawers.map((d) => extractDrawerWidth(d))), // 600
942
+ anchor: detectMode(existingDrawers.map((d) => extractDrawerAnchor(d))), // 'right'
943
+ headerHeight: detectMode(existingDrawers.map((d) => extractHeaderHeight(d))), // 64
944
+ headerPadding: detectMode(existingDrawers.map((d) => extractHeaderPadding(d))),
945
+ contentPadding: detectMode(existingDrawers.map((d) => extractContentPadding(d))),
946
+ footerLayout: detectMode(existingDrawers.map((d) => extractFooterLayout(d))),
947
+ closeIconPosition: detectMode(existingDrawers.map((d) => extractCloseIconPosition(d))),
948
+ },
949
+ dialog: {
950
+ maxWidth: detectMode(existingDialogs.map((d) => extractDialogMaxWidth(d))), // 'sm' (600px)
951
+ titleAlignment: detectMode(existingDialogs.map((d) => extractTitleAlignment(d))), // 'left'
952
+ buttonOrder: detectMode(existingDialogs.map((d) => extractButtonOrder(d))), // ['cancel', 'confirm']
953
+ destructiveColor: detectMode(existingDialogs.map((d) => extractDestructiveColor(d))), // 'error'
954
+ },
955
+ reusableComponents: {
956
+ statusBadge: findComponent('StatusBadge'),
957
+ roleChip: findComponent('RoleChip'),
958
+ emptyState: findComponent('EmptyState'),
959
+ loadingSkeleton: findComponent('LoadingSkeleton'),
960
+ },
961
+ };
962
+
963
+ // Helper functions
964
+ function extractMode<T>(files: string[], extractor: (code: string) => T): T {
965
+ const values = files.map((f) => extractor(readFileSync(f, 'utf-8')));
966
+ return statisticalMode(values); // Most common value
967
+ }
968
+
969
+ function extractTextFieldVariant(code: string): 'outlined' | 'filled' | 'standard' {
970
+ const match = code.match(/<TextField[^>]+variant="([^"]+)"/);
971
+ return (match?.[1] as any) || 'outlined';
972
+ }
973
+
974
+ function extractFormLayout(code: string): 'single-column' | 'two-column' | 'grid' {
975
+ if (code.includes('Grid container') || code.includes('grid-template-columns')) {
976
+ return 'grid';
977
+ }
978
+ if (code.match(/Grid.*xs=\{6\}/)) {
979
+ return 'two-column';
980
+ }
981
+ return 'single-column';
982
+ }
983
+
984
+ function extractSxProp(code: string, prop: string): string {
985
+ const sxMatch = code.match(/sx=\{\{([^}]+)\}\}/);
986
+ if (!sxMatch) return 'not-found';
987
+
988
+ const sxContent = sxMatch[1];
989
+ const propMatch = sxContent.match(new RegExp(`${prop}:\s*([^,}]+)`));
990
+ return propMatch?.[1]?.trim() || 'not-found';
991
+ }
992
+ ```
993
+
994
+ ### 4. Reference Components for Consistency
995
+
996
+ Identify existing components to use as templates:
997
+
998
+ ```typescript
999
+ const referenceComponents = {
1000
+ table: 'src/features/organizations/components/OrganizationTable.tsx',
1001
+ page: 'src/features/organizations/pages/OrganizationsPage.tsx',
1002
+ hooks: 'src/features/backoffice-users/hooks/useBackofficeUsers.ts',
1003
+ mutations: 'src/features/backoffice-users/hooks/useBackofficeUserMutations.ts',
1004
+ layout: 'src/components/layout/AppLayout.tsx',
1005
+ sidebar: 'src/components/layout/Sidebar.tsx',
1006
+ };
1007
+ ```
1008
+
1009
+ ---
1010
+
1011
+ ## Phase 1: Analysis Summary (Show Only)
1012
+
1013
+ Present detected configuration, API analysis, and implementation audit to user:
1014
+
1015
+ ```
1016
+ 🔍 Project Stack Detected:
1017
+
1018
+ UI: Material-UI v5.15.10
1019
+ Table: Material React Table v2.11.0 ✅
1020
+ Forms: React Hook Form v7.50.0 + Zod v3.22.4 ✅
1021
+ Data: TanStack Query v5.20.0 ✅
1022
+ State: Zustand v4.5.0 ✅
1023
+ Toasts: Sonner v1.4.0 ✅
1024
+
1025
+ 📐 UX Standards (from existing code):
1026
+ ✅ CRUD Pattern: Drawer (600px, right side)
1027
+ ✅ Table: MaterialReactTable with sorting, filtering, pagination
1028
+ ✅ Filters: Collapsible panel (MUI Accordion)
1029
+ ✅ Forms: React Hook Form + Zod validation (inline errors)
1030
+ ✅ Delete: Confirmation Dialog (error color for destructive)
1031
+ ✅ Permissions: Hook-based (useAuthStore + role checks)
1032
+
1033
+ 📊 API Module Analysis: Users
1034
+
1035
+ Endpoints Found:
1036
+ ✅ GET /api/users (List with pagination)
1037
+ ✅ POST /api/users (Create)
1038
+ ✅ GET /api/users/{id} (Read)
1039
+ ✅ PUT /api/users/{id} (Update)
1040
+ ✅ DELETE /api/users/{id} (Delete)
1041
+ ℹ️ GET /api/users/me (Profile)
1042
+ ℹ️ PUT /api/users/me/password (Change Password)
1043
+
1044
+ Entity Schema:
1045
+ Fields (8): id, email, firstName, lastName, status, role, createdAt, updatedAt
1046
+ Required: email, firstName, lastName, roleId
1047
+ Enums: status (active, pending, suspended)
1048
+ Relations (1): role → /api/roles (many-to-one, display: name)
1049
+
1050
+ Features:
1051
+ ✅ Server-side pagination (page, limit, max: 100)
1052
+ ✅ Search (by name, email)
1053
+ ✅ Filters (roleId, status)
1054
+ ✅ Authentication (Bearer JWT)
1055
+ ✅ Role-based access (ROOT, OWNER, ADMIN)
1056
+ ❌ Bulk operations
1057
+ ❌ Export
1058
+
1059
+ 📊 Current Implementation Status:
1060
+
1061
+ 🗂️ Feature Structure:
1062
+ ⚠️ Directory exists: src/features/users/ (partial implementation)
1063
+
1064
+ 📦 Types (2/3 complete):
1065
+ ✅ UserResponseDto (matching OpenAPI)
1066
+ ⚠️ CreateUserDto (missing: roleId, organizationId)
1067
+ ❌ UpdateUserDto (not found)
1068
+
1069
+ 🔧 Zod Schemas (0/3 complete):
1070
+ ❌ No validation schemas found
1071
+
1072
+ 🌐 API Services (3/5 endpoints):
1073
+ ✅ GET /users
1074
+ ✅ POST /users
1075
+ ✅ GET /users/{id}
1076
+ ❌ PUT /users/{id} (not implemented)
1077
+ ❌ DELETE /users/{id} (not implemented)
1078
+
1079
+ 🪝 Hooks (1/4 complete):
1080
+ ✅ useUsers (type-safe, correct query key)
1081
+ ❌ useCreateUser (not found)
1082
+ ❌ useUpdateUser (not found)
1083
+ ❌ useDeleteUser (not found)
1084
+
1085
+ 🎨 UI Components (1/5 complete):
1086
+ ⚠️ UsersTable.tsx (uses old DataGrid, should use MaterialReactTable)
1087
+ ❌ UserDrawer.tsx (not found)
1088
+ ❌ UserForm.tsx (not found)
1089
+ ❌ DeleteUserDialog.tsx (not found)
1090
+ ❌ UserFilters.tsx (not found)
1091
+
1092
+ 📄 Pages:
1093
+ ⚠️ UsersPage.tsx (incomplete, missing drawer integration)
1094
+
1095
+ 🧪 Tests (0/2 complete):
1096
+ ❌ No tests found
1097
+
1098
+ 📊 Implementation Score: 35/100
1099
+
1100
+ 💡 Recommendation: REFACTOR_COMPLETE
1101
+ Strategy: Keep working types, refactor table, complete missing pieces
1102
+
1103
+ Action Items:
1104
+ - Update 1 type (CreateUserDto: +2 fields)
1105
+ - Create 1 type (UpdateUserDto)
1106
+ - Create 3 Zod schemas
1107
+ - Add 2 API endpoints (PUT, DELETE)
1108
+ - Create 3 mutation hooks
1109
+ - Refactor table (DataGrid → MaterialReactTable)
1110
+ - Create 4 UI components
1111
+ - Add comprehensive tests
1112
+
1113
+ ⏱️ Estimated: 13 SP / 8-10 hours
1114
+
1115
+ Complexity: 🏗️ COMPLEX (refactor + complete)
1116
+
1117
+ Reference Components (for consistency):
1118
+ 📄 Table: src/features/organizations/components/OrganizationTable.tsx
1119
+ 📄 Page: src/features/organizations/pages/OrganizationsPage.tsx
1120
+ 📄 Hooks: src/features/backoffice-users/hooks/useBackofficeUsers.ts
1121
+ 📄 Mutations: src/features/backoffice-users/hooks/useBackofficeUserMutations.ts
1122
+
1123
+ ✅ All standards locked. Module will match existing patterns.
1124
+
1125
+ Analysis complete. Returning data to flow-work orchestrator...
1126
+ ```
1127
+
1128
+ ---
1129
+
1130
+ ## 📤 OUTPUT Format (CRITICAL)
1131
+
1132
+ **This sub-prompt MUST return a structured JSON object that flow-work can consume.**
1133
+
1134
+ ### OpenAPIAnalysisResult Interface
1135
+
1136
+ ```typescript
1137
+ interface OpenAPIAnalysisResult {
1138
+ // Meta
1139
+ success: boolean;
1140
+ module: string;
1141
+ apiUrl: string;
1142
+ timestamp: string; // ISO 8601
1143
+
1144
+ // Implementation Audit
1145
+ implementationAudit: {
1146
+ status: 'NOT_IMPLEMENTED' | 'PARTIAL' | 'COMPLETE';
1147
+ score: number; // 0-100
1148
+ strategy: 'FULL_NEW' | 'REFACTOR_COMPLETE' | 'MINOR_FIXES';
1149
+ types: {
1150
+ matching: string[];
1151
+ missing: Array<{ schema: string; action: string; reason: string }>;
1152
+ incorrect: Array<{
1153
+ schema: string;
1154
+ file: string;
1155
+ issues: string[];
1156
+ action: string;
1157
+ }>;
1158
+ };
1159
+ hooks: {
1160
+ implemented: string[];
1161
+ missing: Array<{
1162
+ endpoint: string;
1163
+ expectedHook: string;
1164
+ action: string;
1165
+ }>;
1166
+ incorrect: Array<{
1167
+ hook: string;
1168
+ file: string;
1169
+ issues: string[];
1170
+ action: string;
1171
+ }>;
1172
+ };
1173
+ components: {
1174
+ complete: string[];
1175
+ missing: Array<{ component: string; action: string }>;
1176
+ nonStandard: Array<{
1177
+ component: string;
1178
+ file: string;
1179
+ issues: string[];
1180
+ action: string;
1181
+ }>;
1182
+ };
1183
+ actionItems: string[]; // Human-readable list
1184
+ };
1185
+
1186
+ // Project Standards (detected)
1187
+ projectStandards: {
1188
+ stack: {
1189
+ ui: string; // '@mui/material v5.15.10'
1190
+ table: string; // 'material-react-table v2.11.0'
1191
+ forms: string; // 'react-hook-form v7.50.0'
1192
+ validation: string; // 'zod v3.22.4'
1193
+ query: string; // '@tanstack/react-query v5.20.0'
1194
+ state: string; // 'zustand v4.5.0'
1195
+ notifications: string; // 'sonner v1.4.0'
1196
+ };
1197
+ patterns: {
1198
+ crudPattern: string; // 'drawer' | 'modal' | 'page'
1199
+ drawerWidth: number; // 600
1200
+ drawerAnchor: string; // 'right'
1201
+ tableComponent: string; // 'MaterialReactTable'
1202
+ filterUI: string; // 'collapsible_panel'
1203
+ formLayout: string; // 'single_form'
1204
+ deleteConfirmation: string; // 'dialog'
1205
+ };
1206
+ defaults: {
1207
+ pagination: {
1208
+ pageSize: number; // 10
1209
+ options: number[]; // [10, 25, 50, 100]
1210
+ };
1211
+ debounce: {
1212
+ search: number; // 300ms
1213
+ };
1214
+ table: {
1215
+ density: string; // 'comfortable'
1216
+ showProgressBars: boolean;
1217
+ showAlertBanner: boolean;
1218
+ };
1219
+ caching: {
1220
+ staleTime: number; // 30000ms (30s)
1221
+ gcTime: number; // 300000ms (5min)
1222
+ retry: number; // 1 for mutations
1223
+ };
1224
+ };
1225
+ referenceComponents: {
1226
+ table: string; // 'src/features/organizations/components/OrganizationTable.tsx'
1227
+ page: string; // 'src/features/organizations/pages/OrganizationsPage.tsx'
1228
+ hooks: string; // 'src/features/backoffice-users/hooks/useBackofficeUsers.ts'
1229
+ mutations: string; // 'src/features/backoffice-users/hooks/useBackofficeUserMutations.ts'
1230
+ };
1231
+ };
1232
+
1233
+ // OpenAPI Analysis
1234
+ openapi: {
1235
+ version: string; // '3.0.3'
1236
+ title: string; // 'CROSS Backoffice API'
1237
+ totalPaths: number; // 45
1238
+ totalSchemas: number; // 32
1239
+ };
1240
+
1241
+ // Module Endpoints
1242
+ endpoints: Array<{
1243
+ method: string; // 'GET', 'POST', 'PUT', 'DELETE', 'PATCH'
1244
+ path: string; // '/api/users'
1245
+ operationId: string; // 'getUsers'
1246
+ summary: string; // 'List all users with pagination'
1247
+ tags: string[]; // ['Users']
1248
+ parameters: Array<{
1249
+ name: string; // 'page'
1250
+ in: string; // 'query'
1251
+ required: boolean;
1252
+ schema: {
1253
+ type: string;
1254
+ default?: any;
1255
+ enum?: any[];
1256
+ };
1257
+ }>;
1258
+ requestBody?: {
1259
+ required: boolean;
1260
+ schema: string; // 'CreateUserDto' (schema name)
1261
+ };
1262
+ responses: {
1263
+ [statusCode: string]: {
1264
+ description: string;
1265
+ schema?: string; // 'UserResponseDto' or 'PaginatedResponse<UserResponseDto>'
1266
+ };
1267
+ };
1268
+ }>;
1269
+
1270
+ // Entity Schemas (DTOs)
1271
+ schemas: {
1272
+ response: {
1273
+ name: string; // 'UserResponseDto'
1274
+ fields: FieldSpec[];
1275
+ };
1276
+ create: {
1277
+ name: string; // 'CreateUserDto'
1278
+ fields: FieldSpec[];
1279
+ };
1280
+ update: {
1281
+ name: string; // 'UpdateUserDto'
1282
+ fields: FieldSpec[];
1283
+ };
1284
+ };
1285
+
1286
+ // Field Specifications
1287
+ fields: FieldSpec[]; // All unique fields across DTOs
1288
+
1289
+ // Detected Features
1290
+ features: {
1291
+ pagination: {
1292
+ enabled: boolean;
1293
+ params: string[]; // ['page', 'limit']
1294
+ responseFormat: 'array' | 'object';
1295
+ dataKey?: string; // 'items' | 'data'
1296
+ totalKey?: string; // 'total' | 'meta.total'
1297
+ maxPageSize?: number; // 100
1298
+ };
1299
+ search: {
1300
+ enabled: boolean;
1301
+ params: string[]; // ['search', 'q']
1302
+ };
1303
+ sorting: {
1304
+ enabled: boolean;
1305
+ params: string[]; // ['sortBy', 'order']
1306
+ fields?: string[]; // Sortable fields
1307
+ };
1308
+ filtering: {
1309
+ enabled: boolean;
1310
+ fields: string[]; // ['status', 'roleId']
1311
+ };
1312
+ authentication: {
1313
+ type: 'bearer' | 'apiKey' | 'oauth2';
1314
+ required: boolean;
1315
+ };
1316
+ authorization: {
1317
+ roles: string[]; // ['ROOT', 'OWNER', 'ADMIN']
1318
+ permissions?: string[]; // ['user:read', 'user:write']
1319
+ };
1320
+ softDelete: {
1321
+ enabled: boolean;
1322
+ field?: string; // 'deletedAt' | 'status'
1323
+ };
1324
+ };
1325
+
1326
+ // Relationships
1327
+ relationships: Array<{
1328
+ field: string; // 'roleId' or 'role'
1329
+ relatedEntity: string; // 'Role'
1330
+ type: 'many-to-one' | 'one-to-many' | 'many-to-many' | 'one-to-one';
1331
+ foreignKey: string; // 'roleId'
1332
+ endpoint?: string; // '/api/roles'
1333
+ displayField: string; // 'name' (field to display in UI)
1334
+ populated: boolean; // true if backend returns full object
1335
+ }>;
1336
+
1337
+ // Complexity Analysis
1338
+ complexity: {
1339
+ level: 'SIMPLE' | 'MEDIUM' | 'COMPLEX';
1340
+ estimatedFiles: number; // 18-20
1341
+ estimatedSP: number; // 8
1342
+ estimatedHours: number; // 5-6
1343
+ factors: {
1344
+ endpoints: number; // 5
1345
+ relations: number; // 2
1346
+ customEndpoints: number; // 0
1347
+ validationRules: number; // 15
1348
+ };
1349
+ };
1350
+
1351
+ // Validation & Warnings
1352
+ warnings: string[]; // Issues detected (missing endpoints, inconsistent naming, etc.)
1353
+ suggestions: string[]; // Recommendations
1354
+ }
1355
+
1356
+ interface FieldSpec {
1357
+ name: string; // 'email'
1358
+ type: 'string' | 'number' | 'boolean' | 'date' | 'enum' | 'array' | 'object' | 'uuid';
1359
+ required: boolean;
1360
+ nullable: boolean;
1361
+ validation?: {
1362
+ min?: number;
1363
+ max?: number;
1364
+ pattern?: string;
1365
+ format?: 'email' | 'url' | 'uuid' | 'date-time' | 'password';
1366
+ enum?: string[];
1367
+ };
1368
+ relation?: {
1369
+ entity: string; // 'Role'
1370
+ type: 'many-to-one' | 'one-to-many' | 'many-to-many';
1371
+ foreignKey: string; // 'roleId'
1372
+ populated: boolean;
1373
+ displayField: string; // 'name'
1374
+ };
1375
+ category: 'auto-generated' | 'read-only' | 'editable' | 'metadata';
1376
+ usage: {
1377
+ showInTable: boolean;
1378
+ showInForm: boolean; // In create/edit forms
1379
+ showInDetails: boolean;
1380
+ editable: boolean; // Can be edited after creation
1381
+ };
1382
+ default?: any;
1383
+ description?: string;
1384
+
1385
+ // DTO specific
1386
+ inResponseDto: boolean;
1387
+ inCreateDto: boolean;
1388
+ inUpdateDto: boolean;
1389
+ }
1390
+ ```
1391
+
1392
+ ### Return Format
1393
+
1394
+ ```json
1395
+ {
1396
+ "success": true,
1397
+ "module": "users",
1398
+ "apiUrl": "http://localhost:3001/api/docs-json",
1399
+ "timestamp": "2026-03-04T10:30:00-03:00",
1400
+ "projectStandards": {
1401
+ /* ... */
1402
+ },
1403
+ "openapi": {
1404
+ /* ... */
1405
+ },
1406
+ "endpoints": [
1407
+ /* ... */
1408
+ ],
1409
+ "schemas": {
1410
+ /* ... */
1411
+ },
1412
+ "fields": [
1413
+ /* ... */
1414
+ ],
1415
+ "features": {
1416
+ /* ... */
1417
+ },
1418
+ "relationships": [
1419
+ /* ... */
1420
+ ],
1421
+ "complexity": {
1422
+ /* ... */
1423
+ },
1424
+ "warnings": [],
1425
+ "suggestions": []
1426
+ }
1427
+ ```
1428
+
1429
+ ---
1430
+
1431
+ ## Best Practices Reference (For flow-work)
1432
+
1433
+ **These patterns should be enforced by flow-work during code generation:**
1434
+
1435
+ ### 1. Use MaterialReactTable (MRT) - Project Standard
1436
+
1437
+ ```typescript
1438
+ // ✅ CORRECT: Use MRT as detected in OrganizationTable.tsx
1439
+ import { MaterialReactTable, useMaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
1440
+
1441
+ const table = useMaterialReactTable({
1442
+ columns,
1443
+ data: users ?? [],
1444
+ enableRowActions: true,
1445
+ manualPagination: true,
1446
+ rowCount: totalRows,
1447
+ state: { pagination, isLoading },
1448
+ onPaginationChange: setPagination,
1449
+ });
1450
+
1451
+ return <MaterialReactTable table={table} />;
1452
+
1453
+ // ❌ WRONG: Don't use other table libraries
1454
+ // import { DataGrid } from '@mui/x-data-grid'; // NO
1455
+ ```
1456
+
1457
+ ### 2. Query Key Management
1458
+
1459
+ ```typescript
1460
+ // ✅ CORRECT: Export query key constant
1461
+ export const BACKOFFICE_USERS_QUERY_KEY = 'backoffice-users';
1462
+
1463
+ export const useBackofficeUsers = (params: GetBackofficeUsersParams) => {
1464
+ return useQuery({
1465
+ queryKey: [BACKOFFICE_USERS_QUERY_KEY, params],
1466
+ queryFn: () => backofficeUsersService.getBackofficeUsers(params),
1467
+ });
1468
+ };
1469
+ ```
1470
+
1471
+ ### 3. Cache Invalidation Strategy (Broad)
1472
+
1473
+ ```typescript
1474
+ // ✅ CORRECT: Invalidate ALL related queries
1475
+ void queryClient.invalidateQueries({ queryKey: [BACKOFFICE_USERS_QUERY_KEY] });
1476
+
1477
+ // ❌ WRONG: Too specific (misses cached list queries)
1478
+ // void queryClient.invalidateQueries({ queryKey: [BACKOFFICE_USERS_QUERY_KEY, id] });
1479
+ ```
1480
+
1481
+ ### 4. Toast Message Standards
1482
+
1483
+ ```typescript
1484
+ // ✅ CREATE success
1485
+ toast.success('Usuario creado exitosamente. Email de bienvenida enviado.');
1486
+
1487
+ // ✅ UPDATE success
1488
+ toast.success('Usuario actualizado');
1489
+
1490
+ // ✅ ERROR with status
1491
+ if (error.response?.status === 409) {
1492
+ toast.error('No puedes suspender al último OWNER activo de la organización');
1493
+ }
1494
+ ```
1495
+
1496
+ ### 5. Empty & Loading States
1497
+
1498
+ ```typescript
1499
+ const table = useMaterialReactTable({
1500
+ data: data?.items ?? [],
1501
+ state: {
1502
+ isLoading, // Initial load → Full skeleton
1503
+ showProgressBars: isFetching, // Refetch → Top progress bar
1504
+ showAlertBanner: isError, // Error → Red banner
1505
+ },
1506
+ });
1507
+ ```
1508
+
1509
+ ---
1510
+
1511
+ ## Error Handling
1512
+
1513
+ **If analysis fails at any step:**
1514
+
1515
+ ```json
1516
+ {
1517
+ "success": false,
1518
+ "module": "users",
1519
+ "error": "Failed to fetch OpenAPI spec",
1520
+ "details": "Connection timeout after 10 seconds",
1521
+ "suggestions": [
1522
+ "1. Ensure backend server is running on http://localhost:3001",
1523
+ "2. Check CORS configuration in backend",
1524
+ "3. Verify /api/docs-json endpoint is available",
1525
+ "4. Try --api-url=http://other-host:3000/api/docs"
1526
+ ]
1527
+ }
1528
+ ```
1529
+
1530
+ **flow-work should handle this by:**
1531
+
1532
+ 1. Showing error to user
1533
+ 2. Offering retry or manual mode
1534
+ 3. Logging error for debugging
1535
+
1536
+ ---
1537
+
1538
+ ## End of Sub-Prompt
1539
+
1540
+ **This prompt returns control to `flow-work` with the `OpenAPIAnalysisResult` data structure.**
1541
+
1542
+ Flow-work will use this data to:
1543
+
1544
+ - Generate detailed `work.md` (Phase 2)
1545
+ - Create branch with naming convention (Phase 3)
1546
+ - Execute implementation (Phase 3)
1547
+ - Validate and finalize (Phase 4)