devendra-skill-package 1.0.2

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 (223) hide show
  1. package/.github/skills/boiler-project-generator/SKILL.md +103 -0
  2. package/.github/skills/boiler-project-generator/assets/templates/android/README.md +3 -0
  3. package/.github/skills/boiler-project-generator/assets/templates/angular/README.md +3 -0
  4. package/.github/skills/boiler-project-generator/assets/templates/flutter/README.md +3 -0
  5. package/.github/skills/boiler-project-generator/assets/templates/ios/README.md +3 -0
  6. package/.github/skills/boiler-project-generator/assets/templates/react/README.md +3 -0
  7. package/.github/skills/boiler-project-generator/assets/templates/react-native/README.md +3 -0
  8. package/.github/skills/boiler-project-generator/assets/templates/react-native/api-setup.ts +76 -0
  9. package/.github/skills/boiler-project-generator/assets/templates/react-native/component-primary-button.tsx +29 -0
  10. package/.github/skills/boiler-project-generator/assets/templates/react-native/env-config.env +4 -0
  11. package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-auth-screen.tsx +45 -0
  12. package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-dashboard-screen.tsx +45 -0
  13. package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-profile-screen.tsx +45 -0
  14. package/.github/skills/boiler-project-generator/assets/templates/react-native/hook-use-app-boot.ts +11 -0
  15. package/.github/skills/boiler-project-generator/assets/templates/react-native/navigation-setup.tsx +25 -0
  16. package/.github/skills/boiler-project-generator/assets/templates/react-native/project-structure.md +24 -0
  17. package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-hooks.ts +5 -0
  18. package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-session-slice.ts +29 -0
  19. package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-store.ts +15 -0
  20. package/.github/skills/boiler-project-generator/assets/templates/react-native/theme-index.ts +23 -0
  21. package/.github/skills/boiler-project-generator/assets/templates/react-native/utils-helpers.ts +7 -0
  22. package/.github/skills/boiler-project-generator/metadata.yaml +29 -0
  23. package/.github/skills/boiler-project-generator/references/android.md +19 -0
  24. package/.github/skills/boiler-project-generator/references/angular.md +14 -0
  25. package/.github/skills/boiler-project-generator/references/flutter.md +17 -0
  26. package/.github/skills/boiler-project-generator/references/ios.md +17 -0
  27. package/.github/skills/boiler-project-generator/references/react-native.md +103 -0
  28. package/.github/skills/boiler-project-generator/references/react.md +17 -0
  29. package/.github/skills/boiler-project-generator/scripts/angular.js +43 -0
  30. package/.github/skills/boiler-project-generator/scripts/generate-project.mjs +107 -0
  31. package/.github/skills/boiler-project-generator/scripts/init.js +105 -0
  32. package/.github/skills/boiler-project-generator/scripts/react-native.js +1041 -0
  33. package/.github/skills/boiler-project-generator/scripts/react.js +32 -0
  34. package/.github/skills/clean-architecture-generator/SKILL.md +235 -0
  35. package/.github/skills/clean-architecture-generator/references/architecture-core.md +126 -0
  36. package/.github/skills/clean-architecture-generator/references/platform-angular.md +374 -0
  37. package/.github/skills/clean-architecture-generator/references/platform-flutter.md +366 -0
  38. package/.github/skills/clean-architecture-generator/references/platform-react-native.md +590 -0
  39. package/.github/skills/clean-architecture-generator/references/platform-react.md +261 -0
  40. package/.github/skills/code-test-coverage-analyzer/SKILL.md +1358 -0
  41. package/.github/skills/code-test-coverage-analyzer/assets/config-questionnaire.md +118 -0
  42. package/.github/skills/code-test-coverage-analyzer/assets/conflict-resolution-protocol.md +99 -0
  43. package/.github/skills/code-test-coverage-analyzer/assets/coverage-calculation-rules.md +294 -0
  44. package/.github/skills/code-test-coverage-analyzer/assets/multi-strategy-search.md +145 -0
  45. package/.github/skills/code-test-coverage-analyzer/assets/output-file-contracts.md +651 -0
  46. package/.github/skills/code-test-coverage-analyzer/assets/status-definitions.md +273 -0
  47. package/.github/skills/code-test-coverage-analyzer/examples/example-invocation.md +208 -0
  48. package/.github/skills/code-test-coverage-analyzer/references/android-patterns.md +229 -0
  49. package/.github/skills/code-test-coverage-analyzer/references/angular-patterns.md +177 -0
  50. package/.github/skills/code-test-coverage-analyzer/references/backend-patterns.md +383 -0
  51. package/.github/skills/code-test-coverage-analyzer/references/flutter-patterns.md +254 -0
  52. package/.github/skills/code-test-coverage-analyzer/references/ios-patterns.md +228 -0
  53. package/.github/skills/code-test-coverage-analyzer/references/react-native-patterns.md +431 -0
  54. package/.github/skills/code-test-coverage-analyzer/references/react-patterns.md +206 -0
  55. package/.github/skills/code-test-coverage-analyzer/scripts/detect-platform.ps1 +261 -0
  56. package/.github/skills/code-test-coverage-analyzer/scripts/scan-repository.ps1 +242 -0
  57. package/.github/skills/code-test-coverage-analyzer/templates/brd-compliance-row.md +107 -0
  58. package/.github/skills/code-test-coverage-analyzer/templates/test-case-row.md +130 -0
  59. package/.github/skills/code-test-coverage-analyzer/templates/user-story-compliance-row.md +170 -0
  60. package/.github/skills/custom-font-integrator/SKILL.md +373 -0
  61. package/.github/skills/custom-font-integrator/assets/FontTestScreen.js +150 -0
  62. package/.github/skills/custom-font-integrator/references/example-info-plist.xml +21 -0
  63. package/.github/skills/custom-font-integrator/scripts/setup-fonts.sh +99 -0
  64. package/.github/skills/encryption-decryption-utility/Instructions.md +282 -0
  65. package/.github/skills/encryption-decryption-utility/README.md +222 -0
  66. package/.github/skills/encryption-decryption-utility/SKILL.md +645 -0
  67. package/.github/skills/encryption-decryption-utility/assets/encryption-config-template.json +13 -0
  68. package/.github/skills/encryption-decryption-utility/assets/platform-matrix.json +180 -0
  69. package/.github/skills/encryption-decryption-utility/metadata.yaml +51 -0
  70. package/.github/skills/encryption-decryption-utility/references/android-crypto.md +157 -0
  71. package/.github/skills/encryption-decryption-utility/references/angular-crypto.md +130 -0
  72. package/.github/skills/encryption-decryption-utility/references/approach-1-webcrypto.md +95 -0
  73. package/.github/skills/encryption-decryption-utility/references/approach-2-rsa-aes-cbc.md +111 -0
  74. package/.github/skills/encryption-decryption-utility/references/approach-3-aes-sharedkey.md +114 -0
  75. package/.github/skills/encryption-decryption-utility/references/architecture.md +233 -0
  76. package/.github/skills/encryption-decryption-utility/references/backend-alignment.md +506 -0
  77. package/.github/skills/encryption-decryption-utility/references/dependency-guidance.md +234 -0
  78. package/.github/skills/encryption-decryption-utility/references/ec-implementation.md +832 -0
  79. package/.github/skills/encryption-decryption-utility/references/error-handling-playbook.md +234 -0
  80. package/.github/skills/encryption-decryption-utility/references/flutter-crypto.md +105 -0
  81. package/.github/skills/encryption-decryption-utility/references/ios-crypto.md +338 -0
  82. package/.github/skills/encryption-decryption-utility/references/native-rsa-implementation.md +373 -0
  83. package/.github/skills/encryption-decryption-utility/references/node-crypto.md +86 -0
  84. package/.github/skills/encryption-decryption-utility/references/react-crypto.md +105 -0
  85. package/.github/skills/encryption-decryption-utility/references/react-native-crypto.md +1001 -0
  86. package/.github/skills/encryption-decryption-utility/references/react-web-crypto.md +668 -0
  87. package/.github/skills/encryption-decryption-utility/references/security-checklist.md +176 -0
  88. package/.github/skills/encryption-decryption-utility/references/web-crypto.md +74 -0
  89. package/.github/skills/encryption-decryption-utility/scripts/detect.js +128 -0
  90. package/.github/skills/encryption-decryption-utility/scripts/install.js +1713 -0
  91. package/.github/skills/encryption-decryption-utility/scripts/setup.js +800 -0
  92. package/.github/skills/encryption-decryption-utility/template.md +241 -0
  93. package/.github/skills/encryption-decryption-utility/templates/config-questionnaire.md +467 -0
  94. package/.github/skills/encryption-decryption-utility/templates/delivery-checklist.md +206 -0
  95. package/.github/skills/encryption-decryption-utility/templates/implementation-plan.md +304 -0
  96. package/.github/skills/feature-generator/SKILL.MD +2741 -0
  97. package/.github/skills/feature-generator/assets/fingerprint-schema.json +385 -0
  98. package/.github/skills/feature-generator/assets/spec-template.md +172 -0
  99. package/.github/skills/feature-generator/assets/transform-rules.json +82 -0
  100. package/.github/skills/feature-generator/references/api-envelope-patterns.md +327 -0
  101. package/.github/skills/feature-generator/references/screen-logic-patterns.md +399 -0
  102. package/.github/skills/feature-generator/references/state-library-patterns.md +464 -0
  103. package/.github/skills/figma-ui-mapper/README.md +34 -0
  104. package/.github/skills/figma-ui-mapper/SKILL.md +101 -0
  105. package/.github/skills/figma-ui-mapper/assets/templates/component-map-template.md +30 -0
  106. package/.github/skills/figma-ui-mapper/assets/templates/generation-report-template.md +49 -0
  107. package/.github/skills/figma-ui-mapper/metadata.yaml +22 -0
  108. package/.github/skills/figma-ui-mapper/references/android.md +11 -0
  109. package/.github/skills/figma-ui-mapper/references/angular.md +18 -0
  110. package/.github/skills/figma-ui-mapper/references/capacitor.md +18 -0
  111. package/.github/skills/figma-ui-mapper/references/common.md +23 -0
  112. package/.github/skills/figma-ui-mapper/references/expo.md +18 -0
  113. package/.github/skills/figma-ui-mapper/references/flutter.md +18 -0
  114. package/.github/skills/figma-ui-mapper/references/frameworks/angular/rules.md +23 -0
  115. package/.github/skills/figma-ui-mapper/references/frameworks/capacitor/rules.md +23 -0
  116. package/.github/skills/figma-ui-mapper/references/frameworks/expo/rules.md +23 -0
  117. package/.github/skills/figma-ui-mapper/references/frameworks/flutter/rules.md +23 -0
  118. package/.github/skills/figma-ui-mapper/references/frameworks/ionic/rules.md +23 -0
  119. package/.github/skills/figma-ui-mapper/references/frameworks/kotlin-multiplatform/rules.md +23 -0
  120. package/.github/skills/figma-ui-mapper/references/frameworks/native-android/rules.md +23 -0
  121. package/.github/skills/figma-ui-mapper/references/frameworks/native-ios/rules.md +23 -0
  122. package/.github/skills/figma-ui-mapper/references/frameworks/next/rules.md +23 -0
  123. package/.github/skills/figma-ui-mapper/references/frameworks/nuxt/rules.md +23 -0
  124. package/.github/skills/figma-ui-mapper/references/frameworks/react/rules.md +19 -0
  125. package/.github/skills/figma-ui-mapper/references/frameworks/react-native/rules.md +23 -0
  126. package/.github/skills/figma-ui-mapper/references/frameworks/svelte/rules.md +23 -0
  127. package/.github/skills/figma-ui-mapper/references/frameworks/vue/rules.md +23 -0
  128. package/.github/skills/figma-ui-mapper/references/ionic.md +18 -0
  129. package/.github/skills/figma-ui-mapper/references/ios.md +11 -0
  130. package/.github/skills/figma-ui-mapper/references/kotlin-multiplatform.md +18 -0
  131. package/.github/skills/figma-ui-mapper/references/native-android.md +18 -0
  132. package/.github/skills/figma-ui-mapper/references/native-ios.md +18 -0
  133. package/.github/skills/figma-ui-mapper/references/next.md +18 -0
  134. package/.github/skills/figma-ui-mapper/references/nuxt.md +18 -0
  135. package/.github/skills/figma-ui-mapper/references/react-figma-guideline.md +21 -0
  136. package/.github/skills/figma-ui-mapper/references/react-native.md +18 -0
  137. package/.github/skills/figma-ui-mapper/references/react.md +18 -0
  138. package/.github/skills/figma-ui-mapper/references/script-usage.md +46 -0
  139. package/.github/skills/figma-ui-mapper/references/svelte.md +18 -0
  140. package/.github/skills/figma-ui-mapper/references/vue.md +18 -0
  141. package/.github/skills/figma-ui-mapper/references/workflow.md +74 -0
  142. package/.github/skills/figma-ui-mapper/scripts/generate-page-through-figma.js +635 -0
  143. package/.github/skills/figma-ui-mapper/scripts/generate-react-page-through-figma.js +4 -0
  144. package/.github/skills/frontend-task-breakdown/SKILL.md +734 -0
  145. package/.github/skills/md-file-converter/SKILL.md +291 -0
  146. package/.github/skills/md-file-converter/config/formats.json +114 -0
  147. package/.github/skills/md-file-converter/extractors/extract-docx.sh +120 -0
  148. package/.github/skills/md-file-converter/extractors/extract-eml.py +108 -0
  149. package/.github/skills/md-file-converter/extractors/extract-pdf.sh +97 -0
  150. package/.github/skills/md-file-converter/extractors/extract-pptx.py +143 -0
  151. package/.github/skills/md-file-converter/extractors/extract-xlsx.py +175 -0
  152. package/.github/skills/md-file-converter/scripts/check-tools.sh +47 -0
  153. package/.github/skills/md-file-converter/scripts/extract-archive.sh +83 -0
  154. package/.github/skills/md-file-converter/scripts/extract-ocr.sh +77 -0
  155. package/.github/skills/md-file-converter/scripts/get-metadata.sh +57 -0
  156. package/.github/skills/md-file-converter/templates/output.md +73 -0
  157. package/.github/skills/md-file-converter/templates/unsupported-object.md +6 -0
  158. package/.github/skills/mockAPI-contract-generator/SKILL.md +607 -0
  159. package/.github/skills/test-case-validator/CHANGELOG.md +155 -0
  160. package/.github/skills/test-case-validator/CONFIGURATION.md +130 -0
  161. package/.github/skills/test-case-validator/EXAMPLES.md +50 -0
  162. package/.github/skills/test-case-validator/QUALITY_SCORING.md +98 -0
  163. package/.github/skills/test-case-validator/README.md +111 -0
  164. package/.github/skills/test-case-validator/REPORT_TEMPLATE.md +116 -0
  165. package/.github/skills/test-case-validator/SKILL.md +209 -0
  166. package/.github/skills/test-case-validator/SYSTEM_PROMPT.md +127 -0
  167. package/.github/skills/test-case-validator/TRACEABILITY_ENGINE.md +152 -0
  168. package/.github/skills/test-case-validator/VALIDATION_RULES.md +411 -0
  169. package/.github/skills/test-case-validator/config/default.config.yaml +62 -0
  170. package/.github/skills/test-case-validator/docs/ARCHITECTURE.md +66 -0
  171. package/.github/skills/test-case-validator/docs/EXTENDING.md +85 -0
  172. package/.github/skills/test-case-validator/docs/FAQ.md +88 -0
  173. package/.github/skills/test-case-validator/docs/VERSIONING.md +55 -0
  174. package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-brd.md +43 -0
  175. package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-test-cases.csv +9 -0
  176. package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-user-story.md +29 -0
  177. package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/output-report.md +303 -0
  178. package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/input-spec.md +43 -0
  179. package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/input-test-files-index.md +56 -0
  180. package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/output-report.md +274 -0
  181. package/.github/skills/test-case-validator/prompts/00-applicability-resolution.md +61 -0
  182. package/.github/skills/test-case-validator/prompts/01-extraction-user-story.md +58 -0
  183. package/.github/skills/test-case-validator/prompts/02-extraction-brd.md +64 -0
  184. package/.github/skills/test-case-validator/prompts/03-extraction-test-cases.md +92 -0
  185. package/.github/skills/test-case-validator/prompts/04-traceability-matrix.md +41 -0
  186. package/.github/skills/test-case-validator/prompts/05-coverage-analysis.md +46 -0
  187. package/.github/skills/test-case-validator/prompts/06-missing-scenario-detection.md +32 -0
  188. package/.github/skills/test-case-validator/prompts/07-duplicate-detection.md +36 -0
  189. package/.github/skills/test-case-validator/prompts/08-risk-analysis.md +39 -0
  190. package/.github/skills/test-case-validator/prompts/09-gated-wiring-validation.md +53 -0
  191. package/.github/skills/test-case-validator/prompts/10-observation-report.md +56 -0
  192. package/.github/skills/test-case-validator/prompts/11-final-report-assembly.md +57 -0
  193. package/.github/skills/test-case-validator/templates/coverage-table.md +25 -0
  194. package/.github/skills/test-case-validator/templates/executive-summary.md +38 -0
  195. package/.github/skills/test-case-validator/templates/final-summary-block.md +87 -0
  196. package/.github/skills/test-case-validator/templates/observation-entry.md +41 -0
  197. package/.github/skills/test-case-validator/templates/rtm-row.md +25 -0
  198. package/.github/skills/validation-engine-builder/README.md +50 -0
  199. package/.github/skills/validation-engine-builder/SKILL.md +241 -0
  200. package/.github/skills/validation-engine-builder/references/core.md +158 -0
  201. package/.github/skills/validation-engine-builder/references/platform-angular.md +166 -0
  202. package/.github/skills/validation-engine-builder/references/platform-flutter.md +118 -0
  203. package/.github/skills/validation-engine-builder/references/platform-react-native.md +170 -0
  204. package/.github/skills/validation-engine-builder/references/platform-react.md +94 -0
  205. package/.github/skills/validation-engine-builder/scripts/apply-to-project.js +80 -0
  206. package/.github/skills/validation-engine-builder/scripts/generate-angular.js +271 -0
  207. package/.github/skills/validation-engine-builder/scripts/generate-flutter.js +298 -0
  208. package/.github/skills/validation-engine-builder/scripts/generate-react-native.js +217 -0
  209. package/.github/skills/validation-engine-builder/scripts/generate-react.js +163 -0
  210. package/.github/skills/validation-engine-builder/scripts/install-deps.js +53 -0
  211. package/.github/skills/validation-engine-builder/scripts/shared/detect-platform.js +68 -0
  212. package/.github/skills/validation-engine-builder/scripts/shared/npm-deps.js +103 -0
  213. package/.github/skills/validation-engine-builder/scripts/shared/rhf-hook.js +43 -0
  214. package/.github/skills/validation-engine-builder/scripts/shared/ts-messages-regex.js +62 -0
  215. package/.github/skills/validation-engine-builder/scripts/shared/util.js +44 -0
  216. package/.github/skills/validation-engine-builder/scripts/shared/yup-schemas.js +80 -0
  217. package/.github/skills/validation-engine-builder/template.md +73 -0
  218. package/.github/skills/validation-engine-builder/templates/messages.json +22 -0
  219. package/.github/skills/validation-engine-builder/templates/regex.json +16 -0
  220. package/.github/skills/validation-engine-builder/templates/schemas.json +48 -0
  221. package/bin/index.js +145 -0
  222. package/package.json +22 -0
  223. package/readme.md +0 -0
