ai-flow-dev 2.7.0 → 2.8.0

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