@@ -0,0 +1,2741 @@
1
+ # feature-generator
2
+
3
+ ## Skill Metadata
4
+
5
+ ```yaml
6
+ name: feature-generator
7
+ version: 3.1.0
8
+ description: >
9
+ Supports two generation modes: single-screen and multi-screen module.
10
+ In both modes: asks 5 mandatory questions (design source, user stories, test
11
+ cases, business logic, API details + mapping), crawls the repository to build
12
+ an Architecture Fingerprint, then generates every layer of production-ready
13
+ React Native TypeScript code that fits the repository as-is.
14
+ In module mode: collects Q2–Q5 per screen, deduplicates shared entities,
15
+ generates one DI bootstrap for the whole module, and registers all screens
16
+ in the navigator in a single pass.
17
+ After generation, runs a post-completion validation phase that checks file
18
+ existence, imports, mapping coverage, business logic, test cases, user stories,
19
+ and code quality — auto-fixing every issue before reporting completion.
20
+ priority: high
21
+ auto-trigger:
22
+ - "generate feature from spec"
23
+ - "create feature from md"
24
+ - "build screen from spec"
25
+ - "md-driven feature"
26
+ - "spec to feature"
27
+ - "generate module from spec"
28
+ - "build module from md"
29
+ - "create module"
30
+ - "multi-screen feature"
31
+ ```
32
+
33
+ ---
34
+
35
+ ## Assets and References
36
+
37
+ | File | Purpose |
38
+ |---|---|
39
+ | `assets/spec-template.md` | Blank fillable spec template for users. Copy and fill before invoking the skill. |
40
+ | `assets/fingerprint-schema.json` | JSON Schema (draft-07) for the Architecture Fingerprint produced in Phase 0.K. Use to validate the fingerprint before proceeding to Phase 1. |
41
+ | `assets/transform-rules.json` | Configurable map of response mapping transform keywords to TypeScript expressions. Read in Phase 7.2. |
42
+ | `references/api-envelope-patterns.md` | Full code templates for every `apiLib` + `envelopeStyle` combination. Read in Phase 4.6. |
43
+ | `references/state-library-patterns.md` | Full code templates for Zustand, MobX, Context API, and RTK direct-import. Read in Phase 5 when `stateLib` is not `redux-toolkit/thunk-extra`. |
44
+ | `references/screen-logic-patterns.md` | React Native JSX implementations for every screen logic pattern. Read in Phase 7.3. |
45
+
46
+ ---
47
+
48
+ ## Overview
49
+
50
+ This skill turns a human-authored Markdown specification into production-ready
51
+ React Native TypeScript code that fits the repository as-is — not as assumed.
52
+
53
+ **Core philosophy**: Every decision about folder layout, import paths, state
54
+ management, API calling convention, naming style, and navigation must come from
55
+ reading the actual repository. Nothing is assumed. The skill crawls first and
56
+ codes second.
57
+
58
+ ### Generation Modes
59
+
60
+ This skill operates in one of two modes, determined during PHASE -1 Q1:
61
+
62
+ | Mode | When to use | What gets generated |
63
+ |---|---|---|
64
+ | **single** | One screen, one API, self-contained | All layers for one screen |
65
+ | **module** | Multiple screens that share a feature folder (e.g. FD Booking with Details, Payment, Confirmation screens) | All layers for every screen + one shared DI bootstrap for the module + shared entities deduplicated across screens + all screens registered in navigator in one pass |
66
+
67
+ **Module folder structure (example — `fdBooking` module with 3 screens):**
68
+ ```
69
+ features/
70
+ fdBooking/
71
+ domain/
72
+ models/ ← shared entities used by more than one screen live here
73
+ FdBookingItem.ts
74
+ repositories/ ← one repo interface per screen
75
+ useCases/ ← one use case per screen
76
+ data/
77
+ dtos/ ← one DTO per screen
78
+ mappers/ ← one mapper per screen
79
+ datasources/ ← one datasource per screen + shared endpoints + mockConfig
80
+ state/ ← one slice per screen (or one shared slice if confirmed by user)
81
+ store/
82
+ selectors/
83
+ presentation/
84
+ screens/
85
+ FdDetailsScreen/
86
+ PaymentScreen/
87
+ ConfirmationScreen/
88
+ diBootstrap.ts ← ONE file for the whole module (not per-screen)
89
+ ```
90
+
91
+ In single mode, the module folder contains exactly one screen and one of each layer file.
92
+
93
+ ### Input
94
+
95
+ All inputs are collected via the **Mandatory User Interview (PHASE -1)** below.
96
+ Do NOT proceed to PHASE 0 until all 5 questions have been answered and confirmed.
97
+
98
+ ---
99
+
100
+ ## PHASE -1 — Mandatory User Interview
101
+
102
+ > **This phase is REQUIRED. Do NOT skip or reorder any question.**
103
+ > Do NOT assume, infer, or hallucinate any answer to any question.
104
+ > If the user's answer is incomplete, ambiguous, or missing required fields — ask a targeted follow-up before moving on.
105
+ > All 5 questions MUST be answered before proceeding to PHASE 0.
106
+ > Proceed ONLY after you have explicit answers (or an explicit WARN-acknowledged skip) for every question.
107
+
108
+ ---
109
+
110
+ ### QUESTION 1 — Generation Mode & Design Source
111
+
112
+ Ask the user:
113
+
114
+ > "Are you generating a **single screen** or a **module** (multiple screens that belong to the same feature)?
115
+ >
116
+ > - **Single screen** — one screen, one API endpoint
117
+ > - **Module** — multiple screens under one feature folder (e.g. FD Booking: Details screen + Payment screen + Confirmation screen)
118
+ >
119
+ > Please also tell me the name(s):"
120
+
121
+ ---
122
+
123
+ #### If mode = single:
124
+
125
+ Ask:
126
+ > "What is the PascalCase name for the new screen? (e.g. `TransactionHistory`, `FundDetail`, `UserProfile`)
127
+ >
128
+ > Also provide the design source:
129
+ > - **Spec MD files** — file path(s) to filled spec Markdown files
130
+ > - **Existing screen paths** — relative paths to existing screens to use as UI structure reference
131
+ >
132
+ > Provide at least one source."
133
+
134
+ **Collect:**
135
+ ```
136
+ GENERATION_MODE: single
137
+ SCREEN_NAME: <PascalCase name>
138
+ DESIGN_SOURCE_TYPE: md-file | screen-path | mixed
139
+ SPEC_MD_FILES: [path1, path2, ...] or []
140
+ SCREEN_REF_PATHS: [path1, path2, ...] or []
141
+ ```
142
+
143
+ Behaviour: proceed through Q2–Q5 once (for this single screen), then PHASE 0 → PHASE 1–9.
144
+
145
+ ---
146
+
147
+ #### If mode = module:
148
+
149
+ Ask:
150
+ > "What is the PascalCase name of the module? (e.g. `FdBooking`, `Portfolio`, `Onboarding`)
151
+ >
152
+ > How many screens does this module contain? List each screen name (PascalCase) and its design source.
153
+ > For each screen provide:
154
+ > - Screen name (PascalCase)
155
+ > - Spec MD file path (optional)
156
+ > - Existing screen ref path (optional)
157
+ >
158
+ > You must provide at least one source (MD file or screen ref) per screen."
159
+
160
+ **Collect:**
161
+ ```
162
+ GENERATION_MODE: module
163
+ MODULE_NAME: <PascalCase module name — e.g. FdBooking>
164
+ SCREENS: [
165
+ {
166
+ screenName: <PascalCase>,
167
+ specMdFiles: [path, ...] or [],
168
+ screenRefPaths: [path, ...] or []
169
+ },
170
+ ...
171
+ ]
172
+ ```
173
+
174
+ FATAL if `MODULE_NAME` not provided — re-ask.
175
+ FATAL if `SCREENS` list is empty — re-ask.
176
+ FATAL if any screen has neither `specMdFiles` nor `screenRefPaths` — re-ask for that screen.
177
+
178
+ Behaviour:
179
+ - **MD spec files**: read in PHASE 1 as the primary spec source per screen. The `Screen Name` field inside the MD overrides the interview screen name only if different.
180
+ - **Screen paths**: read in PHASE 0 step 0.L. Mirror component structure, StyleSheet, imports. Do NOT generate new layout — replicate existing pattern.
181
+ - Q2–Q5 are collected **per screen** (see below).
182
+
183
+ ---
184
+
185
+ > **IMPORTANT for both modes**: Figma URLs are NOT supported. Do not use any Figma MCP tools.
186
+ > If the user provides a Figma URL, ask them to provide an existing screen path or a filled spec MD file instead.
187
+
188
+ FATAL if no source provided for any screen — re-ask until resolved.
189
+
190
+ ---
191
+
192
+ > ### Module mode — Q2 through Q5 are collected PER SCREEN
193
+ >
194
+ > When `GENERATION_MODE = module`, after Q1 you MUST loop through each screen in
195
+ > `SCREENS[]` and ask Q2–Q5 for that screen before moving to the next.
196
+ >
197
+ > Display a clear heading before each screen's questions:
198
+ > ```
199
+ > ─── Screen N / Total: <ScreenName> ────────────────────────────────
200
+ > ```
201
+ >
202
+ > After collecting Q2–Q5 for ALL screens, proceed to the PHASE -1 Completion Gate.
203
+ > Do NOT skip any screen. Do NOT run PHASE 0 until every screen is fully answered.
204
+
205
+ ---
206
+
207
+ ### QUESTION 2 — User Stories
208
+
209
+ Ask the user:
210
+
211
+ > "Please provide the user stories for this feature. You can:
212
+ > - Paste user story text directly (e.g. 'As a user, I want to see my transactions so that I can track my spending')
213
+ > - Provide a file path to a user stories Markdown file
214
+ >
215
+ > User stories define WHAT the feature must do from the user's perspective and drive screen logic generation."
216
+
217
+ **Collect:**
218
+ ```
219
+ USER_STORIES_SOURCE: inline | file | none
220
+ USER_STORIES_FILE: <path or null>
221
+ USER_STORIES_TEXT: <inline text or null>
222
+ ```
223
+
224
+ Parse into structured entries:
225
+ ```
226
+ USER_STORIES: [
227
+ { id: "US-1", role: "<who>", action: "<wants to>", benefit: "<so that>" },
228
+ ...
229
+ ]
230
+ ```
231
+
232
+ Use user stories to:
233
+ - Drive screen logic completeness check in PHASE 7.3
234
+ - Validate implementation coverage in PHASE 10.6
235
+
236
+ WARN if not provided — log `WARN: No user stories provided. Screen logic will be derived from the spec MD file and Q5 API mapping only.` and continue.
237
+
238
+ ---
239
+
240
+ ### QUESTION 3 — Test Cases
241
+
242
+ Ask the user:
243
+
244
+ > "Please provide the test cases for this feature. You can:
245
+ > - Paste test case descriptions directly (e.g. 'When user has no transactions, show empty state')
246
+ > - Provide a file path to a test cases Markdown file
247
+ > - Provide paths to existing test files (*.test.ts, *.spec.ts)
248
+ >
249
+ > Test cases define expected behaviour and edge cases the implementation must satisfy."
250
+
251
+ **Collect:**
252
+ ```
253
+ TEST_CASES_SOURCE: inline | file | test-files | none
254
+ TEST_CASES_FILE: <path or null>
255
+ TEST_CASES_TEXT: <inline text or null>
256
+ TEST_FILE_PATHS: [path1, ...] or []
257
+ ```
258
+
259
+ Parse into structured entries:
260
+ ```
261
+ TEST_CASES: [
262
+ { id: "TC-1", given: "...", when: "...", then: "...", type: "happy | edge | error" },
263
+ ...
264
+ ]
265
+ ```
266
+
267
+ Use test cases to:
268
+ - Validate business logic guard clauses in PHASE 3.3
269
+ - Validate screen logic completeness in PHASE 7.3
270
+ - Drive PHASE 10.5 post-completion checks
271
+
272
+ WARN if not provided — log `WARN: No test cases provided. Post-completion validation will skip TC coverage.` and continue.
273
+
274
+ ---
275
+
276
+ ### QUESTION 4 — Business Logic
277
+
278
+ Ask the user:
279
+
280
+ > "Please describe ALL business logic rules for this feature. Include:
281
+ > - Validation rules (e.g. 'Amount must be greater than 0')
282
+ > - Domain constraints (e.g. 'Only show active accounts')
283
+ > - Derived values (e.g. 'Calculate net return as current value minus invested amount')
284
+ > - Error conditions (e.g. 'If Status is not success, treat the response as an error')
285
+ > - Any conditional behaviour driven by data values
286
+ >
287
+ > Be as specific and exhaustive as possible. Each rule becomes a guard clause in the use case. Do not leave rules implicit — state them explicitly."
288
+
289
+ **Collect:**
290
+ ```
291
+ BUSINESS_LOGIC_RULES: [
292
+ "<rule 1>",
293
+ "<rule 2>",
294
+ ...
295
+ ]
296
+ ```
297
+
298
+ FATAL if not provided AND no spec MD file from Q1 contains a Business Logic section. Re-ask until at least one rule is given.
299
+
300
+ ---
301
+
302
+ ### QUESTION 5 — API Details & Response Mapping
303
+
304
+ Ask the user:
305
+
306
+ > "Please provide the complete API details for this feature:
307
+ >
308
+ > **A. API Endpoint**
309
+ > - URL (e.g. `/api/v1/portfolio/transactions`)
310
+ > - HTTP Method (GET / POST / PUT / PATCH / DELETE)
311
+ >
312
+ > **B. Request Body**
313
+ > - Paste the exact JSON request body with field names and example values
314
+ > - Use the EXACT field names the API expects (including casing — PascalCase, camelCase, snake_case)
315
+ >
316
+ > **C. Response Shape**
317
+ > - Paste the exact JSON response structure with field names and example values
318
+ > - Include nested objects and arrays exactly as the API returns them
319
+ >
320
+ > **D. Response-to-UI Mapping**
321
+ > - For each response field you want displayed, describe WHERE and HOW it appears in the UI
322
+ > - Format: `ResponseField` → description of UI location and any formatting
323
+ > - Example: `Data[].FundName` → primary title of each list row
324
+ > - Example: `Data[].Amount` → below title, formatted as Indian currency (₹)
325
+ > - Example: `Data[].TransactionID` → unique key only, not displayed
326
+ >
327
+ > **E. Screen Logic**
328
+ > - Describe what happens on screen mount, user interactions, navigation, and conditional rendering
329
+ > - Example: 'Fetch data on screen mount'
330
+ > - Example: 'Support pull-to-refresh'
331
+ > - Example: 'Navigate to DetailScreen when user taps a row'
332
+ > - Example: 'Show empty state message when list is empty'
333
+ > - Example: 'Show loading skeleton while fetching'
334
+ >
335
+ > Provide the actual field names from the API exactly as they appear. Do not rename or guess."
336
+
337
+ **Collect:**
338
+ ```
339
+ API_URL: <endpoint path>
340
+ HTTP_METHOD: GET | POST | PUT | PATCH | DELETE
341
+ REQUEST_BODY: <JSON object — exact API field names>
342
+ RESPONSE_SHAPE: <JSON object — exact API field names and example values>
343
+ RESPONSE_MAPPINGS: [
344
+ { responseField: "Data[].FundName", uiLocation: "primary title of each row", transform: null },
345
+ { responseField: "Data[].Amount", uiLocation: "below title", transform: "format as Indian currency" },
346
+ ...
347
+ ]
348
+ SCREEN_LOGIC: [
349
+ "<behavior 1>",
350
+ "<behavior 2>",
351
+ ...
352
+ ]
353
+ ```
354
+
355
+ FATAL if `API_URL` or `HTTP_METHOD` not provided — re-ask until both are given.
356
+ WARN if `RESPONSE_SHAPE` not provided — generate empty entity and log WARN.
357
+ WARN if `RESPONSE_MAPPINGS` not provided — generate screen without field bindings and log WARN.
358
+ WARN if `SCREEN_LOGIC` not provided — generate screen with fetch-on-mount only and log WARN.
359
+
360
+ ---
361
+
362
+ ### PHASE -1 Completion Gate
363
+
364
+ Before proceeding to PHASE 0, confirm all items:
365
+
366
+ **Single mode checklist:**
367
+ ```
368
+ [ ] Q1: SCREEN_NAME provided AND at least one design source provided (MD spec file or existing screen path — NO Figma)
369
+ [ ] Q2: User stories collected — or WARN logged if skipped
370
+ [ ] Q3: Test cases collected — or WARN logged if skipped
371
+ [ ] Q4: At least one business logic rule provided
372
+ [ ] Q5: API URL, HTTP method, response shape, and mappings provided
373
+ ```
374
+
375
+ **Module mode checklist (repeat per screen):**
376
+ ```
377
+ [ ] Q1: MODULE_NAME provided AND SCREENS[] list has at least one entry, each with a design source
378
+ For each screen in SCREENS[]:
379
+ [ ] Q2: User stories collected for <ScreenName> — or WARN logged
380
+ [ ] Q3: Test cases collected for <ScreenName> — or WARN logged
381
+ [ ] Q4: At least one business logic rule for <ScreenName>
382
+ [ ] Q5: API URL, HTTP method, response shape, and mappings for <ScreenName>
383
+ ```
384
+
385
+ - If any FATAL condition is unmet: stop and re-ask only that specific question (and screen if module mode).
386
+ - If only WARNs are outstanding: proceed with WARN flags recorded.
387
+ - Do NOT proceed if any question is unanswered without a WARN or FATAL resolution.
388
+
389
+ **Merge all collected answers into FeatureSpec(s)** used in PHASE 1.2.
390
+
391
+ - In **single** mode: one `FeatureSpec` is built. Interview answers take precedence over spec MD file values.
392
+ - In **module** mode: one `FeatureSpec` is built **per screen**. Each screen's interview answers take precedence over its spec MD file. The module name is stored as `MODULE_NAME` and is shared across all specs.
393
+
394
+ `SCREEN_LOGIC` from Q5E is merged into `spec.screenLogic[]` and is the primary source for Phases 5 and 7.3.
395
+ `BUSINESS_LOGIC_RULES` from Q4 is merged into `spec.businessLogic[]` and is the primary source for Phase 3.3.
396
+
397
+ ---
398
+
399
+ ## PHASE 0 — Repository Intelligence
400
+
401
+ > **Run this phase completely before touching the spec file.**
402
+ > Every path, import, and naming decision in all later phases is derived from
403
+ > the fingerprint built here. If detection of any dimension is uncertain,
404
+ > record it as `[INFERRED]` and log a WARN — never silently guess.
405
+
406
+ ---
407
+
408
+ ### 0.A — Locate App Root
409
+
410
+ Do NOT assume the source lives in `src/`. Crawl the repository root looking
411
+ for the file that anchors the React Native app entry point.
412
+
413
+ **Algorithm — run in order, stop at first match:**
414
+
415
+ ```
416
+ 1. Find files named: App.tsx, App.ts, App.jsx, App.js, index.tsx, index.ts,
417
+ index.js (in that priority)
418
+ 2. Among matches, pick the one whose directory ALSO contains at least one of:
419
+ package.json tsconfig.json babel.config.js metro.config.js
420
+ 3. The directory of that anchor file is APP_ROOT
421
+ 4. Walk up from APP_ROOT to find the nearest package.json whose
422
+ "dependencies" or "devDependencies" contains "react-native"
423
+ 5. The directory of that package.json is REPO_ROOT
424
+ ```
425
+
426
+ Record:
427
+ ```
428
+ REPO_ROOT: <absolute path>
429
+ APP_ROOT: <absolute path> (may equal REPO_ROOT or be a subfolder like src/, app/, mobile/)
430
+ APP_ROOT_RELATIVE: <path relative to REPO_ROOT>
431
+ ```
432
+
433
+ FATAL if no React Native anchor can be found.
434
+
435
+ ---
436
+
437
+ ### 0.B — Detect Feature Organisation Style
438
+
439
+ Scan every directory under `APP_ROOT` (max depth: 6 levels). Do not look for
440
+ specific folder names — count and classify what actually exists.
441
+
442
+ **Classification algorithm:**
443
+
444
+ ```
445
+ FEATURE_FIRST clues:
446
+ - One directory per product feature at the same level
447
+ - Each feature directory contains at least two of:
448
+ screens/, components/, hooks/, services/, store/, state/, api/
449
+ - Examples found: features/, modules/, pages/, domains/
450
+
451
+ LAYER_FIRST clues:
452
+ - Root-level directories named after layers, not features
453
+ - Look for: screens/, components/, redux/, store/, services/, hooks/
454
+ existing at the same level under APP_ROOT
455
+ - Features are identified by file name prefix (e.g., AuthScreen.tsx)
456
+
457
+ EXPO_ROUTER clues:
458
+ - Directory named: app/ containing (tabs)/ or route files
459
+ - File-system based routing patterns: [id].tsx, (auth)/ groups
460
+
461
+ DOMAIN_DRIVEN clues:
462
+ - Top-level: domain/, data/, presentation/ at same level
463
+
464
+ ATOMIC clues:
465
+ - Top-level: atoms/, molecules/, organisms/ at same level
466
+
467
+ MONOREPO clues:
468
+ - packages/ directory with multiple sub-packages each containing package.json
469
+ ```
470
+
471
+ If multiple signals are mixed (common in real projects), record the dominant
472
+ one and all secondary patterns:
473
+
474
+ ```
475
+ FEATURE_STYLE: feature-first ← dominant
476
+ FEATURE_STYLE_SECONDARY: layer-mixed ← if some layers leak to root
477
+ FEATURES_ROOT: <path relative to APP_ROOT where feature directories live>
478
+ FEATURE_DIR_SAMPLE: [portfolio, auth, dashboard, ...] ← 3-5 example names
479
+ ```
480
+
481
+ **Greenfield / fallback detection:**
482
+
483
+ Run the following decision tree after the normal classification above:
484
+
485
+ ```
486
+ STEP 1 — Check for existing layer-first directories under APP_ROOT:
487
+ Look for ANY of these directory names at the top level of APP_ROOT:
488
+ screens/, screen/, views/, pages/
489
+ store/, redux/, state/
490
+ services/, api/, network/
491
+
492
+ If 2 or more of the above exist:
493
+ → LAYER_FIRST_EXISTING: true
494
+ → FEATURE_STYLE: layer-first (override any earlier classification)
495
+ → GREENFIELD: false
496
+ Record the actual folder names found:
497
+ LAYER_FIRST_SCREENS_DIR: <actual name, e.g. screens/>
498
+ LAYER_FIRST_SERVICES_DIR: <actual name, e.g. services/>
499
+ LAYER_FIRST_STATE_DIR: <actual name, e.g. store/>
500
+ LAYER_FIRST_STATE_SLICES_DIR: <actual subfolder for slices, e.g. store/slices/ or store/>
501
+ Log: INFO: Layer-first project structure detected. Files will be placed in existing layer directories.
502
+
503
+ STEP 2 — If LAYER_FIRST_EXISTING is false AND FEATURE_DIR_SAMPLE is empty:
504
+ → GREENFIELD: true
505
+ → FEATURE_STYLE: feature-first
506
+ → FEATURES_ROOT: features/
507
+ → FEATURE_DIR_SAMPLE: []
508
+ Log: INFO: No existing feature structure detected. Falling back to canonical clean-architecture default.
509
+
510
+ STEP 3 — Otherwise:
511
+ → GREENFIELD: false
512
+ → Use FEATURE_STYLE and FEATURES_ROOT as classified above.
513
+ ```
514
+
515
+ In LAYER_FIRST_EXISTING mode:
516
+ - Phase 0.C layer scanning is adapted — scan the detected layer directories, NOT feature sub-folders.
517
+ - Phase 0.K.1 applies the LAYER_FIRST default map.
518
+ - `FEATURES_ROOT` is set to `null` — there is no single features root.
519
+
520
+ In GREENFIELD mode:
521
+ - Phase 0.C layer scanning is skipped entirely.
522
+ - Phase 0.K.1 applies the FEATURE_FIRST default map.
523
+ - Log: `INFO: No existing feature structure detected. Falling back to canonical default layer map.`
524
+
525
+ ---
526
+
527
+ ### 0.C — Infer Architectural Layers Per Feature
528
+
529
+ Scan **ALL** detected feature directories, not just one. Walk each and map its
530
+ layer structure. When the same layer uses different folder names across features
531
+ (e.g., `domain/models` vs `domain/entities`), record all variants and emit a WARN.
532
+
533
+ Also detect the DI wiring pattern used by each feature.
534
+
535
+ **Layer inference algorithm (run for every feature directory):**
536
+
537
+ ```
538
+ For each subfolder in a feature directory:
539
+ - Contains interfaces/types only → DOMAIN or TYPES layer
540
+ - Contains *Repository* files → REPOSITORY layer (domain or data)
541
+ - Contains *UseCase* or *Service* files → USE_CASE layer
542
+ - Contains *Slice* or *Store* or *Reducer* → STATE layer
543
+ - Contains *DataSource* or *Api* or *Remote* → DATA_SOURCE layer
544
+ - Contains *Screen* or *Page* or *View* → PRESENTATION layer
545
+ - Contains *Mapper* or *Transformer* → MAPPER layer
546
+ - Contains *.mock.json* or mock files → MOCK layer
547
+ - Contains *Selector* or *Query* → SELECTOR layer
548
+ - Named 'di/' and contains *container* or *bootstrap* → DI layer
549
+ ```
550
+
551
+ **DI pattern detection (run per feature):**
552
+
553
+ ```
554
+ Look for a file at feature root named diBootstrap.ts or diBootstrap.js:
555
+ → DI_STYLE: per-feature-bootstrap
556
+ Record: bootstrapFile = "diBootstrap.ts"
557
+ Note: exports named singleton instances consumed via ThunkExtra or direct import
558
+
559
+ Look for a directory named di/ whose files contain class.*Container or getInstance(:
560
+ → DI_STYLE: per-feature-container
561
+ Record: containerFile = "di/container.ts" (or actual path)
562
+ Record: containerClass = detected class name (e.g. "ReportsContainer")
563
+
564
+ Look for a top-level shared DI / IoC file outside all feature directories:
565
+ → DI_STYLE: global
566
+
567
+ If none found:
568
+ → DI_STYLE: none
569
+ ```
570
+
571
+ If features use different DI styles, record all. When generating, use the style
572
+ of the existing feature most similar to the new one.
573
+
574
+ Record actual folder names, not assumed names. When names differ across features,
575
+ record the dominant value AND all alternatives:
576
+
577
+ ```
578
+ LAYER_MAP: {
579
+ domain: "domain"
580
+ domainModels: "domain/models" (variants: ["domain/models","domain/entities"])
581
+ domainRepo: "domain/repositories"
582
+ useCases: "domain/useCases" (variants: ["domain/usecases","domain/useCases"])
583
+ data: "data"
584
+ dataSource: "data/datasources" (variants: ["data/datasources","data/api"])
585
+ repoImpl: "data/repositories" (variants: ["data/repositories","data/repositoryImpl"])
586
+ dtos: "data/dtos" (or null when absent in all features)
587
+ mappers: "data/mappers"
588
+ mocks: "data/datasources/__mocks__" (or nearest mock folder)
589
+ state: "state" (or null when absent — e.g. Context-API features)
590
+ stateStore: "state/store" (or null)
591
+ selectors: "state/selectors" (or null)
592
+ presentation: "presentation"
593
+ screens: "presentation/screens"
594
+ di: "di" (or null — only present for per-feature-container style)
595
+ }
596
+ ```
597
+
598
+ If a layer is absent in ALL scanned features, mark it `null` and skip generation.
599
+
600
+ **Selecting the representative layer map for generation:**
601
+
602
+ ```
603
+ When LAYER_MAP has variants:
604
+ 1. If the new feature name or spec hints at resemblance to an existing feature, use
605
+ that feature's exact layer paths.
606
+ 2. Otherwise, use the layer paths from the most complete feature (most non-null layers).
607
+ 3. Log a WARN for every layer where a variant was not chosen.
608
+ ```
609
+
610
+ **Greenfield / Layer-first override:**
611
+
612
+ If `GREENFIELD = true`:
613
+ - Skip all layer scanning above.
614
+ - Set every LAYER_MAP field to `[DEFAULT]` placeholder.
615
+ - Phase 0.K.1-A will replace them with the canonical feature-first defaults.
616
+ - Do NOT emit WARNs for missing layers.
617
+
618
+ If `LAYER_FIRST_EXISTING = true`:
619
+ - Skip feature-directory layer scanning above (there are no feature sub-folders to scan).
620
+ - Instead, read 2–3 existing files from each detected layer directory
621
+ (`LAYER_FIRST_SCREENS_DIR`, `LAYER_FIRST_SERVICES_DIR`, `LAYER_FIRST_STATE_DIR`) to
622
+ detect naming conventions (file name style, export style, import paths).
623
+ - Set LAYER_MAP fields using the detected actual folder names.
624
+ - Phase 0.K.1-B will fill any remaining `[DEFAULT]` placeholders.
625
+ - Do NOT emit WARNs for absent domain/repository/useCase layers — they are intentionally absent.
626
+
627
+ **Depth calculation:** Count directory segments from `APP_ROOT` to the deepest
628
+ layer folder. This determines the import prefix needed to reach shared
629
+ utilities.
630
+
631
+ ```
632
+ Example:
633
+ APP_ROOT = src/
634
+ datasource file = src/features/portfolio/data/datasources/File.ts
635
+ Depth from APP_ROOT = 4 (features → portfolio → data → datasources)
636
+ Import prefix to APP_ROOT = ../../../../
637
+
638
+ Record:
639
+ MAX_LAYER_DEPTH: 4
640
+ IMPORT_PREFIX_TO_APP_ROOT: ../../../../
641
+ ```
642
+
643
+ ---
644
+
645
+ ### 0.D — Locate Shared / Common Utilities
646
+
647
+ Do NOT assume a `shared/` folder. Scan for directories used by multiple
648
+ features as imports.
649
+
650
+ **Algorithm:**
651
+
652
+ ```
653
+ 1. Pick 3-5 feature files from Step 0.C
654
+ 2. Read their import statements
655
+ 3. Identify import paths that:
656
+ - Appear in more than one feature
657
+ - Are NOT from node_modules
658
+ - Point to a common ancestor directory
659
+ 4. That common ancestor directory is SHARED_ROOT
660
+ 5. Record the actual folder name (shared, common, core, utils, lib, etc.)
661
+ ```
662
+
663
+ Record:
664
+ ```
665
+ SHARED_ROOT: <path relative to APP_ROOT> e.g. shared/, common/, core/
666
+ SHARED_ROOT_ALIAS: <alias if used> e.g. @shared, @/shared, ~/shared, or null
667
+ SHARED_API_DIR: <subfolder under SHARED_ROOT containing API client>
668
+ SHARED_TYPES_DIR: <subfolder under SHARED_ROOT containing shared types>
669
+ SHARED_STORE_DIR: <subfolder under SHARED_ROOT containing store config>
670
+ ```
671
+
672
+ For each layer file generated later, compute:
673
+ ```
674
+ IMPORT_PREFIX_TO_SHARED = repeat("../", depth_of_file_from_APP_ROOT) + SHARED_ROOT
675
+ ```
676
+
677
+ If `SHARED_ROOT_ALIAS` is non-null, use the alias directly instead of relative
678
+ path (see 0.G for alias detection).
679
+
680
+ ---
681
+
682
+ ### 0.E — API Layer Discovery
683
+
684
+ Do NOT look in a specific folder. Search the entire repository.
685
+
686
+ **Search for API client instantiation patterns:**
687
+
688
+ ```
689
+ Pattern A — Axios:
690
+ Search: axios.create(
691
+ Files found → AXIOS_CLIENT_FILES
692
+
693
+ Pattern B — Fetch wrapper:
694
+ Search: fetch( OR window.fetch(
695
+ Combined with response.json() → FETCH_WRAPPER_FILES
696
+
697
+ Pattern C — RTK Query:
698
+ Search: createApi(
699
+ Files found → RTK_QUERY_FILES
700
+
701
+ Pattern D — React Query / TanStack Query:
702
+ Search: useQuery( OR useMutation( OR QueryClient
703
+ Files found → REACT_QUERY_FILES
704
+
705
+ Pattern E — Apollo / GraphQL:
706
+ Search: ApolloClient OR gql` OR useQuery from @apollo
707
+ Files found → APOLLO_FILES
708
+
709
+ Pattern F — Other (ky, superagent, got):
710
+ Search: import ky OR require('ky') etc.
711
+ ```
712
+
713
+ For the detected API library:
714
+ - Record the exact file path(s) of the shared client instance
715
+ - Read those files and extract: base URL, headers, interceptors, retry logic,
716
+ token injection pattern
717
+ - Record the exact import statement used by existing feature files to reach the
718
+ client
719
+
720
+ **Envelope / Request Shape Detection:**
721
+
722
+ Read 3-5 existing API call sites. Examine the request body structure passed to
723
+ the client:
724
+
725
+ ```
726
+ If body is wrapped: { mb: { operationId, rq: { reqdata: {} } } }
727
+ → ENVELOPE_STYLE: mb-operationId
728
+ → ENVELOPE_BUILDER: detect if a buildEnvelope() helper exists or is inlined
729
+
730
+ If body is plain: { key: value, key2: value2 }
731
+ → ENVELOPE_STYLE: none
732
+
733
+ If body follows another wrapper pattern → record exact shape
734
+ ```
735
+
736
+ **Return type pattern detection:**
737
+
738
+ Read 3–5 existing repository interface files. Examine the return types of their methods:
739
+
740
+ ```
741
+ If return types are Promise<{ ok: boolean; data?: T; error?: string }>
742
+ → RETURN_TYPE_STYLE: result-wrapper
743
+ Record: RESULT_TYPE_IMPORT = <exact import string for the Result type>
744
+
745
+ If return types are Promise<CustomNamedType> where CustomNamedType is defined in the
746
+ same feature's domain layer (e.g. Promise<PortfolioSummaryResult>):
747
+ → RETURN_TYPE_STYLE: custom-type
748
+ Record: no shared Result import needed
749
+
750
+ If return types are direct: Promise<T[]> or Promise<T> with no wrapper:
751
+ → RETURN_TYPE_STYLE: direct-promise
752
+ Record: no wrapper — throws on error instead of returning { ok: false }
753
+ ```
754
+
755
+ This field controls how Phase 3.2, 4.7, and 5.1 generate the repository interface,
756
+ implementation, and thunk error handling respectively.
757
+
758
+ **Mock / Stub Detection:**
759
+
760
+ ```
761
+ Search for: mockEnabled OR globalMockEnabled OR mock.config OR msw OR nock
762
+ If found → record file path, exact shape, evaluation order
763
+ ```
764
+
765
+ Record:
766
+ ```
767
+ API_LIB: axios | fetch | rtk-query | react-query | apollo | other
768
+ API_CLIENT_FILE: <exact path to shared client file>
769
+ API_CLIENT_IMPORT: <exact import string used by feature files>
770
+ ENVELOPE_STYLE: mb-operationId | mb-operationid-lowercase | none | <other>
771
+ ENVELOPE_BUILDER: <function name and file, or "inline">
772
+ MOCK_SYSTEM: mockConfig | msw | none
773
+ MOCK_CONFIG_FILE: <path or null>
774
+ MOCK_GLOBAL_FLAG: globalMockEnabled | <other field name> | null
775
+ MOCK_DELAY_FIELD: simulatedDelayMs | <other field name> | null
776
+ MOCK_JSON_FOLDER: <path pattern for mock JSON files, relative to datasource>
777
+ RETURN_TYPE_STYLE: result-wrapper | custom-type | direct-promise
778
+ RESULT_TYPE_IMPORT: <exact import string for Result type, or null>
779
+ ```
780
+
781
+ ---
782
+
783
+ ### 0.F — State Management Discovery
784
+
785
+ Search the entire repository (not just specific folders).
786
+
787
+ **Search for state library signatures:**
788
+
789
+ ```
790
+ createSlice( → redux-toolkit
791
+ createAsyncThunk( → redux-toolkit
792
+ configureStore( → redux-toolkit (store config)
793
+ createReducer( → redux-toolkit or plain redux
794
+ create( → zustand (if imported from 'zustand')
795
+ makeAutoObservable( → mobx
796
+ observable( → mobx
797
+ useReducer( → context-api (if paired with createContext)
798
+ createContext( → context-api
799
+ QueryClient → react-query / tanstack-query
800
+ ```
801
+
802
+ Record all matches. If multiple libraries exist, note which features use which.
803
+ For the dominant library, detect the injection/sharing pattern:
804
+
805
+ **For Redux Toolkit — detect thunk injection style:**
806
+
807
+ ```
808
+ Search async thunks for:
809
+ Pattern A (ThunkExtra): async (params, { extra, rejectWithValue }) => {
810
+ const { someUseCase } = extra as { ... }
811
+ → THUNK_PATTERN: thunk-extra
812
+
813
+ Pattern B (Direct import): import { someUseCase } from '...'
814
+ async (params, { rejectWithValue }) => {
815
+ → THUNK_PATTERN: direct-import
816
+
817
+ Pattern C (RTK Query): endpoints builder pattern
818
+ → THUNK_PATTERN: rtk-query
819
+ ```
820
+
821
+ **For Redux — locate the store configuration:**
822
+
823
+ ```
824
+ Search for configureStore( call
825
+ Read that file to find:
826
+ - middleware / extra argument → confirm ThunkExtra injection
827
+ - reducer map keys → these become slice name constraints
828
+ - The RootState type definition file / export
829
+ ```
830
+
831
+ Record:
832
+ ```
833
+ STATE_LIB: redux-toolkit | zustand | mobx | context-api | react-query | other
834
+ THUNK_PATTERN: thunk-extra | direct-import | rtk-query | n/a
835
+ STORE_CONFIG_FILE: <path to configureStore call>
836
+ ROOT_STATE_TYPE_FILE: <path where RootState is exported>
837
+ ROOT_STATE_IMPORT: <exact import string to reach RootState from a selector file>
838
+ SLICE_NAME_STYLE: camelCase | kebab-case (from existing slice name strings)
839
+ REDUCER_MAP_KEYS: [portfolio, auth, ...] (existing keys in combineReducers/configureStore)
840
+ ```
841
+
842
+ ---
843
+
844
+ ### 0.G — Import Alias Detection
845
+
846
+ Import aliases are critical — generated code MUST use the same alias style,
847
+ otherwise it will fail to compile.
848
+
849
+ **Search in order:**
850
+
851
+ ```
852
+ 1. tsconfig.json or tsconfig.base.json → paths: { "@/*": ["./src/*"], ... }
853
+ 2. babel.config.js or babel.config.ts → module-resolver plugin aliases
854
+ 3. metro.config.js → resolver.extraNodeModules or resolver.alias
855
+ 4. package.json → imports field (Node.js subpath imports)
856
+ 5. jsconfig.json → paths
857
+ ```
858
+
859
+ For each alias found, record:
860
+ ```
861
+ ALIAS_MAP: {
862
+ "@": "src/",
863
+ "@shared": "src/shared/",
864
+ "~": "./",
865
+ "@app": "app/",
866
+ ...
867
+ }
868
+ ```
869
+
870
+ Then, for each shared import generated later: prefer the longest matching alias
871
+ over a relative path. If no alias matches, use the computed relative path from
872
+ Step 0.D.
873
+
874
+ Record:
875
+ ```
876
+ ALIASES_DETECTED: true | false
877
+ ALIAS_MAP: { ... } or {}
878
+ PREFER_ALIASES: true | false (true if existing feature files use aliases)
879
+ ```
880
+
881
+ ---
882
+
883
+ ### 0.H — Navigation Discovery
884
+
885
+ ```
886
+ Search for:
887
+ @react-navigation/native → REACT_NAVIGATION, detect version from package.json
888
+ expo-router → EXPO_ROUTER
889
+ react-native-navigation (wix) → WIX_NAVIGATION
890
+ react-native-screens → (supporting library, not primary)
891
+
892
+ For React Navigation — detect version:
893
+ package.json "@react-navigation/native": "^6.x" → v6
894
+ package.json "@react-navigation/native": "^5.x" → v5
895
+ package.json "@react-navigation/native": "^7.x" → v7
896
+
897
+ For React Navigation — detect stack type used:
898
+ Search: createNativeStackNavigator OR createStackNavigator OR createBottomTabNavigator
899
+ Read 1-2 screen registration files to see how screens are added
900
+
901
+ For Expo Router — detect routing pattern:
902
+ Read app/ directory structure to understand route groups
903
+ ```
904
+
905
+ Record:
906
+ ```
907
+ NAV_LIB: react-navigation | expo-router | wix-navigation | none
908
+ NAV_VERSION: 6 | 5 | 7 | n/a
909
+ NAV_STACK_TYPE: native-stack | stack | bottom-tab | n/a
910
+ NAV_SCREEN_FILE: <path to main navigator file where screens are registered>
911
+ NAV_PARAMS_PATTERN: <how params are typed — RootStackParamList, RouteParams, etc.>
912
+ ```
913
+
914
+ ---
915
+
916
+ ### 0.I — Type System & Code Quality Discovery
917
+
918
+ ```
919
+ Read tsconfig.json:
920
+ compilerOptions.strict → TS_STRICT: true | false
921
+ compilerOptions.noImplicitAny → NO_IMPLICIT_ANY: true | false
922
+ compilerOptions.strictNullChecks → STRICT_NULL_CHECKS: true | false
923
+
924
+ Read .eslintrc.* or eslint.config.*:
925
+ Record any rules that affect generated code:
926
+ - no-explicit-any
927
+ - @typescript-eslint/explicit-function-return-type
928
+ - import/order
929
+
930
+ Read .prettierrc or prettier.config.*:
931
+ Record: singleQuote, tabWidth, trailingComma, semi
932
+
933
+ Read package.json scripts:
934
+ Detect test runner: jest | vitest | mocha
935
+ Detect test pattern: *.test.ts | *.spec.ts | __tests__/*.ts
936
+ ```
937
+
938
+ Record:
939
+ ```
940
+ TS_STRICT: true | false
941
+ NO_IMPLICIT_ANY: true | false
942
+ STRICT_NULL_CHECKS: true | false
943
+ EXPLICIT_RETURN_TYPE: true | false (requires function return types)
944
+ QUOTE_STYLE: single | double
945
+ TRAILING_COMMA: es5 | all | none
946
+ SEMI: true | false
947
+ TAB_WIDTH: 2 | 4
948
+ TEST_RUNNER: jest | vitest | none
949
+ TEST_FILE_PATTERN: *.test.ts | *.spec.ts | __tests__/
950
+ ```
951
+
952
+ ---
953
+
954
+ ### 0.J — Naming Convention Discovery
955
+
956
+ Detect naming conventions from existing files — never assume.
957
+
958
+ ```
959
+ Read file names in FEATURES_ROOT:
960
+ All lowercase + hyphens: portfolioSlice.ts, portfolio-slice.ts
961
+ → FILE_NAME_STYLE: camelCase | kebab-case | PascalCase
962
+
963
+ Read class names in datasource files:
964
+ class PortfolioApiDataSource → CLASS_STYLE: PascalCase
965
+
966
+ Read interface/type names:
967
+ interface IPortfolioRepository → INTERFACE_PREFIX: I
968
+ interface PortfolioRepository → INTERFACE_PREFIX: none
969
+
970
+ Read existing operationId strings in envelope calls:
971
+ 'GetPortfolioSummary' → OPERATION_ID_STYLE: PascalCase with Get prefix
972
+ 'portfolio/fetchSummary' → OPERATION_ID_STYLE: path-style
973
+
974
+ Read mock JSON file names:
975
+ portfolioSummary.mock.json → MOCK_JSON_STYLE: camelCase.mock.json
976
+ portfolio_summary_mock.json → MOCK_JSON_STYLE: snake_case_mock.json
977
+
978
+ Read feature folder names:
979
+ portfolio/, transactionHistory/ → FEATURE_FOLDER_STYLE: camelCase
980
+ transaction-history/ → FEATURE_FOLDER_STYLE: kebab-case
981
+ ```
982
+
983
+ Record:
984
+ ```
985
+ FILE_NAME_STYLE: camelCase | kebab-case | PascalCase
986
+ CLASS_STYLE: PascalCase
987
+ INTERFACE_PREFIX: I | none
988
+ OPERATION_ID_STYLE: PascalCase-Get | path-style | camelCase
989
+ MOCK_JSON_STYLE: <detected pattern>
990
+ FEATURE_FOLDER_STYLE: camelCase | kebab-case
991
+ ```
992
+
993
+ ---
994
+
995
+ ### 0.K — Build the Architecture Fingerprint
996
+
997
+ Consolidate all Phase 0 findings into a single, structured fingerprint. This
998
+ fingerprint is the **only** source of truth for all file paths, import strings,
999
+ naming, and patterns used in Phases 1–7.
1000
+
1001
+ ```json
1002
+ {
1003
+ "repoRoot": "<absolute path>",
1004
+ "appRoot": "<absolute path>",
1005
+ "appRootRelative": "src/",
1006
+
1007
+ "featureStyle": "feature-first | layer-first | expo-router | domain-driven | atomic",
1008
+ "featuresRoot": "<path relative to appRoot where features live>",
1009
+ "featureDirSample": ["portfolio", "auth", "dashboard"],
1010
+
1011
+ "layerMap": {
1012
+ "domain": "<actual folder name or null>",
1013
+ "domainModels": "<actual path segment or null>",
1014
+ "domainRepo": "<actual path segment or null>",
1015
+ "useCases": "<actual path segment or null>",
1016
+ "data": "<actual folder name or null>",
1017
+ "dataSource": "<actual path segment or null>",
1018
+ "dtos": "<actual path segment or null>",
1019
+ "mappers": "<actual path segment or null>",
1020
+ "mocks": "<actual path segment or null>",
1021
+ "state": "<actual folder name or null>",
1022
+ "stateStore": "<actual path segment or null>",
1023
+ "selectors": "<actual path segment or null>",
1024
+ "presentation": "<actual folder name or null>",
1025
+ "screens": "<actual path segment or null>"
1026
+ },
1027
+
1028
+ "maxLayerDepth": 4,
1029
+ "importPrefixToAppRoot": "../../../../",
1030
+
1031
+ "sharedRoot": "<path relative to appRoot>",
1032
+ "sharedRootAlias": "@shared | null",
1033
+ "sharedApiDir": "<path relative to appRoot>",
1034
+ "sharedTypesDir": "<path relative to appRoot>",
1035
+ "sharedStoreDir": "<path relative to appRoot>",
1036
+
1037
+ "aliasesDetected": true,
1038
+ "aliasMap": { "@": "src/", "@shared": "src/shared/" },
1039
+ "preferAliases": true,
1040
+
1041
+ "apiLib": "axios | fetch | rtk-query | react-query | apollo | other",
1042
+ "apiClientFile": "<absolute path>",
1043
+ "apiClientImport": "<exact import string>",
1044
+ "envelopeStyle": "mb-operationId | none | <other>",
1045
+ "envelopeBuilder": "<function name> | inline | null",
1046
+ "mockSystem": "mockConfig | msw | none",
1047
+ "mockConfigFile": "<path or null>",
1048
+ "mockGlobalFlag": "globalMockEnabled | <other> | null",
1049
+ "mockDelayField": "simulatedDelayMs | <other> | null",
1050
+ "mockJsonFolder": "<path pattern relative to datasource file>",
1051
+
1052
+ "stateLib": "redux-toolkit | zustand | mobx | context-api | react-query | other",
1053
+ "thunkPattern": "thunk-extra | direct-import | rtk-query | n/a",
1054
+ "storeConfigFile": "<path>",
1055
+ "rootStateTypeFile": "<path>",
1056
+ "rootStateImport": "<exact import string>",
1057
+ "sliceNameStyle": "camelCase | kebab-case",
1058
+ "reducerMapKeys": ["portfolio", "auth"],
1059
+ "reducerKey": "<sliceName — single mode only; null in module mode (each screen derives its own reducerKey in Phase 1.4)>",
1060
+
1061
+ "navLib": "react-navigation | expo-router | wix-navigation | none",
1062
+ "navVersion": "6 | 5 | 7 | n/a",
1063
+ "navStackType": "native-stack | stack | bottom-tab | n/a",
1064
+ "navScreenFile": "<path>",
1065
+ "navParamsPattern": "<RootStackParamList type name>",
1066
+
1067
+ "tsStrict": true,
1068
+ "noImplicitAny": true,
1069
+ "explicitReturnType": false,
1070
+ "quoteStyle": "single",
1071
+ "trailingComma": "es5",
1072
+ "semi": true,
1073
+ "tabWidth": 2,
1074
+ "testRunner": "jest | vitest | none",
1075
+ "testFilePattern": "*.test.ts",
1076
+
1077
+ "fileNameStyle": "camelCase | kebab-case | PascalCase",
1078
+ "classStyle": "PascalCase",
1079
+ "interfacePrefix": "I | none",
1080
+ "operationIdStyle": "PascalCase-Get | path-style | camelCase",
1081
+ "mockJsonStyle": "<pattern>",
1082
+ "featureFolderStyle": "camelCase | kebab-case",
1083
+
1084
+ "diStyle": "per-feature-bootstrap | per-feature-container | global | none",
1085
+ "diBootstrapFile": "<path relative to feature root, or null>",
1086
+ "diContainerFile": "<path relative to feature root, or null>",
1087
+ "diContainerClass": "<class name, or null>",
1088
+
1089
+ "returnTypeStyle": "result-wrapper | custom-type | direct-promise",
1090
+ "resultTypeImport": "<exact import string for Result type, or null>",
1091
+ "repoReturnWrapper": "<custom type name if returnTypeStyle=custom-type, or null>",
1092
+
1093
+ "layerMapVariants": {
1094
+ "domainModels": ["domain/models"],
1095
+ "dataSource": ["data/datasources"],
1096
+ "repoImpl": ["data/repositories"]
1097
+ },
1098
+
1099
+ "screenRefPatterns": [
1100
+ {
1101
+ "file": "<relative path>",
1102
+ "scrollContainer": "FlatList | ScrollView",
1103
+ "styleNames": ["container", "header", "listItem"],
1104
+ "sharedComponents": ["AppHeader", "PrimaryButton"],
1105
+ "navHook": "useNavigation | useRouter | none",
1106
+ "stateHooks": ["useSelector", "useDispatch"],
1107
+ "earlyReturnOrder": ["isLoading", "isAuthError", "error"],
1108
+ "listItemLayout": "<brief description>"
1109
+ }
1110
+ ]
1111
+ }
1112
+ ```
1113
+
1114
+ Print the complete fingerprint before proceeding. If any field is `[INFERRED]`,
1115
+ it must be visually flagged. Do not proceed to Phase 1 if more than 3
1116
+ FATAL-tier fields are unresolved.
1117
+
1118
+ ---
1119
+
1120
+ ### 0.K.1 — Default Fingerprint (No Existing Structure)
1121
+
1122
+ Apply this section when `GREENFIELD = true` OR `LAYER_FIRST_EXISTING = true`.
1123
+ Choose the appropriate sub-section based on the flag.
1124
+
1125
+ ---
1126
+
1127
+ #### A — Feature-First Default (`GREENFIELD = true`)
1128
+
1129
+ No project structure exists at all. Generate a canonical clean-architecture
1130
+ feature-first layout under a `features/` root.
1131
+
1132
+ ```json
1133
+ {
1134
+ "featuresRoot": "features",
1135
+ "featureFolderStyle": "camelCase",
1136
+ "fileNameStyle": "camelCase",
1137
+ "featureStyle": "feature-first",
1138
+
1139
+ "layerMap": {
1140
+ "domain": "domain",
1141
+ "domainModels": "domain/models",
1142
+ "domainRepo": "domain/repositories",
1143
+ "useCases": "domain/useCases",
1144
+ "data": "data",
1145
+ "dataSource": "data/datasources",
1146
+ "dtos": "data/dtos",
1147
+ "mappers": "data/mappers",
1148
+ "mocks": "data/datasources",
1149
+ "repoImpl": "data/repositories",
1150
+ "state": "state",
1151
+ "stateStore": "state/store",
1152
+ "selectors": "state/selectors",
1153
+ "presentation": "presentation",
1154
+ "screens": "presentation/screens",
1155
+ "di": null
1156
+ },
1157
+
1158
+ "diStyle": "per-feature-bootstrap",
1159
+ "diBootstrapFile": "diBootstrap.ts",
1160
+ "stateLib": "redux-toolkit",
1161
+ "thunkPattern": "thunk-extra",
1162
+ "returnTypeStyle": "result-wrapper",
1163
+ "resultTypeImport": null,
1164
+ "sliceNameStyle": "camelCase",
1165
+ "navLib": "react-navigation",
1166
+ "navVersion": "6",
1167
+ "navStackType": "native-stack",
1168
+ "apiLib": "axios",
1169
+ "envelopeStyle": "none",
1170
+ "mockSystem": "none",
1171
+ "mockGlobalFlag": null,
1172
+ "mockDelayField": null,
1173
+ "mockJsonFolder": "data/datasources",
1174
+ "tsStrict": true,
1175
+ "noImplicitAny": true,
1176
+ "explicitReturnType": false,
1177
+ "quoteStyle": "single",
1178
+ "trailingComma": "es5",
1179
+ "semi": true,
1180
+ "tabWidth": 2,
1181
+ "interfacePrefix": "none",
1182
+ "classStyle": "PascalCase",
1183
+ "operationIdStyle": "camelCase",
1184
+ "mockJsonStyle": "camelCase.mock.json",
1185
+ "aliasesDetected": false,
1186
+ "aliasMap": {},
1187
+ "preferAliases": false
1188
+ }
1189
+ ```
1190
+
1191
+ Folder layout produced (example — `fdBooking` module):
1192
+ ```
1193
+ features/
1194
+ fdBooking/
1195
+ domain/
1196
+ models/ ← entity interfaces
1197
+ repositories/ ← repository interfaces
1198
+ useCases/ ← use cases
1199
+ data/
1200
+ dtos/ ← DTOs
1201
+ mappers/ ← mappers
1202
+ datasources/ ← datasources, endpoints, mock JSON
1203
+ repositories/ ← repository implementations
1204
+ state/
1205
+ store/ ← Redux slices
1206
+ selectors/ ← selectors
1207
+ presentation/
1208
+ screens/ ← screen components
1209
+ diBootstrap.ts ← DI bootstrap (one per module)
1210
+ ```
1211
+
1212
+ Log: `INFO: Greenfield defaults applied. Generated structure will follow canonical clean-architecture layout.`
1213
+
1214
+ ---
1215
+
1216
+ #### B — Layer-First Default (`LAYER_FIRST_EXISTING = true`)
1217
+
1218
+ The project already has flat layer directories (e.g. `screens/`, `store/`, `services/`).
1219
+ No feature-scoped sub-folders exist. Place every generated file inside the existing
1220
+ layer directories, grouped only by a per-screen sub-folder under `screens/`.
1221
+
1222
+ All paths below are relative to `APP_ROOT`. Substitute the ACTUAL folder names
1223
+ detected in Phase 0.B (e.g. if services is named `api/`, use `api/` not `services/`).
1224
+
1225
+ ```json
1226
+ {
1227
+ "featuresRoot": null,
1228
+ "featureFolderStyle": "PascalCase",
1229
+ "fileNameStyle": "PascalCase",
1230
+ "featureStyle": "layer-first",
1231
+
1232
+ "layerMap": {
1233
+ "domain": null,
1234
+ "domainModels": null,
1235
+ "domainRepo": null,
1236
+ "useCases": null,
1237
+ "data": null,
1238
+ "dataSource": "<LAYER_FIRST_SERVICES_DIR>",
1239
+ "dtos": null,
1240
+ "mappers": null,
1241
+ "mocks": null,
1242
+ "repoImpl": null,
1243
+ "state": "<LAYER_FIRST_STATE_DIR>",
1244
+ "stateStore": "<LAYER_FIRST_STATE_SLICES_DIR>",
1245
+ "selectors": null,
1246
+ "presentation": "<LAYER_FIRST_SCREENS_DIR>",
1247
+ "screens": "<LAYER_FIRST_SCREENS_DIR>",
1248
+ "di": null
1249
+ },
1250
+
1251
+ "diStyle": "none",
1252
+ "diBootstrapFile": null,
1253
+ "stateLib": "redux-toolkit",
1254
+ "thunkPattern": "direct-import",
1255
+ "returnTypeStyle": "direct-promise",
1256
+ "resultTypeImport": null,
1257
+ "sliceNameStyle": "camelCase",
1258
+ "navLib": "react-navigation",
1259
+ "navVersion": "6",
1260
+ "navStackType": "native-stack",
1261
+ "apiLib": "axios",
1262
+ "envelopeStyle": "none",
1263
+ "mockSystem": "none",
1264
+ "mockGlobalFlag": null,
1265
+ "mockDelayField": null,
1266
+ "mockJsonFolder": null,
1267
+ "tsStrict": true,
1268
+ "noImplicitAny": true,
1269
+ "explicitReturnType": false,
1270
+ "quoteStyle": "single",
1271
+ "trailingComma": "es5",
1272
+ "semi": true,
1273
+ "tabWidth": 2,
1274
+ "interfacePrefix": "none",
1275
+ "classStyle": "PascalCase",
1276
+ "operationIdStyle": "camelCase",
1277
+ "mockJsonStyle": null,
1278
+ "aliasesDetected": false,
1279
+ "aliasMap": {},
1280
+ "preferAliases": false
1281
+ }
1282
+ ```
1283
+
1284
+ **Layer-first generation rules** (override Phases 3–7 defaults):
1285
+
1286
+ ```
1287
+ Phase 3 (Domain layer) — SKIP entirely. domain*, useCases* paths are null.
1288
+ Do NOT generate entity interfaces, repository interfaces, or use cases.
1289
+
1290
+ Phase 4 (Data layer) — Generate ONLY the service file:
1291
+ File: <LAYER_FIRST_SERVICES_DIR>/<featureName>Service.ts
1292
+ (e.g. services/fdBookingService.ts)
1293
+ Pattern: plain async functions exported directly (no class wrapper).
1294
+ Imports the shared API client (detected in Phase 0.E) directly.
1295
+ One exported function per API endpoint in the spec.
1296
+ Response types exported as named TypeScript interfaces in the same file.
1297
+ Skip: DTOs, mappers, mock JSON, endpoint constants, repoImpl.
1298
+
1299
+ Phase 5 (State layer) — Generate ONLY the slice file:
1300
+ File: <LAYER_FIRST_STATE_SLICES_DIR>/<featureSliceName>Slice.ts
1301
+ (e.g. store/slices/fdBookingSlice.ts)
1302
+ Thunk pattern: direct-import — import service functions at the top of the
1303
+ slice file, call them directly inside createAsyncThunk (no ThunkExtra).
1304
+ Return type: direct-promise — service throws on error; thunk wraps with
1305
+ rejectWithValue.
1306
+ One slice per module (not per screen). Name: <featureName>Slice.
1307
+ Skip: selectors file (select via useSelector inline in screen).
1308
+
1309
+ Phase 6 (DI Bootstrap) — SKIP entirely. diStyle is none.
1310
+
1311
+ Phase 7 (Presentation) — Generate screen folder inside existing screens dir:
1312
+ Folder: <LAYER_FIRST_SCREENS_DIR>/<ScreenName>/
1313
+ Files:
1314
+ <ScreenName>.tsx ← main screen component
1315
+ <ScreenName>Style.ts ← StyleSheet (if reference screen has a style file)
1316
+ <ScreenName>Tokens.ts ← design tokens (only if reference screen has one)
1317
+ Import slice from: <relative path to LAYER_FIRST_STATE_SLICES_DIR>/<featureSliceName>Slice
1318
+ Import service types from: <relative path to LAYER_FIRST_SERVICES_DIR>/<featureName>Service
1319
+ ```
1320
+
1321
+ Folder layout produced (example — new `TransactionHistory` screen in this project):
1322
+ ```
1323
+ src/
1324
+ screens/
1325
+ TransactionHistory/
1326
+ TransactionHistory.tsx ← screen component
1327
+ TransactionHistoryStyle.ts ← StyleSheet
1328
+ store/
1329
+ slices/
1330
+ transactionHistorySlice.ts ← Redux slice + thunk
1331
+ services/
1332
+ transactionHistoryService.ts ← API functions + response types
1333
+ ```
1334
+
1335
+ Log: `INFO: Layer-first project structure detected. Files placed in existing layer directories.`
1336
+
1337
+ ---
1338
+
1339
+ ### 0.L — Read Screen Reference Files
1340
+
1341
+ *Run this step only if `SCREEN_REF_PATHS` from PHASE -1 Q1 is non-empty.*
1342
+
1343
+ For each path in `SCREEN_REF_PATHS`:
1344
+
1345
+ 1. Read the file
1346
+ 2. Extract and record:
1347
+ - **Component structure**: function signature, props interface shape, return type
1348
+ - **StyleSheet shape**: names and categories of styles defined (e.g. `container`, `header`, `listItem`)
1349
+ - **Imports used**: which RN components, shared components, hooks, and utilities are imported
1350
+ - **FlatList vs ScrollView**: which scroll container is used; `keyExtractor` pattern
1351
+ - **Navigation pattern**: which hook is imported, how `navigation.navigate()` is called
1352
+ - **State hooks used**: `useSelector`, `useState`, `useMemo`, `useCallback`, `useEffect` patterns
1353
+ - **Conditional renders**: early return pattern for loading, error, auth error
1354
+ - **List item JSX structure**: how each row is laid out (columns, rows, nested Views)
1355
+
1356
+ Record as:
1357
+ ```
1358
+ SCREEN_REF_PATTERNS: [
1359
+ {
1360
+ file: "<path>",
1361
+ scrollContainer: "FlatList | ScrollView",
1362
+ styleNames: ["container", "header", ...],
1363
+ sharedComponents: ["AppHeader", "PrimaryButton", ...],
1364
+ navHook: "useNavigation | useRouter | none",
1365
+ stateHooks: ["useSelector", "useDispatch", ...],
1366
+ earlyReturnOrder: ["isLoading", "isAuthError", "error"],
1367
+ listItemLayout: "<brief description>"
1368
+ },
1369
+ ...
1370
+ ]
1371
+ ```
1372
+
1373
+ Add `screenRefPatterns` to the fingerprint:
1374
+ ```json
1375
+ "screenRefPatterns": [{ "file": "...", "scrollContainer": "...", ... }]
1376
+ ```
1377
+
1378
+ **Use in PHASE 7**: When `screenRefPatterns` is non-empty, the generated screen component MUST:
1379
+ - Use the same scroll container type (`FlatList` vs `ScrollView`)
1380
+ - Mirror the same early-return order (loading → authError → error)
1381
+ - Import and use the same shared components found in the reference screen
1382
+ - Apply the same StyleSheet naming conventions
1383
+ - Use the same navigation hook and call pattern
1384
+
1385
+ If multiple reference screens conflict on any dimension, use the pattern from the first screen and log a WARN.
1386
+
1387
+ ---
1388
+
1389
+ ## PHASE 1 — Parse Input Spec Files
1390
+
1391
+ ### 1.1 — Locate Spec Files
1392
+
1393
+ Accept spec files as: file paths, dropped files, or inline Markdown.
1394
+
1395
+ **In module mode**: parse one spec file per screen in `SCREENS[]`. The result
1396
+ is a list of `FeatureSpec` objects (one per screen). All later phases loop over
1397
+ this list.
1398
+
1399
+ ### 1.2 — Extract Spec Fields
1400
+
1401
+ ```typescript
1402
+ interface FeatureSpec {
1403
+ screenName: string; // e.g. "TransactionHistory"
1404
+ featureFolderName: string; // TOP-LEVEL folder: derived from MODULE_NAME (module) or screenName (single)
1405
+ moduleName: string | null; // MODULE_NAME if mode=module; null if mode=single
1406
+ apiUrl: string;
1407
+ httpMethod: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
1408
+ requestBody: Record<string, unknown>;
1409
+ responseShape: Record<string, unknown>;
1410
+ businessLogic: string[];
1411
+ screenLogic: string[];
1412
+ responseMappings: ResponseMapping[];
1413
+ }
1414
+
1415
+ interface ResponseMapping {
1416
+ responseField: string; // dot-notation: "data.user.name"
1417
+ uiLocation: string; // "displayed in the Name label"
1418
+ transform?: string; // "format as currency", "show as percentage"
1419
+ }
1420
+ ```
1421
+
1422
+ **Precedence rule for `screenName`:**
1423
+ 1. `SCREEN_NAME` (single) or `SCREENS[N].screenName` (module) from PHASE -1 Q1 — highest priority
1424
+ 2. `## Screen Name` field inside the spec MD file — used only if Q1 name was not given
1425
+ 3. FATAL if neither source provides a name for any screen
1426
+
1427
+ If a spec MD file's `## Screen Name` conflicts with the Q1 name, use Q1 and log a WARN.
1428
+
1429
+ **Merge rule:** PHASE -1 answers (Q2–Q5) for the matching screen are merged into its `FeatureSpec`.
1430
+ Interview answers take precedence over MD file values for every matching field.
1431
+
1432
+ ### 1.3 — Validate Spec
1433
+
1434
+ Run for each `FeatureSpec` in the list:
1435
+
1436
+ FATAL if missing: `screenName`, `apiUrl`, `httpMethod`.
1437
+ WARN if missing: `responseShape` (generate empty entity), `requestBody`
1438
+ (assume `{}`), `responseMappings`, `businessLogic`, `screenLogic`.
1439
+
1440
+ ### 1.4 — Derive Names (using fingerprint conventions)
1441
+
1442
+ Run for each `FeatureSpec`. All derived names below are **per screen**:
1443
+
1444
+ | Derived value | Rule |
1445
+ |---|---|
1446
+ | `featureFolderName` | **module mode**: apply `fingerprint.featureFolderStyle` to `MODULE_NAME`. **single mode**: apply to `screenName`. This is the TOP-LEVEL feature folder — shared by all screens in a module. |
1447
+ | `EntityName` | `screenName + "Item"` if response is array, else `screenName` |
1448
+ | `operationId` | Apply `fingerprint.operationIdStyle` to `screenName` |
1449
+ | `sliceName` | Apply `fingerprint.sliceNameStyle` to `screenName` |
1450
+ | `reducerKey` | Same value as `sliceName`. Used as the key in the store's reducer map and in selectors (`state.<reducerKey>`). Must not collide with existing keys in `fingerprint.reducerMapKeys` — if it does, append `"Feature"` suffix. |
1451
+ | `thunkName` | `"fetch" + screenName + "Thunk"` |
1452
+ | `useCaseName` | `"Fetch" + screenName + "UseCase"` |
1453
+ | `repoInterfaceName` | `fingerprint.interfacePrefix + screenName + "Repository"` |
1454
+ | `dataSourceClassName` | `screenName + "ApiDataSource"` |
1455
+ | `repoImplClassName` | `screenName + "RepositoryImpl"` |
1456
+ | `mockJsonFileName` | Apply `fingerprint.mockJsonStyle` to camelCase of `screenName` |
1457
+ | `endpointConstantName` | SCREAMING_SNAKE_CASE of `screenName` |
1458
+ | `screenComponentName` | `screenName + "Screen"` |
1459
+
1460
+ All file names: apply `fingerprint.fileNameStyle`.
1461
+
1462
+ ### 1.5 — Shared Entity Deduplication (module mode only)
1463
+
1464
+ *Skip this step in single mode.*
1465
+
1466
+ After deriving names for all screens:
1467
+
1468
+ 1. Compare `EntityName` across all screens in the module.
1469
+ 2. If two or more screens share the same `EntityName` (same response shape for the same entity):
1470
+ - Mark that entity as **shared**: `EntityName.isShared = true`
1471
+ - Its domain model file path moves from the per-screen layer to the module's shared models folder:
1472
+ `FEATURE_DIR/domain/models/shared/<EntityName>.ts`
1473
+ - All screens that reference it import from that shared path instead of their own domain folder.
1474
+ - Generate the shared entity file **once** — do NOT duplicate it.
1475
+ 3. Log: `SHARED ENTITY: <EntityName> used by [ScreenA, ScreenB] → generated at shared path`
1476
+
1477
+ ---
1478
+
1479
+ ## PHASE 2 — Resolve All Output Paths
1480
+
1481
+ Before generating any file, compute every output path using only fingerprint
1482
+ values. Store as `OutputPaths`.
1483
+
1484
+ **In module mode**, `FEATURE_DIR` is the SAME for all screens:
1485
+ ```
1486
+ FEATURE_DIR = fingerprint.featuresRoot + "/" + featureFolderName (derived from MODULE_NAME)
1487
+ ```
1488
+
1489
+ All screen-specific files go INSIDE `FEATURE_DIR` using per-screen names.
1490
+ The DI bootstrap and mockConfig are module-level — one per module, not per screen.
1491
+
1492
+ ```
1493
+ FEATURE_DIR = fingerprint.featuresRoot + "/" + featureFolderName
1494
+
1495
+ # Per-screen paths (resolve once per FeatureSpec):
1496
+ PerScreenOutputPaths[screenName] = {
1497
+ domainModel: (isShared)
1498
+ FEATURE_DIR + "/" + fingerprint.layerMap.domainModels + "/shared/" + EntityName + ".ts"
1499
+ (not shared)
1500
+ FEATURE_DIR + "/" + fingerprint.layerMap.domainModels + "/" + EntityName + ".ts"
1501
+ domainRepo: FEATURE_DIR + "/" + fingerprint.layerMap.domainRepo + "/" + repoInterfaceName + ".ts"
1502
+ useCase: FEATURE_DIR + "/" + fingerprint.layerMap.useCases + "/Fetch" + screenName + "UseCase.ts"
1503
+ dto: FEATURE_DIR + "/" + fingerprint.layerMap.dtos + "/" + screenName + "Dto.ts"
1504
+ mapper: FEATURE_DIR + "/" + fingerprint.layerMap.mappers + "/" + screenName + "Mapper.ts"
1505
+ mockJson: FEATURE_DIR + "/" + fingerprint.layerMap.mocks + "/" + mockJsonFileName
1506
+ endpoints: FEATURE_DIR + "/" + fingerprint.layerMap.dataSource + "/" + screenName + "Endpoints.ts"
1507
+ dataSource: FEATURE_DIR + "/" + fingerprint.layerMap.dataSource + "/" + dataSourceClassName + ".ts"
1508
+ repoImpl: FEATURE_DIR + "/" + fingerprint.layerMap.data + "/repositories/" + repoImplClassName + ".ts"
1509
+ slice: FEATURE_DIR + "/" + fingerprint.layerMap.stateStore + "/" + sliceName + "Slice.ts"
1510
+ selectors: FEATURE_DIR + "/" + fingerprint.layerMap.selectors + "/" + screenName + "Selectors.ts"
1511
+ screen: FEATURE_DIR + "/" + fingerprint.layerMap.screens + "/" + screenComponentName + "/" + screenComponentName + ".tsx"
1512
+ }
1513
+
1514
+ # Module-level paths (ONE per module, shared across all screens):
1515
+ ModuleOutputPaths = {
1516
+ mockConfig: FEATURE_DIR + "/" + fingerprint.layerMap.dataSource + "/mockConfig.ts"
1517
+ diBootstrap: FEATURE_DIR + "/diBootstrap.ts" (or global DI file if fingerprint shows a global one)
1518
+ }
1519
+ ```
1520
+
1521
+ If any `fingerprint.layerMap.*` is `null`, skip that file and log a WARN.
1522
+
1523
+ **Import path computation for each file:**
1524
+
1525
+ For any file at depth D from `fingerprint.appRoot`, the prefix to reach
1526
+ `fingerprint.sharedRoot` is:
1527
+ ```
1528
+ If fingerprint.preferAliases && fingerprint.sharedRootAlias != null:
1529
+ USE alias directly → e.g. "@shared/types/Result"
1530
+ Else:
1531
+ prefix = repeat("../", D) + fingerprint.sharedRoot
1532
+ → e.g. "../../../../shared"
1533
+ ```
1534
+
1535
+ Similarly for cross-layer imports within the feature, compute relative paths
1536
+ from the actual file depths — never hardcode `../../domain`.
1537
+
1538
+ ---
1539
+
1540
+ > ### Phases 3–7 execution order
1541
+ >
1542
+ > **Single mode**: run Phases 3 → 4 → 5 → 6 → 7 once.
1543
+ >
1544
+ > **Module mode**: run the following loop:
1545
+ > ```
1546
+ > FOR each screen in SCREENS[] (in the order provided by the user):
1547
+ > Run Phase 3 for this screen (skip 3.1 if EntityName.isShared and already generated)
1548
+ > Run Phase 4 for this screen
1549
+ > Run Phase 5 for this screen
1550
+ > Run Phase 7 for this screen
1551
+ > END FOR
1552
+ > Then run Phase 6 ONCE for the whole module (all screens wired into one diBootstrap)
1553
+ > ```
1554
+ >
1555
+ > Phase 6 is intentionally **after** the per-screen loop in module mode so that
1556
+ > all use-case exports are known before the single DI bootstrap is written.
1557
+
1558
+ ---
1559
+
1560
+ ## PHASE 3 — Generate Domain Layer
1561
+
1562
+ ### 3.1 — Entity Interface
1563
+
1564
+ File: `PerScreenOutputPaths[screenName].domainModel`
1565
+
1566
+ *In module mode: if `EntityName.isShared = true` and this entity was already generated
1567
+ for a previous screen, SKIP this step — do not regenerate the shared entity file.*
1568
+
1569
+ - Parse every key from `responseShape` recursively
1570
+ - Infer TypeScript types from values
1571
+ - All fields `readonly` (if `fingerprint.tsStrict === true`)
1572
+ - Optional `?` for fields noted as potentially absent
1573
+ - Never `any` — use `unknown` for opaque shapes
1574
+ - JSDoc comments for fields referenced in `responseMappings`
1575
+ - If `fingerprint.explicitReturnType === true`, add return types to any functions
1576
+
1577
+ ### 3.2 — Repository Interface
1578
+
1579
+ File: `PerScreenOutputPaths[screenName].domainRepo`
1580
+
1581
+ - `Fetch<ScreenName>Params` interface: one property per `requestBody` field, camelCased
1582
+ - Return type is driven by `fingerprint.returnTypeStyle`:
1583
+
1584
+ ```
1585
+ result-wrapper → Promise<Result<EntityName[]>>
1586
+ Import Result from fingerprint.resultTypeImport
1587
+
1588
+ custom-type → Promise<<ScreenName>Result>
1589
+ Define <ScreenName>Result inline in this file as a named interface
1590
+ containing the domain entities; match the shape used in existing
1591
+ repository interfaces in the project
1592
+
1593
+ direct-promise → Promise<EntityName[]>
1594
+ No wrapper — the implementation throws on error
1595
+ ```
1596
+
1597
+ - Zero framework imports
1598
+
1599
+ ### 3.3 — Use Case
1600
+
1601
+ File: `PerScreenOutputPaths[screenName].useCase`
1602
+
1603
+ - Class with `constructor(private readonly repository: <repoInterfaceName>)`
1604
+ - `execute(params)` method return type matches the repository interface return type
1605
+ - Each `businessLogic` rule from spec → one guard clause before delegation
1606
+ - Zero framework imports (no React, Redux, Axios, or any detected API lib)
1607
+ - **If `fingerprint.returnTypeStyle = "direct-promise"`**: let errors propagate naturally
1608
+ (no `try/catch` or `{ ok }` wrapping in the use case)
1609
+ - **If `fingerprint.returnTypeStyle = "result-wrapper"`**: catch and return
1610
+ `{ ok: false, error: message }`
1611
+
1612
+ ---
1613
+
1614
+ ## PHASE 4 — Generate Data Layer
1615
+
1616
+ ### 4.1 — DTO
1617
+
1618
+ File: `PerScreenOutputPaths[screenName].dto`
1619
+
1620
+ - Mirror raw API response shape exactly, preserving original casing from spec
1621
+ - If spec shows PascalCase keys, generate BOTH PascalCase and camelCase variants as optional fields
1622
+ - Mapper will use `??` chaining across both variants
1623
+
1624
+ ### 4.2 — Mapper
1625
+
1626
+ File: `PerScreenOutputPaths[screenName].mapper`
1627
+
1628
+ Rules (apply regardless of project):
1629
+ - Always generate `map<Entity>FromDto` AND `map<Entity>ListFromDto`
1630
+ - Every field: `(dto.PascalCaseKey ?? dto.camelCaseKey) ?? <default>`
1631
+ - Defaults: `''` for string, `0` for number, `false` for boolean, `[]` for array, `null` for object
1632
+ - One mapper file per entity — never merge unrelated entities into one mapper
1633
+
1634
+ ### 4.3 — Mock JSON
1635
+
1636
+ File: `PerScreenOutputPaths[screenName].mockJson`
1637
+
1638
+ - Exact JSON matching the `responseShape` from spec
1639
+ - Populated with realistic placeholder values
1640
+ - Valid JSON (parseable by `JSON.parse`)
1641
+
1642
+ ### 4.4 — Endpoint Constants
1643
+
1644
+ File: `PerScreenOutputPaths[screenName].endpoints`
1645
+
1646
+ ```typescript
1647
+ export const <endpointConstantName>_ENDPOINTS = {
1648
+ FETCH: '<spec.apiUrl>',
1649
+ } as const;
1650
+ ```
1651
+
1652
+ ### 4.5 — Mock Config
1653
+
1654
+ File: `ModuleOutputPaths.mockConfig` — one file per module (shared by all screens)
1655
+
1656
+ In module mode: generate a single mockConfig that includes one entry per screen's `operationId`.
1657
+ Do NOT generate separate mockConfig files per screen.
1658
+
1659
+ Generate using the **exact shape** detected in `fingerprint.mockSystem`. Copy
1660
+ field names from the live mockConfig file detected in Phase 0.E. Do not invent
1661
+ field names.
1662
+
1663
+ If `fingerprint.mockSystem === "none"` → skip this file, add a TODO comment in
1664
+ the datasource.
1665
+
1666
+ Rules (apply regardless of shape):
1667
+ - `fingerprint.mockGlobalFlag` field always `false`
1668
+ - Per-API flag for `operationId` always `false`
1669
+ - `fingerprint.mockDelayField` value: copy from existing config or default to 800
1670
+
1671
+ ### 4.6 — API DataSource
1672
+
1673
+ File: `PerScreenOutputPaths[screenName].dataSource`
1674
+
1675
+ > See: `references/api-envelope-patterns.md` — full templates for all `apiLib` + `envelopeStyle` combinations.
1676
+ > Read the section matching the detected values before generating.
1677
+
1678
+ Generate using the pattern matching `fingerprint.apiLib` + `fingerprint.envelopeStyle`.
1679
+
1680
+ **If apiLib = axios AND envelopeStyle = mb-operationId:**
1681
+
1682
+ ```typescript
1683
+ import { apiClient } from '<fingerprint.apiClientImport>';
1684
+ import { <endpointConstantName>_ENDPOINTS } from './<screenName>Endpoints'; // file name uses screenName, not featureFolderName
1685
+ import { mockConfig } from './mockConfig';
1686
+ import type { Fetch<ScreenName>Params } from '<relative-path-to-domainRepo>';
1687
+ import mockData from '<relative-path-to-mockJson>';
1688
+
1689
+ function delay(ms: number): Promise<void> {
1690
+ return new Promise((resolve) => setTimeout(resolve, ms));
1691
+ }
1692
+
1693
+ // Replicate envelope builder exactly as detected — do not rename fields
1694
+ function buildEnvelope(operationId: string, reqdata: Record<string, unknown>): object {
1695
+ return { mb: { operationId, rq: { reqdata } } };
1696
+ }
1697
+
1698
+ export class <dataSourceClassName> {
1699
+ async fetch<ScreenName>(params: Fetch<ScreenName>Params): Promise<Record<string, unknown>> {
1700
+ const { <operationId> } = mockConfig.apis;
1701
+ // fingerprint.mockGlobalFlag checked FIRST — always
1702
+ if (mockConfig.<fingerprint.mockGlobalFlag> || <operationId>.mockEnabled) {
1703
+ await delay(mockConfig.<fingerprint.mockDelayField>);
1704
+ return mockData as Record<string, unknown>;
1705
+ }
1706
+ const body = buildEnvelope('<operationId>', {
1707
+ // Map camelCase params → original API casing from spec requestBody
1708
+ });
1709
+ const response = await apiClient.<httpMethod.toLowerCase()><Record<string, unknown>>(
1710
+ <endpointConstantName>_ENDPOINTS.FETCH,
1711
+ body,
1712
+ );
1713
+ return response.data;
1714
+ }
1715
+ }
1716
+ ```
1717
+
1718
+ **If apiLib = fetch AND envelopeStyle = none:**
1719
+
1720
+ ```typescript
1721
+ export class <dataSourceClassName> {
1722
+ async fetch<ScreenName>(params: Fetch<ScreenName>Params): Promise<Record<string, unknown>> {
1723
+ const response = await fetch('<spec.apiUrl>', {
1724
+ method: '<spec.httpMethod>',
1725
+ headers: { 'Content-Type': 'application/json' },
1726
+ body: JSON.stringify({ /* mapped params */ }),
1727
+ });
1728
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
1729
+ return response.json();
1730
+ }
1731
+ }
1732
+ ```
1733
+
1734
+ **If apiLib = rtk-query or react-query:** Generate the appropriate endpoint/hook
1735
+ definition instead of a class. Adapt to the detected pattern.
1736
+
1737
+ **Request body field mapping:**
1738
+ - `requestBody` from spec shows API-expected field names and casing
1739
+ - `Params` interface uses camelCase
1740
+ - Datasource maps camelCase params → spec field names inside the request body
1741
+
1742
+ ### 4.7 — Repository Implementation
1743
+
1744
+ File: `PerScreenOutputPaths[screenName].repoImpl`
1745
+
1746
+ > DTO type name rule: The DTO interface inside `<screenName>Dto.ts` is named `<ScreenName>Dto`.
1747
+ > The domain entity is `<EntityName>` (= `<ScreenName>Item` when the response is an array).
1748
+ > They are NOT the same name. Always cast raw items as `<ScreenName>Dto`, not `<EntityName>Dto`.
1749
+
1750
+ The return type of the implementation method is driven by `fingerprint.returnTypeStyle`.
1751
+
1752
+ **result-wrapper** (when `fingerprint.returnTypeStyle = "result-wrapper"`):
1753
+
1754
+ ```typescript
1755
+ import type { Result } from '<fingerprint.resultTypeImport>';
1756
+ import type { <repoInterfaceName>, Fetch<ScreenName>Params } from '<relative-path-to-domainRepo>';
1757
+ import type { <EntityName> } from '<relative-path-to-domainModel>';
1758
+ import type { <dataSourceClassName> } from '<relative-path-to-dataSource>';
1759
+ import { map<Entity>ListFromDto } from '<relative-path-to-mapper>';
1760
+
1761
+ export class <repoImplClassName> implements <repoInterfaceName> {
1762
+ constructor(private readonly dataSource: <dataSourceClassName>) {}
1763
+
1764
+ async fetch<ScreenName>(params: Fetch<ScreenName>Params): Promise<Result<<EntityName>[]>> {
1765
+ try {
1766
+ const raw = await this.dataSource.fetch<ScreenName>(params);
1767
+ const items = (raw.Data ?? raw.data ?? []) as <ScreenName>Dto[]; // cast to DTO, not entity
1768
+ return { ok: true, data: map<Entity>ListFromDto(items) };
1769
+ } catch (err: unknown) {
1770
+ const apiErr = err as { statusCode?: number; message?: string };
1771
+ return { ok: false, error: apiErr.message ?? 'Failed to fetch <featureFolderName>' };
1772
+ }
1773
+ }
1774
+ }
1775
+ ```
1776
+
1777
+ **custom-type** (when `fingerprint.returnTypeStyle = "custom-type"`):
1778
+
1779
+ ```typescript
1780
+ import type { <repoInterfaceName>, Fetch<ScreenName>Params, <ScreenName>Result } from '<relative-path-to-domainRepo>';
1781
+ import type { <dataSourceClassName> } from '<relative-path-to-dataSource>';
1782
+ import { map<Entity>ListFromDto } from '<relative-path-to-mapper>';
1783
+
1784
+ export class <repoImplClassName> implements <repoInterfaceName> {
1785
+ constructor(private readonly dataSource: <dataSourceClassName>) {}
1786
+
1787
+ async fetch<ScreenName>(params: Fetch<ScreenName>Params): Promise<<ScreenName>Result> {
1788
+ const raw = await this.dataSource.fetch<ScreenName>(params);
1789
+ const items = (raw.Data ?? raw.data ?? []) as <ScreenName>Dto[]; // cast to DTO, not entity
1790
+ return { <primaryField>: map<Entity>ListFromDto(items) };
1791
+ // Shape must match the custom-type interface defined in the domain repo file
1792
+ }
1793
+ }
1794
+ ```
1795
+
1796
+ **direct-promise** (when `fingerprint.returnTypeStyle = "direct-promise"`):
1797
+
1798
+ ```typescript
1799
+ import type { <repoInterfaceName>, Fetch<ScreenName>Params } from '<relative-path-to-domainRepo>';
1800
+ import type { <EntityName> } from '<relative-path-to-domainModel>';
1801
+ import type { <dataSourceClassName> } from '<relative-path-to-dataSource>';
1802
+ import { map<Entity>ListFromDto } from '<relative-path-to-mapper>';
1803
+
1804
+ export class <repoImplClassName> implements <repoInterfaceName> {
1805
+ constructor(private readonly dataSource: <dataSourceClassName>) {}
1806
+
1807
+ async fetch<ScreenName>(params: Fetch<ScreenName>Params): Promise<<EntityName>[]> {
1808
+ const raw = await this.dataSource.fetch<ScreenName>(params);
1809
+ const items = (raw.Data ?? raw.data ?? []) as <ScreenName>Dto[]; // cast to DTO, not entity
1810
+ return map<Entity>ListFromDto(items);
1811
+ // Errors propagate as thrown exceptions — caller handles them
1812
+ }
1813
+ }
1814
+ ```
1815
+
1816
+ ---
1817
+
1818
+ ## PHASE 5 — Generate State Layer
1819
+
1820
+ Generate state files only for the detected `fingerprint.stateLib`.
1821
+
1822
+ ### 5.1 — Redux Toolkit (stateLib = redux-toolkit)
1823
+
1824
+ File: `PerScreenOutputPaths[screenName].slice`
1825
+
1826
+ Use `fingerprint.thunkPattern` to determine injection style.
1827
+
1828
+ **ThunkExtra pattern** (when `fingerprint.thunkPattern = "thunk-extra"`):
1829
+
1830
+ The thunk body structure depends on `fingerprint.returnTypeStyle`.
1831
+
1832
+ **result-wrapper** (use case returns `{ ok, data, error }`):
1833
+
1834
+ ```typescript
1835
+ import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
1836
+ import type { PayloadAction } from '@reduxjs/toolkit'; // needed: used in extraReducers fulfilled case
1837
+ // also add if any slice reducer receives a payload
1838
+ import type { <EntityName> } from '<relative-path-to-domainModel>';
1839
+
1840
+ export interface <ScreenName>State {
1841
+ items: <EntityName>[];
1842
+ isLoading: boolean;
1843
+ isRefreshing: boolean;
1844
+ error: string | null;
1845
+ isAuthError: boolean;
1846
+ // Additional state fields derived from spec.screenLogic
1847
+ }
1848
+
1849
+ const initialState: <ScreenName>State = {
1850
+ items: [],
1851
+ isLoading: false,
1852
+ isRefreshing: false,
1853
+ error: null,
1854
+ isAuthError: false,
1855
+ // Add any extra fields from spec.screenLogic with appropriate zero-value defaults
1856
+ };
1857
+
1858
+ export const fetch<ScreenName>Thunk = createAsyncThunk(
1859
+ '<sliceName>/fetch', // e.g. 'transactionHistory/fetch'
1860
+ async (params: { /* from Fetch<ScreenName>Params */ }, { extra, rejectWithValue }) => {
1861
+ try {
1862
+ const { fetch<ScreenName>UseCase } = extra as {
1863
+ fetch<ScreenName>UseCase: {
1864
+ execute: (p: typeof params) => Promise<{ ok: boolean; data?: <EntityName>[]; error?: string }>;
1865
+ };
1866
+ };
1867
+ const result = await fetch<ScreenName>UseCase.execute(params);
1868
+ if (!result.ok) return rejectWithValue({ message: result.error ?? 'Unknown error', isAuthError: false });
1869
+ return result.data;
1870
+ } catch (err: unknown) {
1871
+ const apiErr = err as { statusCode?: number; message?: string };
1872
+ return rejectWithValue({ message: apiErr.message ?? 'Unexpected error', isAuthError: apiErr.statusCode === 401 });
1873
+ }
1874
+ },
1875
+ );
1876
+ ```
1877
+
1878
+ **custom-type** (use case returns a named type — no `.ok` field):
1879
+
1880
+ ```typescript
1881
+ export const fetch<ScreenName>Thunk = createAsyncThunk(
1882
+ '<sliceName>/fetch', // e.g. 'transactionHistory/fetch'
1883
+ async (params: { /* from Fetch<ScreenName>Params */ }, { extra, rejectWithValue }) => {
1884
+ try {
1885
+ const { fetch<ScreenName>UseCase } = extra as {
1886
+ fetch<ScreenName>UseCase: {
1887
+ execute: (p: typeof params) => Promise<<ScreenName>Result>;
1888
+ };
1889
+ };
1890
+ return await fetch<ScreenName>UseCase.execute(params);
1891
+ } catch (err: unknown) {
1892
+ const apiErr = err as { statusCode?: number; message?: string };
1893
+ return rejectWithValue({ message: apiErr.message ?? 'Unexpected error', isAuthError: apiErr.statusCode === 401 });
1894
+ }
1895
+ },
1896
+ );
1897
+ ```
1898
+
1899
+ **direct-promise** (use case returns a plain type and throws on error):
1900
+
1901
+ ```typescript
1902
+ export const fetch<ScreenName>Thunk = createAsyncThunk(
1903
+ '<sliceName>/fetch', // e.g. 'transactionHistory/fetch'
1904
+ async (params: { /* from Fetch<ScreenName>Params */ }, { extra, rejectWithValue }) => {
1905
+ try {
1906
+ const { fetch<ScreenName>UseCase } = extra as {
1907
+ fetch<ScreenName>UseCase: {
1908
+ execute: (p: typeof params) => Promise<<EntityName>[]>;
1909
+ };
1910
+ };
1911
+ return await fetch<ScreenName>UseCase.execute(params);
1912
+ } catch (err: unknown) {
1913
+ const apiErr = err as { statusCode?: number; message?: string };
1914
+ return rejectWithValue({ message: apiErr.message ?? 'Unexpected error', isAuthError: apiErr.statusCode === 401 });
1915
+ }
1916
+ },
1917
+ );
1918
+ ```
1919
+
1920
+ // NOTE: If spec.screenLogic contains "pull to refresh" or "refresh", generate
1921
+ // refresh<ScreenName>Thunk as described in the refreshThunk generation section below.
1922
+
1923
+ const <sliceName>Slice = createSlice({
1924
+ name: '<sliceName>',
1925
+ initialState,
1926
+ reducers: {
1927
+ reset<ScreenName>: () => initialState,
1928
+ // Reducers derived from spec.screenLogic (filters, sorts, selectedItem, tabs)
1929
+ },
1930
+ extraReducers: builder => {
1931
+ // fetch thunk
1932
+ builder
1933
+ .addCase(fetch<ScreenName>Thunk.pending, (state) => {
1934
+ state.isLoading = true;
1935
+ state.error = null;
1936
+ state.isAuthError = false;
1937
+ })
1938
+ .addCase(fetch<ScreenName>Thunk.fulfilled, (state, action: PayloadAction<<EntityName>[]>) => {
1939
+ state.isLoading = false;
1940
+ state.items = action.payload;
1941
+ })
1942
+ .addCase(fetch<ScreenName>Thunk.rejected, (state, action) => {
1943
+ state.isLoading = false;
1944
+ state.error = action.payload as string ?? 'Failed to load';
1945
+ state.isAuthError = action.payload === 'AUTH_ERROR';
1946
+ });
1947
+ // refresh thunk (if generated)
1948
+ // builder
1949
+ // .addCase(refresh<ScreenName>Thunk.pending, (state) => { state.isRefreshing = true; state.error = null; })
1950
+ // .addCase(refresh<ScreenName>Thunk.fulfilled, (state, action) => { state.isRefreshing = false; state.items = action.payload; })
1951
+ // .addCase(refresh<ScreenName>Thunk.rejected, (state, action) => { state.isRefreshing = false; state.error = action.payload as string ?? 'Failed to refresh'; });
1952
+ },
1953
+ });
1954
+ ```
1955
+
1956
+ **Direct import pattern** (when `fingerprint.thunkPattern = "direct-import"`):
1957
+
1958
+ Import the use case at the top of the slice file and call it directly without
1959
+ `extra`.
1960
+
1961
+ **refreshThunk generation (add when spec.screenLogic contains "pull to refresh" or "refresh"):**
1962
+
1963
+ Generate a separate `refresh<ScreenName>Thunk` alongside the fetch thunk. It has the
1964
+ exact same body as `fetch<ScreenName>Thunk` for the applicable `returnTypeStyle`. The
1965
+ only difference is the action type string and which state fields it sets:
1966
+
1967
+ ```typescript
1968
+ export const refresh<ScreenName>Thunk = createAsyncThunk(
1969
+ '<sliceName>/refresh', // e.g. 'transactionHistory/refresh'
1970
+ async (params: { /* same as fetch params */ }, { extra, rejectWithValue }) => {
1971
+ // identical body to fetch<ScreenName>Thunk
1972
+ },
1973
+ );
1974
+
1975
+ // In extraReducers:
1976
+ .addCase(refresh<ScreenName>Thunk.pending, (state) => {
1977
+ state.isRefreshing = true; // NOT isLoading — this is the critical difference
1978
+ state.error = null;
1979
+ })
1980
+ .addCase(refresh<ScreenName>Thunk.fulfilled, (state, action) => {
1981
+ state.isRefreshing = false;
1982
+ state.items = action.payload ?? [];
1983
+ })
1984
+ .addCase(refresh<ScreenName>Thunk.rejected, (state, action) => {
1985
+ state.isRefreshing = false;
1986
+ const payload = action.payload as { message: string; isAuthError: boolean };
1987
+ state.error = payload?.message ?? 'Failed to refresh';
1988
+ });
1989
+ ```
1990
+
1991
+ **State fields from screenLogic:**
1992
+
1993
+ | screenLogic phrase | State field | Reducer |
1994
+ |---|---|---|
1995
+ | "filter by category" | `filter: string` | `setFilter` |
1996
+ | "sortable by X" | `sortOrder: 'asc' \| 'desc'` | `setSortOrder` |
1997
+ | "selected item detail" | `selectedItemId: string \| null` | `setSelectedItem` |
1998
+ | "tab switcher" | `activeTab: string` | `setActiveTab` |
1999
+ | "pagination" | `page: number`, `hasMore: boolean` | `setPage`, `setHasMore` |
2000
+
2001
+ ### 5.2 — Selectors
2002
+
2003
+ File: `PerScreenOutputPaths[screenName].selectors`
2004
+
2005
+ ```typescript
2006
+ import type { RootState } from '<fingerprint.rootStateImport>';
2007
+
2008
+ export const select<ScreenName>Items = (state: RootState) =>
2009
+ state.<reducerKey>.items; // reducerKey derived in Phase 1.4 for this specific screen
2010
+
2011
+ // One selector per state field in the slice
2012
+ ```
2013
+
2014
+ `reducerKey` is the per-screen derived value from Phase 1.4 — NOT the single `fingerprint.reducerKey`.
2015
+ In module mode each screen has its own `reducerKey` and they MUST all be distinct.
2016
+
2017
+ ### 5.3 — Zustand (stateLib = zustand)
2018
+
2019
+ > See: `references/state-library-patterns.md` — Zustand section.
2020
+ > Detect zustand version and pattern (single store vs slice) before generating.
2021
+
2022
+ Generate a store file using the detected zustand pattern (slice-based or single
2023
+ store). Do not use Redux patterns.
2024
+
2025
+ ### 5.4 — Context API (stateLib = context-api)
2026
+
2027
+ > See: `references/state-library-patterns.md` — Context API section.
2028
+
2029
+ Generate context + reducer + provider. Do not use Redux patterns.
2030
+
2031
+ ### 5.5 — MobX (stateLib = mobx)
2032
+
2033
+ > See: `references/state-library-patterns.md` — MobX section.
2034
+ > Detect MobX version (6+ uses `makeAutoObservable`; 4/5 uses `@observable` decorators).
2035
+
2036
+ Generate a MobX store class. Do not generate a Redux slice, selectors file, or thunk.
2037
+ The screen component must be wrapped in `observer()` from `mobx-react-lite`.
2038
+ Computed values are class getters, not a separate selectors file.
2039
+
2040
+ ---
2041
+
2042
+ ## PHASE 6 — Generate DI Wiring
2043
+
2044
+ Use `fingerprint.diStyle` to choose the generation path.
2045
+
2046
+ **Module mode**: Phase 6 runs ONCE after the per-screen loop (Phases 3–5 and 7).
2047
+ One DI file is generated for the ENTIRE module. It imports and instantiates every
2048
+ datasource, repository, and use case across ALL screens — not one file per screen.
2049
+
2050
+ ---
2051
+
2052
+ ### 6.A — per-feature-bootstrap (diStyle = "per-feature-bootstrap")
2053
+
2054
+ File: `ModuleOutputPaths.diBootstrap` — one file for the whole module
2055
+
2056
+ **Module mode template** (expand the pattern for each screen in `SCREENS[]`):
2057
+ ```typescript
2058
+ // ─── <ModuleName> DI Bootstrap ───────────────────────────────────────────────
2059
+ // Auto-generated. Do not edit manually.
2060
+
2061
+ // Screen 1: <ScreenName1>
2062
+ import { <DataSourceClassName1> } from '<relative-path>';
2063
+ import { <RepoImplClassName1> } from '<relative-path>';
2064
+ import { Fetch<ScreenName1>UseCase } from '<relative-path>';
2065
+
2066
+ // Screen 2: <ScreenName2>
2067
+ import { <DataSourceClassName2> } from '<relative-path>';
2068
+ import { <RepoImplClassName2> } from '<relative-path>';
2069
+ import { Fetch<ScreenName2>UseCase } from '<relative-path>';
2070
+
2071
+ // ... (repeat for each screen)
2072
+
2073
+ const <screenName1>DataSource = new <DataSourceClassName1>();
2074
+ const <screenName1>Repository = new <RepoImplClassName1>(<screenName1>DataSource);
2075
+ export const fetch<ScreenName1>UseCase = new Fetch<ScreenName1>UseCase(<screenName1>Repository);
2076
+
2077
+ const <screenName2>DataSource = new <DataSourceClassName2>();
2078
+ const <screenName2>Repository = new <RepoImplClassName2>(<screenName2>DataSource);
2079
+ export const fetch<ScreenName2>UseCase = new Fetch<ScreenName2>UseCase(<screenName2>Repository);
2080
+
2081
+ // ... (repeat for each screen)
2082
+ ```
2083
+
2084
+ **Single mode template** (unchanged behaviour — one screen):
2085
+ ```typescript
2086
+ import { <dataSourceClassName> } from '<relative-path>';
2087
+ import { <repoImplClassName> } from '<relative-path>';
2088
+ import { Fetch<ScreenName>UseCase } from '<relative-path>';
2089
+
2090
+ // <screenNameCamelCase> = camelCase of screenName, e.g. TransactionHistory → transactionHistory
2091
+ const <screenNameCamelCase>DataSource = new <dataSourceClassName>();
2092
+ const <screenNameCamelCase>Repository = new <repoImplClassName>(<screenNameCamelCase>DataSource);
2093
+ export const fetch<ScreenName>UseCase = new Fetch<ScreenName>UseCase(<screenNameCamelCase>Repository);
2094
+ ```
2095
+
2096
+ **If `fingerprint.thunkPattern = "thunk-extra"`**, append a comment:
2097
+ ```typescript
2098
+ // Wire into store extra argument in <fingerprint.storeConfigFile>:
2099
+ // { ...existingExtra, fetch<ScreenName>UseCase }
2100
+ ```
2101
+
2102
+ **Store wiring instruction (append to diBootstrap.ts or DI container file):**
2103
+
2104
+ After the DI wiring, always add the following comments describing the exact manual steps
2105
+ the developer must perform.
2106
+
2107
+ *In module mode, list ALL screens in the STORE REDUCER and THUNK EXTRA blocks, and list
2108
+ ALL screen registrations in the NAVIGATOR block:*
2109
+
2110
+ ```typescript
2111
+ // ─── MANUAL WIRING REQUIRED ───────────────────────────────────────────────
2112
+ //
2113
+ // 1. STORE REDUCER — open <fingerprint.storeConfigFile> and add one import + key per screen:
2114
+ //
2115
+ // import <sliceName1>Reducer from '<relative-path-to-slice1>';
2116
+ // import <sliceName2>Reducer from '<relative-path-to-slice2>';
2117
+ //
2118
+ // reducer: {
2119
+ // ...existingReducers,
2120
+ // <reducerKey1>: <sliceName1>Reducer,
2121
+ // <reducerKey2>: <sliceName2>Reducer,
2122
+ // }
2123
+ //
2124
+ // 2. THUNK EXTRA (thunk-extra only) — in the same file, add to middleware:
2125
+ //
2126
+ // getDefaultMiddleware({ thunk: { extraArgument: {
2127
+ // ...existingExtra,
2128
+ // fetch<ScreenName1>UseCase,
2129
+ // fetch<ScreenName2>UseCase,
2130
+ // }}})
2131
+ //
2132
+ // 3. NAVIGATOR — open <fingerprint.navScreenFile> and add one import + Stack.Screen per screen:
2133
+ //
2134
+ // import <ScreenName1>Screen from '<relative-path-to-screen1>';
2135
+ // import <ScreenName2>Screen from '<relative-path-to-screen2>';
2136
+ //
2137
+ // // Inside the navigator stack:
2138
+ // <Stack.Screen name="<ScreenName1>" component={<ScreenName1>Screen} />
2139
+ // <Stack.Screen name="<ScreenName2>" component={<ScreenName2>Screen} />
2140
+ //
2141
+ // // Add to <fingerprint.navParamsPattern> type:
2142
+ // <ScreenName1>: { /* params if any */ } | undefined;
2143
+ // <ScreenName2>: { /* params if any */ } | undefined;
2144
+ //
2145
+ // ─────────────────────────────────────────────────────────────────────────
2146
+ ```
2147
+
2148
+ ---
2149
+
2150
+ ### 6.B — per-feature-container (diStyle = "per-feature-container")
2151
+
2152
+ File: `FEATURE_DIR + "/" + fingerprint.layerMap.di + "/" + moduleName + "Container.ts"`
2153
+
2154
+ In **module mode**: generate ONE container class for the entire module. It holds one datasource,
2155
+ repository, and use-case getter per screen — all wired inside the single class.
2156
+
2157
+ In **single mode**: generate one container for the single screen (same as before).
2158
+
2159
+ Use the class and method names matching those in `fingerprint.diContainerClass`.
2160
+
2161
+ ```typescript
2162
+ import { <dataSourceClassName> } from '<relative-path>';
2163
+ import { <repoImplClassName> } from '<relative-path>';
2164
+ import { Fetch<ScreenName>UseCase } from '<relative-path>';
2165
+ import type { I<ScreenName>Repository } from '<relative-path>';
2166
+
2167
+ class <ScreenName>Container {
2168
+ private static _instance: <ScreenName>Container | null = null;
2169
+
2170
+ private readonly _dataSource: <dataSourceClassName>;
2171
+ private readonly _repository: I<ScreenName>Repository;
2172
+
2173
+ private constructor() {
2174
+ this._dataSource = new <dataSourceClassName>();
2175
+ this._repository = new <repoImplClassName>(this._dataSource);
2176
+ }
2177
+
2178
+ static getInstance(): <ScreenName>Container {
2179
+ if (!<ScreenName>Container._instance) {
2180
+ <ScreenName>Container._instance = new <ScreenName>Container();
2181
+ }
2182
+ return <ScreenName>Container._instance;
2183
+ }
2184
+
2185
+ get fetch<ScreenName>UseCase(): Fetch<ScreenName>UseCase {
2186
+ return new Fetch<ScreenName>UseCase(this._repository);
2187
+ }
2188
+
2189
+ // For testing: reset singleton between test suites
2190
+ static resetInstance(): void {
2191
+ <ScreenName>Container._instance = null;
2192
+ }
2193
+ }
2194
+
2195
+ export const <featureFolderName>Container = <ScreenName>Container.getInstance();
2196
+ ```
2197
+
2198
+ Consumers call `<featureFolderName>Container.fetch<ScreenName>UseCase.execute(params)`.
2199
+
2200
+ ---
2201
+
2202
+ ### 6.C — global (diStyle = "global")
2203
+
2204
+ Append the new feature's wiring to the existing global DI file. Never overwrite
2205
+ existing entries.
2206
+
2207
+ ---
2208
+
2209
+ ### 6.D — none (diStyle = "none")
2210
+
2211
+ Skip DI file generation. Components instantiate dependencies inline (rare — log a WARN).
2212
+
2213
+ ---
2214
+
2215
+ ## PHASE 7 — Generate Screen Component
2216
+
2217
+ File: `PerScreenOutputPaths[screenName].screen`
2218
+
2219
+ ### 7.1 — Imports
2220
+
2221
+ Resolve all imports using the fingerprint:
2222
+ - `useDispatch`, `useSelector` from `react-redux` (if redux)
2223
+ - `AppDispatch` from fingerprint-resolved store path
2224
+ - Thunks from `PerScreenOutputPaths[screenName].slice` (relative import)
2225
+ - Selectors from `PerScreenOutputPaths[screenName].selectors` (relative import)
2226
+ - Entity type from `PerScreenOutputPaths[screenName].domainModel` (relative import)
2227
+
2228
+ For navigation (if spec.screenLogic mentions navigation):
2229
+ - Import navigator hook matching `fingerprint.navLib`:
2230
+ - `useNavigation` from `@react-navigation/native`
2231
+ - `useRouter` from `expo-router`
2232
+ - `Navigation` from `react-native-navigation`
2233
+
2234
+ ### 7.2 — Response Mapping Implementation
2235
+
2236
+ > See: `assets/transform-rules.json` — full keyword-to-TypeScript-expression map.
2237
+ > Match each transform phrase in the spec against entries in that file (case-insensitive substring match).
2238
+ > If no entry matches, render as raw string and log a WARN.
2239
+
2240
+ For every `responseMappings` entry in the spec:
2241
+
2242
+ 1. Trace the dot-notation path through the entity interface using optional chaining
2243
+ 2. Match the transform keyword against `assets/transform-rules.json`. Use `nullSafe` variant when the field is optional.
2244
+ Quick reference (non-exhaustive — always read the JSON file):
2245
+ - `"formatted as indian currency"` → `toLocaleString('en-IN', { style: 'currency', currency: 'INR' })`
2246
+ - `"formatted as percentage"` → `` `${(value * 100).toFixed(2)}%` ``
2247
+ - `"formatted as date"` → `new Date(value).toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' })`
2248
+ - `"formatted as boolean badge"` → conditional `<Text style>` with color
2249
+ - `"formatted as compact number"` → Cr/L abbreviation for Indian units
2250
+ - `"unique key"` / `"hidden"` → used as keyExtractor only, not rendered
2251
+ 3. Add a comment above each JSX element citing the spec mapping instruction
2252
+ 4. If mapping says "hide when null/empty" → conditional render `{value ? <Text>...</Text> : null}`
2253
+
2254
+ ### 7.3 — Screen Logic Implementation
2255
+
2256
+ > See: `references/screen-logic-patterns.md` — complete JSX implementations for every pattern below.
2257
+ > Read the matching section(s) and compose them into the screen component.
2258
+
2259
+ | screenLogic type | Implementation |
2260
+ |---|---|
2261
+ | Navigate to detail on tap | `onPress` → `navigation.navigate(...)` using fingerprint nav style |
2262
+ | Filter list | Local or Redux filter state, filtered `FlatList data` |
2263
+ | Summary card at top | `ListHeaderComponent` on FlatList |
2264
+ | Tab switcher | Tab bar component, state for active tab |
2265
+ | Pull to refresh | `RefreshControl` with refresh thunk dispatch |
2266
+ | Empty state | `ListEmptyComponent` |
2267
+ | Auth error + logout | Check `isAuthError`, render logout UI |
2268
+ | Pagination / load more | `onEndReached` with page state |
2269
+ | Search / query filter | `TextInput` with `useMemo` filtered array |
2270
+
2271
+ ---
2272
+
2273
+ ## PHASE 8 — Validation
2274
+
2275
+ > **Module mode**: run Phase 8 in a loop over every screen in `SCREENS[]`.
2276
+ > Check `ModuleOutputPaths` (mockConfig, diBootstrap) once after the per-screen loop.
2277
+
2278
+ ### 8.1 — Mapping Coverage
2279
+
2280
+ For every `responseMappings` entry of the current screen: verify it appears in the screen component.
2281
+ Missing mapping → FATAL. Fix before output.
2282
+
2283
+ ### 8.2 — File Checklist
2284
+
2285
+ Report a table of all expected files vs. actually generated files. Any layer
2286
+ that was `null` in the fingerprint is listed as `SKIPPED (not in project)` —
2287
+ not as missing.
2288
+
2289
+ ### 8.3 — Pattern Consistency
2290
+
2291
+ | Check | Rule |
2292
+ |---|---|
2293
+ | API client import matches fingerprint | No feature-local axios.create |
2294
+ | mockGlobalFlag checked before per-API flag | In every datasource method |
2295
+ | All mapper fields use `??` chaining | No bare `dto.field` |
2296
+ | Thunk uses `rejectWithValue` | Never throws from thunk |
2297
+ | Use case has zero framework imports | No React, Redux, or API lib |
2298
+ | No `any` (if fingerprint.noImplicitAny) | Use `unknown` |
2299
+ | Readonly entity fields (if fingerprint.tsStrict) | Applied |
2300
+ | Import aliases match fingerprint.aliasMap | Consistent with project |
2301
+ | Quote/semicolon style matches fingerprint | Consistent with prettier config |
2302
+
2303
+ ### 8.4 — Import Depth Verification
2304
+
2305
+ For each generated file: count actual directory depth from `appRoot`. Verify
2306
+ that relative imports compute to valid paths. Log any mismatch as FATAL.
2307
+
2308
+ ---
2309
+
2310
+ ## PHASE 9 — Output Summary
2311
+
2312
+ **Single mode summary:**
2313
+ ```
2314
+ === feature-generator OUTPUT SUMMARY ===
2315
+ Mode: single
2316
+ Architecture Fingerprint: [attached above]
2317
+ Screen: <ScreenName>
2318
+ Files generated: <N>
2319
+ Files skipped: <N> (layers not present in project)
2320
+ Mappings covered: <N>/<N> ✅
2321
+
2322
+ Generated:
2323
+ <list of PerScreenOutputPaths[ScreenName]>
2324
+ <ModuleOutputPaths.mockConfig>
2325
+ <ModuleOutputPaths.diBootstrap>
2326
+
2327
+ Skipped (layer not in project):
2328
+ <list of null layers>
2329
+
2330
+ Required manual steps:
2331
+ 1. Add fetch<ScreenName>UseCase to <fingerprint.storeConfigFile> extra argument
2332
+ 2. Register <ScreenName>Screen in <fingerprint.navScreenFile>
2333
+ 3. Set <operationId>.mockEnabled = true in mockConfig for local testing
2334
+ ==================================================
2335
+ ```
2336
+
2337
+ **Module mode summary:**
2338
+ ```
2339
+ === feature-generator MODULE SUMMARY ===
2340
+ Mode: module
2341
+ Module: <ModuleName>
2342
+ Screens: <N>
2343
+ Architecture Fingerprint: [attached above]
2344
+
2345
+ Module folder: <FEATURE_DIR>/
2346
+ diBootstrap.ts [MODULE-LEVEL]
2347
+ domain/
2348
+ models/
2349
+ shared/
2350
+ <SharedEntityName>.ts [SHARED — used by: ScreenA, ScreenB]
2351
+ <ScreenName1>Item.ts
2352
+ <ScreenName2>Item.ts
2353
+ repositories/
2354
+ I<ScreenName1>Repository.ts
2355
+ I<ScreenName2>Repository.ts
2356
+ useCases/
2357
+ Fetch<ScreenName1>UseCase.ts
2358
+ Fetch<ScreenName2>UseCase.ts
2359
+ data/
2360
+ datasources/
2361
+ mockConfig.ts [MODULE-LEVEL]
2362
+ <ScreenName1>Endpoints.ts
2363
+ <ScreenName2>Endpoints.ts
2364
+ <ScreenName1>ApiDataSource.ts
2365
+ <ScreenName2>ApiDataSource.ts
2366
+ dtos/
2367
+ <ScreenName1>Dto.ts
2368
+ <ScreenName2>Dto.ts
2369
+ mappers/
2370
+ <ScreenName1>Mapper.ts
2371
+ <ScreenName2>Mapper.ts
2372
+ repositories/
2373
+ <ScreenName1>RepositoryImpl.ts
2374
+ <ScreenName2>RepositoryImpl.ts
2375
+ state/
2376
+ store/
2377
+ <screenName1>Slice.ts
2378
+ <screenName2>Slice.ts
2379
+ selectors/
2380
+ <ScreenName1>Selectors.ts
2381
+ <ScreenName2>Selectors.ts
2382
+ presentation/
2383
+ screens/
2384
+ <ScreenName1>Screen/
2385
+ <ScreenName1>Screen.tsx
2386
+ <ScreenName2>Screen/
2387
+ <ScreenName2>Screen.tsx
2388
+
2389
+ Files generated: <N total across all screens>
2390
+ Files skipped: <N> (layers not present in project)
2391
+ Shared entities: <N>
2392
+
2393
+ Per-screen mapping coverage:
2394
+ <ScreenName1>: <N>/<N> mappings ✅
2395
+ <ScreenName2>: <N>/<N> mappings ✅
2396
+
2397
+ Required manual steps:
2398
+ 1. Add all slice reducers to <fingerprint.storeConfigFile>:
2399
+ <screenName1>: <sliceName1>Reducer
2400
+ <screenName2>: <sliceName2>Reducer
2401
+ 2. Add all use cases to store extra argument:
2402
+ fetch<ScreenName1>UseCase, fetch<ScreenName2>UseCase
2403
+ 3. Register all screens in <fingerprint.navScreenFile>:
2404
+ <ScreenName1>, <ScreenName2>
2405
+ 4. Set mockEnabled = true per screen in mockConfig for local testing
2406
+ ==================================================
2407
+ ```
2408
+
2409
+ > **Do NOT report completion to the user after PHASE 9.**
2410
+ > Proceed immediately to PHASE 10 — Post-Completion Validation.
2411
+
2412
+ ---
2413
+
2414
+ ## PHASE 10 — Post-Completion Validation & Auto-Fix
2415
+
2416
+ > **Run this phase after all files in PHASE 9 have been generated.**
2417
+ > Do NOT report completion to the user until this phase produces a `READY` status.
2418
+ > For every failed check: fix the issue, then re-run that specific check before proceeding to the next.
2419
+ > Never skip a check. Never mark a check as passed without verifying it.
2420
+ >
2421
+ > **Module mode**: run checks 10.1–10.7 in a loop over every screen in `SCREENS[]`.
2422
+ > Also validate `ModuleOutputPaths` (diBootstrap, mockConfig) once after the per-screen loop.
2423
+ > The 10.8 final report aggregates results across all screens.
2424
+
2425
+ ---
2426
+
2427
+ ### 10.1 — File Existence Check
2428
+
2429
+ For every path in `PerScreenOutputPaths[currentScreen]` AND (after the loop) `ModuleOutputPaths`:
2430
+ - Read the file — if it does not exist or is empty, regenerate it using the phase that produces it
2431
+ - Log: `MISSING → regenerating <path>`
2432
+
2433
+ Pass condition: every non-null path entry exists and has content.
2434
+
2435
+ ---
2436
+
2437
+ ### 10.2 — Import Resolution Check
2438
+
2439
+ For each generated file:
2440
+ - Read every import statement
2441
+ - For relative imports: verify the target file exists at the computed path
2442
+ - For alias imports: verify the alias prefix exists in `fingerprint.aliasMap`
2443
+ - If a broken import is found: correct the path using the fingerprint, rewrite the file
2444
+ - Log: `BROKEN IMPORT in <file>: <bad-path> → fixed to <correct-path>`
2445
+
2446
+ Pass condition: zero broken imports across all generated files.
2447
+
2448
+ ---
2449
+
2450
+ ### 10.3 — Response Mapping Coverage Check
2451
+
2452
+ For every entry in `RESPONSE_MAPPINGS` collected in PHASE -1 Q5:
2453
+ - Search the generated screen component for the `responseField` value
2454
+ - If a field is present in mappings but absent from the screen: add it
2455
+ - If a `transform` was specified but not applied: apply it using the matching rule from `assets/transform-rules.json`
2456
+ - Log: `UNMAPPED FIELD <responseField> → added to screen with transform: <transform or none>`
2457
+
2458
+ Pass condition: every `RESPONSE_MAPPINGS` entry appears in the screen component.
2459
+
2460
+ ---
2461
+
2462
+ ### 10.4 — Business Logic Coverage Check
2463
+
2464
+ For every rule in `BUSINESS_LOGIC_RULES` collected in PHASE -1 Q4:
2465
+ - Read the use case `execute()` method
2466
+ - Verify a guard clause or conditional exists that directly implements the rule
2467
+ - If a rule has no corresponding guard: add it to the use case
2468
+ - Log: `MISSING RULE "<rule>" → added guard clause to <useCase path>`
2469
+
2470
+ Pass condition: every business logic rule has a traceable guard clause in the use case.
2471
+
2472
+ ---
2473
+
2474
+ ### 10.5 — Test Case Coverage Check
2475
+
2476
+ *Skip this check with `N/A` if no test cases were provided in PHASE -1 Q3.*
2477
+
2478
+ For each entry in `TEST_CASES`:
2479
+ - `type: happy` — verify the primary success path exists: data loads, renders in FlatList/View, no error state shown
2480
+ - `type: edge` — verify the edge condition is handled: empty state component, boundary guard in use case, null-safe access
2481
+ - `type: error` — verify the error state is rendered: error message in screen, `rejectWithValue` in thunk, error field in state
2482
+ - If a scenario is unhandled: add the required handling to the appropriate file (use case, slice, or screen)
2483
+ - Log: `UNHANDLED TC-<id> "<description>" → fixed in <file>`
2484
+
2485
+ Pass condition: all test case scenarios have implementation coverage.
2486
+
2487
+ ---
2488
+
2489
+ ### 10.6 — User Story Coverage Check
2490
+
2491
+ *Skip this check with `N/A` if no user stories were provided in PHASE -1 Q2.*
2492
+
2493
+ For each entry in `USER_STORIES`:
2494
+ - Map the `action` and `benefit` to a feature behaviour (navigation, data display, interaction, feedback)
2495
+ - Verify that behaviour is implemented across: screen logic, state slice, or navigation wiring
2496
+ - If a story is not covered: identify the phase responsible and regenerate only the affected file(s)
2497
+ - Log: `UNCOVERED US-<id> "<story>" → fixed in <file>`
2498
+
2499
+ Pass condition: every user story action has a traceable implementation.
2500
+
2501
+ ---
2502
+
2503
+ ### 10.7 — Code Quality Check
2504
+
2505
+ Read each generated file and verify the following rules. Fix any violation in-place:
2506
+
2507
+ | Rule | Check |
2508
+ |---|---|
2509
+ | R3 — `??` chaining | No bare `dto.field` — must be `(dto.FieldA ?? dto.fieldA) ?? default` |
2510
+ | R4 — mockGlobalFlag order | `fingerprint.mockGlobalFlag` checked BEFORE per-operationId `mockEnabled` |
2511
+ | R7 — Use case purity | Use case file has zero imports from react, redux, axios, or any detected API lib |
2512
+ | R5 — Readonly fields | All entity interface fields are `readonly` when `fingerprint.tsStrict === true` |
2513
+ | No `any` | No `any` type used when `fingerprint.noImplicitAny === true` — use `unknown` |
2514
+ | R12 — Style consistency | Quote style, semicolons, and tab width match `fingerprint.quoteStyle / semi / tabWidth` |
2515
+
2516
+ Log: `CODE QUALITY: <rule> violation in <file> at line <approx> → fixed`
2517
+
2518
+ Pass condition: zero unfixed violations.
2519
+
2520
+ ---
2521
+
2522
+ ### 10.8 — Final Status Report
2523
+
2524
+ After all checks pass (or have been fixed and re-verified):
2525
+
2526
+ **Single mode report:**
2527
+ ```
2528
+ === PHASE 10 VALIDATION REPORT ===
2529
+ Mode: single
2530
+ Screen: <ScreenName>
2531
+ Files verified: <N>/<N>
2532
+ Imports resolved: <N>/<N>
2533
+ Mappings covered: <N>/<N>
2534
+ Business rules covered: <N>/<N>
2535
+ Test cases handled: <N>/<N> (or N/A)
2536
+ User stories covered: <N>/<N> (or N/A)
2537
+ Code quality checks: <N>/<N>
2538
+
2539
+ Auto-fixed issues:
2540
+ <list each MISSING / BROKEN / UNMAPPED / UNHANDLED / CODE QUALITY item that was fixed>
2541
+ ("None" if everything passed on first check)
2542
+
2543
+ Status: READY — all checks passed
2544
+ OR BLOCKED — <describe exactly what the user must provide to unblock>
2545
+ ===================================
2546
+ ```
2547
+
2548
+ **Module mode report:**
2549
+ ```
2550
+ === PHASE 10 MODULE VALIDATION REPORT ===
2551
+ Mode: module
2552
+ Module: <ModuleName>
2553
+ Screens validated: <N>
2554
+
2555
+ Per-screen results:
2556
+ <ScreenName1>:
2557
+ Files: <N>/<N> Imports: <N>/<N> Mappings: <N>/<N> Rules: <N>/<N>
2558
+ TC: <N>/<N> US: <N>/<N> Quality: <N>/<N>
2559
+ <ScreenName2>:
2560
+ Files: <N>/<N> Imports: <N>/<N> Mappings: <N>/<N> Rules: <N>/<N>
2561
+ TC: <N>/<N> US: <N>/<N> Quality: <N>/<N>
2562
+
2563
+ Module-level files:
2564
+ diBootstrap.ts: ✅ | ❌
2565
+ mockConfig.ts: ✅ | ❌
2566
+
2567
+ Totals:
2568
+ Files verified: <N>/<N>
2569
+ Imports resolved: <N>/<N>
2570
+ Mappings covered: <N>/<N>
2571
+ Business rules covered: <N>/<N>
2572
+ Test cases handled: <N>/<N> (or N/A)
2573
+ User stories covered: <N>/<N> (or N/A)
2574
+ Code quality checks: <N>/<N>
2575
+
2576
+ Auto-fixed issues:
2577
+ <list each MISSING / BROKEN / UNMAPPED / UNHANDLED / CODE QUALITY item with screen name prefix>
2578
+ ("None" if everything passed on first check)
2579
+
2580
+ Status: READY — all screens and module-level files passed
2581
+ OR BLOCKED — <describe exactly what input or clarification is needed per screen>
2582
+ ==========================================
2583
+ ```
2584
+
2585
+ Only report completion to the user after this report shows `READY`.
2586
+ If `BLOCKED`, describe exactly what input or clarification is needed and wait for the user.
2587
+
2588
+ ---
2589
+
2590
+ ## Universal Rules
2591
+
2592
+ ### R1 — Zero Hardcoded Paths
2593
+ No file, import path, folder name, or alias may be written without first
2594
+ deriving it from the Architecture Fingerprint. If the fingerprint cannot resolve
2595
+ it, log FATAL.
2596
+
2597
+ ### R2 — Fingerprint Is the Only Source of Truth
2598
+ The spec tells you WHAT to build. The fingerprint tells you HOW (paths, imports,
2599
+ patterns, naming). Never override fingerprint values with guesses.
2600
+
2601
+ ### R3 — Field Casing Always Uses `??` Chaining
2602
+ ```typescript
2603
+ // ✅
2604
+ const name = (dto.UserName ?? dto.userName) ?? '';
2605
+ // ❌
2606
+ const name = dto.UserName;
2607
+ ```
2608
+
2609
+ ### R4 — mockGlobalFlag Before Per-API Flag
2610
+ ```typescript
2611
+ // ✅
2612
+ if (mockConfig[fingerprint.mockGlobalFlag] || apiConfig.mockEnabled) { ... }
2613
+ // ❌
2614
+ if (apiConfig.mockEnabled || mockConfig[fingerprint.mockGlobalFlag]) { ... }
2615
+ ```
2616
+
2617
+ ### R5 — Entity Immutability
2618
+ `readonly` on all entity fields when `fingerprint.tsStrict === true`.
2619
+
2620
+ ### R6 — Mapping Coverage Is Mandatory
2621
+ Every `responseMappings` entry in the spec must appear in the screen. Missing
2622
+ entries block output (FATAL).
2623
+
2624
+ ### R7 — Business Logic Stays in Domain
2625
+ All spec `businessLogic` rules → use case `execute()` guard clauses only.
2626
+ Never in slice, datasource, or component.
2627
+
2628
+ ### R8 — Screen Logic Stays in Screen
2629
+ All spec `screenLogic` behaviour → screen component only.
2630
+ Never in use case or slice.
2631
+
2632
+ ### R9 — One Mapper Per Entity
2633
+ If the response produces two entity types → two mapper files.
2634
+
2635
+ ### R10 — Append, Never Overwrite DI
2636
+ When adding to a global DI file, append new exports only.
2637
+
2638
+ ### R11 — Skip, Don't Invent Missing Layers
2639
+ If a layer is `null` in the fingerprint, skip it with a WARN. Do not invent
2640
+ a folder that doesn't exist in the project.
2641
+
2642
+ ### R12 — Quote/Semicolon/Indent Style Matches Project
2643
+ Apply `fingerprint.quoteStyle`, `fingerprint.semi`, `fingerprint.tabWidth` to
2644
+ every generated file. Consistency with the existing codebase is non-negotiable.
2645
+
2646
+ ---
2647
+
2648
+ ## Decision Points
2649
+
2650
+ | Situation | Action |
2651
+ |---|---|
2652
+ | App root cannot be located | FATAL — ask user to specify |
2653
+ | Feature organisation style is ambiguous | Generate to dominant style; WARN about secondary |
2654
+ | Detected state lib is not redux-toolkit | Adapt generation to detected lib; do not use RTK patterns |
2655
+ | No envelope pattern detected | Generate plain request body without wrapper |
2656
+ | No mock system detected | Skip mockConfig; add TODO comment in datasource |
2657
+ | Import aliases found but not used in existing features | Set preferAliases = false; use relative paths |
2658
+ | Response is single object (not array) | Generate `mapFromDto` only; skip list mapper |
2659
+ | Response has deeply nested data | Generate nested sub-entity interfaces and mappers |
2660
+ | Multiple spec files provided | In **module mode**: all spec files belong to one shared feature folder. Run Phases 3–5, 7 per screen then Phase 6 once. In **single mode** with multiple files: treat as multiple independent features and run the full pipeline separately for each. |
2661
+ | Global DI file exists | Append to it; never overwrite |
2662
+ | Screen file already exists | Ask user before overwriting; offer to merge mappings |
2663
+ | Navigation not detected | Generate screen component without nav imports; WARN |
2664
+ | RootState type not locatable | Generate selector with `any` as state type; mark as FIXME |
2665
+ | `dtos` layer is null | Inline DTO type inside mapper file |
2666
+ | `selectors` layer is null | Inline selectors at bottom of slice file |
2667
+
2668
+ ---
2669
+
2670
+ ## Integration with flutter-rn-orchestrator
2671
+
2672
+ When called via the orchestrator:
2673
+ - **Skip Phase 0** — use the GSD artifacts (`ARCHITECTURE.md`, `STRUCTURE.md`,
2674
+ `CONVENTIONS.md`, `INTEGRATIONS.md`, `STACK.md`) as the fingerprint source.
2675
+ Parse those files to build the fingerprint instead of crawling.
2676
+ - Spec file is derived from the orchestrator's layout and domain analysis artifacts.
2677
+ - Output file paths are written to the orchestrator's `artifacts/` inventory.
2678
+
2679
+ ---
2680
+
2681
+ ## Example Spec File
2682
+
2683
+ ```markdown
2684
+ # Feature Spec: Transaction History
2685
+
2686
+ ## Screen Name
2687
+ TransactionHistory
2688
+
2689
+ ## API URL
2690
+ /api/v1/portfolio/transactions
2691
+
2692
+ ## HTTP Method
2693
+ POST
2694
+
2695
+ ## Request Body
2696
+ ```json
2697
+ {
2698
+ "ClientCode": 12345,
2699
+ "SessionID": "abc-session-xyz",
2700
+ "FamilyFlag": 0
2701
+ }
2702
+ ```
2703
+
2704
+ ## Response Shape
2705
+ ```json
2706
+ {
2707
+ "Status": "success",
2708
+ "Data": [
2709
+ {
2710
+ "TransactionID": "TXN001",
2711
+ "FundName": "SBI Bluechip Fund",
2712
+ "Amount": 5000.00,
2713
+ "TransactionDate": "2024-01-15",
2714
+ "TransactionType": "Purchase",
2715
+ "Units": 12.345,
2716
+ "NAV": 405.23
2717
+ }
2718
+ ]
2719
+ }
2720
+ ```
2721
+
2722
+ ## Business Logic
2723
+ - Only show transactions where Amount > 0
2724
+ - Transactions older than 7 years should be marked as "Archived"
2725
+ - If Status is not "success", treat the response as an error
2726
+
2727
+ ## Screen Logic
2728
+ - Fetch transaction history on screen mount
2729
+ - Support pull-to-refresh
2730
+ - Navigate to TransactionDetail screen when user taps a transaction row
2731
+ - Show empty state message "No transactions found" when list is empty
2732
+
2733
+ ## Response Mapping
2734
+ - `Data[].TransactionID` → unique key for each list row (not visible to user)
2735
+ - `Data[].FundName` → primary title of each row
2736
+ - `Data[].Amount` → below FundName, formatted as Indian currency (₹)
2737
+ - `Data[].TransactionDate` → subtitle, formatted as "15 Jan 2024"
2738
+ - `Data[].TransactionType` → badge: green for Purchase, red for Redemption
2739
+ - `Data[].Units` → detail row: "Units: 12.345"
2740
+ - `Data[].NAV` → detail row: "NAV: ₹405.23"
2741
+ ```