moai-adk 0.4.5__py3-none-any.whl → 0.20.1__py3-none-any.whl

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.

Potentially problematic release.


This version of moai-adk might be problematic. Click here for more details.

Files changed (433) hide show
  1. moai_adk/__init__.py +1 -1
  2. moai_adk/__main__.py +74 -1
  3. moai_adk/cli/commands/__init__.py +1 -1
  4. moai_adk/cli/commands/analyze.py +119 -0
  5. moai_adk/cli/commands/backup.py +25 -1
  6. moai_adk/cli/commands/doctor.py +31 -5
  7. moai_adk/cli/commands/improve_user_experience.py +307 -0
  8. moai_adk/cli/commands/init.py +111 -10
  9. moai_adk/cli/commands/status.py +33 -3
  10. moai_adk/cli/commands/update.py +921 -130
  11. moai_adk/cli/commands/validate_links.py +120 -0
  12. moai_adk/cli/prompts/init_prompts.py +22 -87
  13. moai_adk/core/analysis/__init__.py +9 -0
  14. moai_adk/core/analysis/session_analyzer.py +388 -0
  15. moai_adk/core/analysis/tag_chain_analyzer.py +344 -0
  16. moai_adk/core/analysis/tag_chain_repair.py +879 -0
  17. moai_adk/core/config/__init__.py +19 -0
  18. moai_adk/core/config/migration.py +235 -0
  19. moai_adk/core/git/__init__.py +1 -1
  20. moai_adk/core/git/branch.py +1 -1
  21. moai_adk/core/git/commit.py +1 -1
  22. moai_adk/core/git/manager.py +1 -1
  23. moai_adk/core/issue_creator.py +313 -0
  24. moai_adk/core/mcp/setup.py +56 -0
  25. moai_adk/core/mcp/setup_old.py +296 -0
  26. moai_adk/core/project/backup_utils.py +1 -1
  27. moai_adk/core/project/checker.py +2 -2
  28. moai_adk/core/project/detector.py +211 -12
  29. moai_adk/core/project/initializer.py +85 -15
  30. moai_adk/core/project/phase_executor.py +76 -13
  31. moai_adk/core/project/validator.py +13 -13
  32. moai_adk/core/quality/__init__.py +1 -1
  33. moai_adk/core/quality/trust_checker.py +1 -1
  34. moai_adk/core/quality/validators/__init__.py +1 -1
  35. moai_adk/core/quality/validators/base_validator.py +1 -1
  36. moai_adk/core/tags/__init__.py +86 -0
  37. moai_adk/core/tags/auto_corrector.py +693 -0
  38. moai_adk/core/tags/ci_validator.py +463 -0
  39. moai_adk/core/tags/cli.py +283 -0
  40. moai_adk/core/tags/generator.py +109 -0
  41. moai_adk/core/tags/inserter.py +99 -0
  42. moai_adk/core/tags/mapper.py +126 -0
  43. moai_adk/core/tags/parser.py +76 -0
  44. moai_adk/core/tags/policy_validator.py +580 -0
  45. moai_adk/core/tags/pre_commit_validator.py +421 -0
  46. moai_adk/core/tags/reporter.py +956 -0
  47. moai_adk/core/tags/rollback_manager.py +525 -0
  48. moai_adk/core/tags/tags.py +149 -0
  49. moai_adk/core/tags/validator.py +897 -0
  50. moai_adk/core/template/__init__.py +1 -1
  51. moai_adk/core/template/backup.py +1 -1
  52. moai_adk/core/template/merger.py +50 -1
  53. moai_adk/core/template/processor.py +119 -13
  54. moai_adk/core/template_engine.py +268 -0
  55. moai_adk/templates/.claude/agents/alfred/backend-expert.md +348 -0
  56. moai_adk/templates/.claude/agents/alfred/cc-manager.md +209 -944
  57. moai_adk/templates/.claude/agents/alfred/database-expert.md +352 -0
  58. moai_adk/templates/.claude/agents/alfred/debug-helper.md +34 -5
  59. moai_adk/templates/.claude/agents/alfred/devops-expert.md +464 -0
  60. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +38 -8
  61. moai_adk/templates/.claude/agents/alfred/format-expert.md +469 -0
  62. moai_adk/templates/.claude/agents/alfred/frontend-expert.md +357 -0
  63. moai_adk/templates/.claude/agents/alfred/git-manager.md +128 -9
  64. moai_adk/templates/.claude/agents/alfred/implementation-planner.md +104 -6
  65. moai_adk/templates/.claude/agents/alfred/project-manager.md +88 -16
  66. moai_adk/templates/.claude/agents/alfred/quality-gate.md +36 -9
  67. moai_adk/templates/.claude/agents/alfred/security-expert.md +270 -0
  68. moai_adk/templates/.claude/agents/alfred/skill-factory.md +865 -0
  69. moai_adk/templates/.claude/agents/alfred/spec-builder.md +214 -43
  70. moai_adk/templates/.claude/agents/alfred/tag-agent.md +111 -9
  71. moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +309 -160
  72. moai_adk/templates/.claude/agents/alfred/trust-checker.md +36 -7
  73. moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +605 -0
  74. moai_adk/templates/.claude/commands/alfred/0-project.md +393 -966
  75. moai_adk/templates/.claude/commands/alfred/1-plan.md +651 -367
  76. moai_adk/templates/.claude/commands/alfred/2-run.md +388 -241
  77. moai_adk/templates/.claude/commands/alfred/3-sync.md +1921 -410
  78. moai_adk/templates/.claude/commands/alfred/9-feedback.md +153 -0
  79. moai_adk/templates/.claude/commands/alfred/release-new.md +3604 -0
  80. moai_adk/templates/.claude/hooks/alfred/core/project.py +484 -20
  81. moai_adk/templates/.claude/hooks/alfred/core/timeout.py +136 -0
  82. moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +108 -0
  83. moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +198 -0
  84. moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +14 -6
  85. moai_adk/templates/.claude/hooks/alfred/post_tool__enable_streaming_ui.py +50 -0
  86. moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +93 -0
  87. moai_adk/templates/.claude/hooks/alfred/post_tool__tag_auto_corrector.py +407 -0
  88. moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +99 -0
  89. moai_adk/templates/.claude/hooks/alfred/pre_tool__realtime_tag_monitor.py +335 -0
  90. moai_adk/templates/.claude/hooks/alfred/pre_tool__tag_policy_validator.py +325 -0
  91. moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +93 -0
  92. moai_adk/templates/.claude/hooks/alfred/session_start__auto_cleanup.py +580 -0
  93. moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +298 -0
  94. moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +170 -0
  95. moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/checkpoint.py +3 -3
  96. moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/context.py +5 -5
  97. moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +749 -0
  98. moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +230 -0
  99. moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +198 -0
  100. moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +21 -0
  101. moai_adk/templates/.claude/hooks/alfred/shared/handlers/daily_analysis.py +351 -0
  102. moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +154 -0
  103. moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +174 -0
  104. moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +87 -0
  105. moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +61 -0
  106. moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +111 -0
  107. moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +1 -0
  108. moai_adk/templates/.claude/hooks/alfred/utils/hook_config.py +94 -0
  109. moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +161 -0
  110. moai_adk/templates/.claude/output-styles/alfred/alfred-moai-adk-beginner.md +267 -0
  111. moai_adk/templates/.claude/output-styles/alfred/keating-personal-tutor.md +440 -0
  112. moai_adk/templates/.claude/output-styles/alfred/r2d2-agentic-coding.md +583 -0
  113. moai_adk/templates/.claude/settings.json +96 -14
  114. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +70 -0
  115. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +62 -0
  116. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +242 -0
  117. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/SKILL.md +237 -0
  118. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/examples.md +871 -0
  119. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/reference.md +653 -0
  120. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/README.md +162 -0
  121. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/SKILL.md +227 -0
  122. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/examples.md +354 -0
  123. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/reference.md +158 -0
  124. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/SKILL.md +179 -79
  125. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/examples.md +117 -0
  126. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/scripts/pre-review-check.sh +62 -0
  127. moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +132 -0
  128. moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +28 -0
  129. moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +444 -0
  130. moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +62 -0
  131. moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +28 -0
  132. moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +405 -0
  133. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +51 -0
  134. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +355 -0
  135. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +239 -0
  136. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +323 -0
  137. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +286 -0
  138. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +126 -0
  139. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +229 -0
  140. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +4 -0
  141. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +150 -0
  142. moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +87 -73
  143. moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +29 -0
  144. moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +28 -0
  145. moai_adk/templates/.claude/skills/moai-alfred-personas/README.md +42 -0
  146. moai_adk/templates/.claude/skills/moai-alfred-personas/SKILL.md +429 -0
  147. moai_adk/templates/.claude/skills/moai-alfred-personas/examples.md +520 -0
  148. moai_adk/templates/.claude/skills/moai-alfred-personas/reference.md +405 -0
  149. moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +89 -0
  150. moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +122 -0
  151. moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +369 -0
  152. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +508 -0
  153. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +481 -0
  154. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +100 -0
  155. moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +77 -0
  156. moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +265 -0
  157. moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +539 -0
  158. moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +320 -0
  159. moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +4 -0
  160. moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +84 -0
  161. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +137 -0
  162. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +219 -0
  163. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +161 -0
  164. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +541 -0
  165. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +622 -0
  166. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +19 -0
  167. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +4 -0
  168. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +211 -0
  169. moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +288 -0
  170. moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +269 -0
  171. moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +32 -0
  172. moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +298 -0
  173. moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +26 -0
  174. moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +307 -0
  175. moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +21 -0
  176. moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +252 -0
  177. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +19 -0
  178. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +19 -0
  179. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +24 -0
  180. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +199 -0
  181. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +39 -0
  182. moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +316 -0
  183. moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +18 -0
  184. moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +263 -0
  185. moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +30 -0
  186. moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +482 -0
  187. moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +303 -0
  188. moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +524 -0
  189. moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +477 -0
  190. moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +429 -0
  191. moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +391 -0
  192. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +431 -0
  193. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +577 -0
  194. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +273 -0
  195. moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +466 -0
  196. moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +583 -0
  197. moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +526 -0
  198. moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +608 -0
  199. moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +328 -0
  200. moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +312 -0
  201. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +245 -0
  202. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +285 -0
  203. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +278 -0
  204. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +303 -0
  205. moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +291 -0
  206. moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +15 -0
  207. moai_adk/templates/.claude/skills/moai-change-logger/SKILL.md +563 -0
  208. moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +802 -0
  209. moai_adk/templates/.claude/skills/moai-design-systems/examples.md +1238 -0
  210. moai_adk/templates/.claude/skills/moai-design-systems/reference.md +673 -0
  211. moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +234 -43
  212. moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +1633 -0
  213. moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +660 -0
  214. moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +97 -69
  215. moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +29 -0
  216. moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +30 -0
  217. moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +97 -72
  218. moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +29 -0
  219. moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +30 -0
  220. moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +97 -74
  221. moai_adk/templates/.claude/skills/moai-domain-database/examples.md +29 -0
  222. moai_adk/templates/.claude/skills/moai-domain-database/reference.md +30 -0
  223. moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +98 -74
  224. moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +29 -0
  225. moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +31 -0
  226. moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +102 -73
  227. moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +29 -0
  228. moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +31 -0
  229. moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +97 -73
  230. moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +29 -0
  231. moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +30 -0
  232. moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +97 -67
  233. moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +29 -0
  234. moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +30 -0
  235. moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +97 -79
  236. moai_adk/templates/.claude/skills/moai-domain-security/examples.md +29 -0
  237. moai_adk/templates/.claude/skills/moai-domain-security/reference.md +30 -0
  238. moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +97 -71
  239. moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +29 -0
  240. moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +30 -0
  241. moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +265 -64
  242. moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +1064 -0
  243. moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +1047 -0
  244. moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +87 -78
  245. moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +29 -0
  246. moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +28 -0
  247. moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +87 -70
  248. moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +29 -0
  249. moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +28 -0
  250. moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +87 -86
  251. moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +29 -0
  252. moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +28 -0
  253. moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +80 -62
  254. moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +29 -0
  255. moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +28 -0
  256. moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +207 -50
  257. moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +29 -0
  258. moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +29 -0
  259. moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +90 -71
  260. moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +29 -0
  261. moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +28 -0
  262. moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +78 -58
  263. moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +29 -0
  264. moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +28 -0
  265. moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +78 -51
  266. moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +29 -0
  267. moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +28 -0
  268. moai_adk/templates/.claude/skills/moai-foundation-trust/.!11330!examples.md +0 -0
  269. moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +253 -32
  270. moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
  271. moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +1099 -0
  272. moai_adk/templates/.claude/skills/moai-jit-docs-enhanced/SKILL.md +460 -0
  273. moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +98 -74
  274. moai_adk/templates/.claude/skills/moai-lang-c/examples.md +29 -0
  275. moai_adk/templates/.claude/skills/moai-lang-c/reference.md +31 -0
  276. moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +98 -76
  277. moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +29 -0
  278. moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +31 -0
  279. moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +2358 -70
  280. moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +29 -0
  281. moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +30 -0
  282. moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +2962 -68
  283. moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +29 -0
  284. moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +30 -0
  285. moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +1898 -70
  286. moai_adk/templates/.claude/skills/moai-lang-go/examples.md +29 -0
  287. moai_adk/templates/.claude/skills/moai-lang-go/reference.md +31 -0
  288. moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +1465 -68
  289. moai_adk/templates/.claude/skills/moai-lang-java/examples.md +29 -0
  290. moai_adk/templates/.claude/skills/moai-lang-java/reference.md +31 -0
  291. moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +2364 -66
  292. moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +29 -0
  293. moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +32 -0
  294. moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +1630 -69
  295. moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +29 -0
  296. moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +31 -0
  297. moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +89 -61
  298. moai_adk/templates/.claude/skills/moai-lang-php/examples.md +29 -0
  299. moai_adk/templates/.claude/skills/moai-lang-php/reference.md +30 -0
  300. moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +735 -66
  301. moai_adk/templates/.claude/skills/moai-lang-python/examples.md +624 -0
  302. moai_adk/templates/.claude/skills/moai-lang-python/reference.md +316 -0
  303. moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +97 -73
  304. moai_adk/templates/.claude/skills/moai-lang-r/examples.md +29 -0
  305. moai_adk/templates/.claude/skills/moai-lang-r/reference.md +30 -0
  306. moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +98 -73
  307. moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +29 -0
  308. moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +31 -0
  309. moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +1834 -70
  310. moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +29 -0
  311. moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +31 -0
  312. moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +99 -74
  313. moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +29 -0
  314. moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +30 -0
  315. moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +97 -74
  316. moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +29 -0
  317. moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +30 -0
  318. moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +98 -74
  319. moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +29 -0
  320. moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +31 -0
  321. moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +1959 -69
  322. moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +29 -0
  323. moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +30 -0
  324. moai_adk/templates/.claude/skills/moai-lang-template/SKILL.md +348 -0
  325. moai_adk/templates/.claude/skills/moai-lang-template/VARIABLES.md +98 -0
  326. moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +1230 -66
  327. moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +29 -0
  328. moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +34 -0
  329. moai_adk/templates/.claude/skills/moai-learning-optimizer/SKILL.md +575 -0
  330. moai_adk/templates/.claude/skills/moai-project-batch-questions/README.md +50 -0
  331. moai_adk/templates/.claude/skills/moai-project-batch-questions/SKILL.md +304 -0
  332. moai_adk/templates/.claude/skills/moai-project-batch-questions/examples.md +417 -0
  333. moai_adk/templates/.claude/skills/moai-project-batch-questions/reference.md +704 -0
  334. moai_adk/templates/.claude/skills/moai-project-config-manager/README.md +87 -0
  335. moai_adk/templates/.claude/skills/moai-project-config-manager/SKILL.md +552 -0
  336. moai_adk/templates/.claude/skills/moai-project-config-manager/examples.md +1109 -0
  337. moai_adk/templates/.claude/skills/moai-project-config-manager/reference.md +514 -0
  338. moai_adk/templates/.claude/skills/moai-project-config-manager/validate.py +106 -0
  339. moai_adk/templates/.claude/skills/moai-project-documentation/README.md +11 -0
  340. moai_adk/templates/.claude/skills/moai-project-documentation/SKILL.md +622 -0
  341. moai_adk/templates/.claude/skills/moai-project-documentation/examples.md +20 -0
  342. moai_adk/templates/.claude/skills/moai-project-documentation/reference.md +12 -0
  343. moai_adk/templates/.claude/skills/moai-project-language-initializer/README.md +152 -0
  344. moai_adk/templates/.claude/skills/moai-project-language-initializer/SKILL.md +285 -0
  345. moai_adk/templates/.claude/skills/moai-project-language-initializer/examples.md +333 -0
  346. moai_adk/templates/.claude/skills/moai-project-language-initializer/reference.md +386 -0
  347. moai_adk/templates/.claude/skills/moai-project-template-optimizer/README.md +49 -0
  348. moai_adk/templates/.claude/skills/moai-project-template-optimizer/SKILL.md +319 -0
  349. moai_adk/templates/.claude/skills/moai-project-template-optimizer/examples.md +58 -0
  350. moai_adk/templates/.claude/skills/moai-project-template-optimizer/reference.md +123 -0
  351. moai_adk/templates/.claude/skills/moai-session-info/SKILL.md +314 -0
  352. moai_adk/templates/.claude/skills/moai-streaming-ui/SKILL.md +552 -0
  353. moai_adk/templates/.claude/skills/moai-tag-policy-validator/SKILL.md +570 -0
  354. moai_adk/templates/.git-hooks/pre-commit +66 -0
  355. moai_adk/templates/.git-hooks/pre-push +255 -0
  356. moai_adk/templates/.github/workflows/c-tag-validation.yml +11 -0
  357. moai_adk/templates/.github/workflows/cpp-tag-validation.yml +11 -0
  358. moai_adk/templates/.github/workflows/csharp-tag-validation.yml +11 -0
  359. moai_adk/templates/.github/workflows/dart-tag-validation.yml +11 -0
  360. moai_adk/templates/.github/workflows/go-tag-validation.yml +130 -0
  361. moai_adk/templates/.github/workflows/java-tag-validation.yml +11 -0
  362. moai_adk/templates/.github/workflows/javascript-tag-validation.yml +135 -0
  363. moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +11 -0
  364. moai_adk/templates/.github/workflows/moai-gitflow.yml +166 -3
  365. moai_adk/templates/.github/workflows/moai-release-create.yml +100 -0
  366. moai_adk/templates/.github/workflows/moai-release-pipeline.yml +188 -0
  367. moai_adk/templates/.github/workflows/php-tag-validation.yml +11 -0
  368. moai_adk/templates/.github/workflows/python-tag-validation.yml +118 -0
  369. moai_adk/templates/.github/workflows/release.yml +118 -0
  370. moai_adk/templates/.github/workflows/ruby-tag-validation.yml +11 -0
  371. moai_adk/templates/.github/workflows/rust-tag-validation.yml +11 -0
  372. moai_adk/templates/.github/workflows/shell-tag-validation.yml +11 -0
  373. moai_adk/templates/.github/workflows/spec-issue-sync.yml +338 -0
  374. moai_adk/templates/.github/workflows/swift-tag-validation.yml +11 -0
  375. moai_adk/templates/.github/workflows/tag-report.yml +269 -0
  376. moai_adk/templates/.github/workflows/tag-validation.yml +186 -0
  377. moai_adk/templates/.github/workflows/typescript-tag-validation.yml +154 -0
  378. moai_adk/templates/.mcp.json +31 -0
  379. moai_adk/templates/.moai/config.json +80 -7
  380. moai_adk/templates/CLAUDE.md +562 -546
  381. moai_adk/utils/banner.py +5 -5
  382. moai_adk/utils/common.py +294 -0
  383. moai_adk/utils/link_validator.py +235 -0
  384. moai_adk/utils/logger.py +8 -8
  385. moai_adk/utils/user_experience.py +451 -0
  386. moai_adk-0.20.1.dist-info/METADATA +233 -0
  387. moai_adk-0.20.1.dist-info/RECORD +404 -0
  388. moai_adk/templates/.claude/hooks/alfred/README.md +0 -230
  389. moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -156
  390. moai_adk/templates/.claude/hooks/alfred/core/__init__.py +0 -85
  391. moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +0 -25
  392. moai_adk/templates/.claude/hooks/alfred/handlers/session.py +0 -92
  393. moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +0 -70
  394. moai_adk/templates/.claude/hooks/alfred/handlers/user.py +0 -41
  395. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -636
  396. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -692
  397. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -470
  398. moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/SKILL.md +0 -103
  399. moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -103
  400. moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -95
  401. moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/SKILL.md +0 -105
  402. moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/SKILL.md +0 -97
  403. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -97
  404. moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -90
  405. moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -99
  406. moai_adk/templates/.claude/skills/moai-alfred-tui-survey/SKILL.md +0 -87
  407. moai_adk/templates/.claude/skills/moai-alfred-tui-survey/examples.md +0 -62
  408. moai_adk/templates/.claude/skills/moai-claude-code/SKILL.md +0 -94
  409. moai_adk/templates/.claude/skills/moai-claude-code/examples.md +0 -513
  410. moai_adk/templates/.claude/skills/moai-claude-code/reference.md +0 -433
  411. moai_adk/templates/.claude/skills/moai-claude-code/templates/agent-full.md +0 -332
  412. moai_adk/templates/.claude/skills/moai-claude-code/templates/command-full.md +0 -384
  413. moai_adk/templates/.claude/skills/moai-claude-code/templates/plugin-full.json +0 -363
  414. moai_adk/templates/.claude/skills/moai-claude-code/templates/settings-full.json +0 -595
  415. moai_adk/templates/.claude/skills/moai-claude-code/templates/skill-full.md +0 -496
  416. moai_adk/templates/.claude/skills/moai-lang-clojure/SKILL.md +0 -100
  417. moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +0 -99
  418. moai_adk/templates/.claude/skills/moai-lang-haskell/SKILL.md +0 -100
  419. moai_adk/templates/.claude/skills/moai-lang-julia/SKILL.md +0 -98
  420. moai_adk/templates/.claude/skills/moai-lang-lua/SKILL.md +0 -98
  421. moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -69
  422. moai_adk/templates/.moai/memory/development-guide.md +0 -344
  423. moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -220
  424. moai_adk/templates/.moai/memory/spec-metadata.md +0 -356
  425. moai_adk/templates/.moai/project/product.md +0 -161
  426. moai_adk/templates/.moai/project/structure.md +0 -156
  427. moai_adk/templates/.moai/project/tech.md +0 -227
  428. moai_adk/templates/__init__.py +0 -2
  429. moai_adk-0.4.5.dist-info/METADATA +0 -369
  430. moai_adk-0.4.5.dist-info/RECORD +0 -152
  431. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/WHEEL +0 -0
  432. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/entry_points.txt +0 -0
  433. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,98 +1,2992 @@
1
1
  ---
2
-
3
2
  name: moai-lang-dart
4
- description: Dart best practices with flutter test, dart analyze, and Flutter widget patterns. Use when writing or reviewing Dart/Flutter code in project workflows.
3
+ version: 2.0.0
4
+ created: 2025-11-06
5
+ updated: 2025-11-06
6
+ status: active
7
+ description: "Dart best practices with Flutter mobile development, async programming, and server-side Dart for 2025"
8
+ keywords: [dart, programming, flutter, mobile, async, server-side, development]
5
9
  allowed-tools:
6
10
  - Read
11
+ - Write
12
+ - Edit
7
13
  - Bash
14
+ - WebFetch
15
+ - WebSearch
8
16
  ---
9
17
 
10
- # Dart Expert
18
+ # Dart Development Mastery
19
+
20
+ **Modern Dart Development with 2025 Best Practices**
21
+
22
+ > Comprehensive Dart development guidance covering Flutter mobile applications, async programming patterns, server-side development, and cross-platform solutions using the latest tools and frameworks.
23
+
24
+ ## What It Does
11
25
 
12
- ## Skill Metadata
13
- | Field | Value |
14
- | ----- | ----- |
15
- | Allowed tools | Read (read_file), Bash (terminal) |
16
- | Auto-load | On demand when language keywords are detected |
17
- | Trigger cues | Dart code discussions, framework guidance, or file extensions such as .dart. |
18
- | Tier | 3 |
26
+ ### Flutter Mobile Development
27
+ - **Mobile App Development**: Flutter 3.x with Material Design 3 and Cupertino widgets
28
+ - **State Management**: Provider, Riverpod, BLoC patterns for scalable applications
29
+ - **Navigation**: Go Router for declarative routing and deep linking
30
+ - **Performance**: Widget optimization, lazy loading, memory management
19
31
 
20
- ## What it does
32
+ ### Server-Side Development
33
+ - **Web APIs**: Shelf, Dart Frog, or Aqueduct for backend services
34
+ - **Database Integration**: PostgreSQL, MongoDB with async drivers
35
+ - **Real-time Communication**: WebSockets, gRPC with Dart's async capabilities
36
+ - **Testing**: Unit tests, widget tests, integration tests with Dart test framework
21
37
 
22
- Provides Dart-specific expertise for TDD development, including flutter test framework, dart analyze linting, and Flutter widget patterns for cross-platform app development.
38
+ ### Cross-Platform Development
39
+ - **Flutter for Multiple Platforms**: iOS, Android, Web, Desktop, and Embedded
40
+ - **Shared Codebases**: Dart packages for business logic across platforms
41
+ - **Platform-Specific APIs**: Method channels for native integration
23
42
 
24
- ## When to use
43
+ ## When to Use
25
44
 
26
- - Engages when the conversation references Dart work, frameworks, or files like .dart.
27
- - “Writing Dart tests”, “Flutter widget patterns”, “How to use flutter tests”
28
- - Automatically invoked when working with Dart/Flutter projects
29
- - Dart SPEC implementation (`/alfred:2-run`)
45
+ ### Perfect Scenarios
46
+ - **Building cross-platform mobile applications with Flutter**
47
+ - **Developing scalable Flutter apps with modern state management**
48
+ - **Creating server-side APIs with Dart**
49
+ - **Implementing real-time applications with WebSockets**
50
+ - **Building web applications with Flutter Web**
51
+ - **Developing desktop applications with Flutter Desktop**
52
+ - **Creating embedded systems applications**
30
53
 
31
- ## How it works
54
+ ### Common Triggers
55
+ - "Create Flutter app"
56
+ - "Build Dart web API"
57
+ - "Implement Flutter state management"
58
+ - "Optimize Flutter performance"
59
+ - "Test Flutter application"
60
+ - "Dart best practices"
32
61
 
33
- **TDD Framework**:
34
- - **flutter test**: Built-in test framework
35
- - **mockito**: Mocking library for Dart
36
- - **Widget testing**: Test Flutter widgets
37
- - Test coverage with `flutter test --coverage`
62
+ ## Tool Version Matrix (2025-11-06)
38
63
 
39
- **Code Quality**:
40
- - **dart analyze**: Static analysis tool
41
- - **dart format**: Code formatting
42
- - **very_good_analysis**: Strict lint rules
64
+ ### Core Dart/Flutter
65
+ - **Dart**: 3.5.x (current) / 3.4.x (LTS)
66
+ - **Flutter**: 3.24.x (current) / 3.22.x (LTS)
67
+ - **Dart SDK**: 3.5.0
68
+ - **Package Manager**: pub (built-in)
43
69
 
44
- **Package Management**:
45
- - **pub**: Package manager (pub.dev)
46
- - **pubspec.yaml**: Dependency configuration
47
- - Flutter SDK version management
70
+ ### Flutter Frameworks
71
+ - **Material Design**: 3.x (Material 3)
72
+ - **Cupertino Widgets**: iOS 17+ support
73
+ - **Go Router**: 13.x - Declarative routing
74
+ - **Riverpod**: 2.5.x - Reactive state management
75
+ - **BLoC**: 8.1.x - State management library
48
76
 
49
- **Flutter Patterns**:
50
- - **StatelessWidget/StatefulWidget**: UI components
51
- - **Provider/Riverpod**: State management
52
- - **BLoC**: Business logic separation
53
- - **Navigator**: Routing and navigation
77
+ ### Testing Tools
78
+ - **Dart Test**: Built-in testing framework
79
+ - **Flutter Test**: Widget and integration testing
80
+ - **Mockito**: 5.4.x - Mocking framework
81
+ - **Golden Tests**: Widget screenshot testing
82
+ - **Integration Test**: End-to-end testing
54
83
 
55
- **Best Practices**:
56
- - File ≤300 LOC, function ≤50 LOC
57
- - Prefer `const` constructors for immutable widgets
58
- - Use `final` for immutable fields
59
- - Widget composition over inheritance
84
+ ### Development Tools
85
+ - **Flutter CLI**: 3.24.x
86
+ - **Dart DevTools**: Web-based debugging tools
87
+ - **Android Studio**: Dolphin 2024.x
88
+ - **VS Code**: Flutter extension
89
+
90
+ ### Backend Tools
91
+ - **Shelf**: 1.4.x - Web server framework
92
+ - **Dart Frog**: 1.0.x - Server-side framework
93
+ - **Aqueduct**: 7.x - Full-stack framework
94
+ - **MongoDB Dart Driver**: 4.12.x
95
+
96
+ ## Ecosystem Overview
97
+
98
+ ### Package Management
60
99
 
61
- ## Examples
62
100
  ```bash
63
- dart test && dart analyze
101
+ # Create new Flutter project
102
+ flutter create my_app
103
+ flutter create --org com.example --platforms=web,desktop my_app
104
+
105
+ # Create new Dart project
106
+ dart create my_dart_app
107
+
108
+ # Add dependencies
109
+ flutter pub add provider riverpod go_router
110
+ flutter pub add dio retrofit json_annotation
111
+ dart pub add shelf shelf_router
112
+
113
+ # Get dependencies
114
+ flutter pub get
115
+ dart pub get
116
+
117
+ # Run and build
118
+ flutter run
119
+ flutter run --release
120
+ flutter build apk
121
+ flutter build web
122
+ dart run
123
+ ```
124
+
125
+ ### Project Structure (2025 Best Practice)
126
+
127
+ ```
128
+ my_flutter_app/
129
+ ├── lib/
130
+ │ ├── main.dart # App entry point
131
+ │ ├── app.dart # App configuration
132
+ │ ├── core/ # Core utilities
133
+ │ │ ├── constants/ # App constants
134
+ │ │ ├── errors/ # Custom error classes
135
+ │ │ ├── extensions/ # Dart extensions
136
+ │ │ ├── network/ # Network configuration
137
+ │ │ ├── themes/ # App themes
138
+ │ │ └── utils/ # Utility functions
139
+ │ ├── features/ # Feature modules
140
+ │ │ ├── authentication/ # Auth feature
141
+ │ │ │ ├── data/ # Data layer (repositories, data sources)
142
+ │ │ │ ├── domain/ # Domain layer (entities, use cases)
143
+ │ │ │ └── presentation/ # UI layer (pages, widgets, providers)
144
+ │ │ ├── user_profile/ # User profile feature
145
+ │ │ └── settings/ # Settings feature
146
+ │ ├── shared/ # Shared components
147
+ │ │ ├── widgets/ # Reusable widgets
148
+ │ │ ├── models/ # Shared data models
149
+ │ │ ├── services/ # Shared services
150
+ │ │ └── providers/ # Shared providers
151
+ │ └── routes/ # App routes
152
+ ├── test/ # Test files
153
+ │ ├── unit/ # Unit tests
154
+ │ ├── widget/ # Widget tests
155
+ │ └── integration/ # Integration tests
156
+ ├── assets/ # Static assets
157
+ ├── pubspec.yaml # Dependencies
158
+ └── analysis_options.yaml # Linting rules
159
+ ```
160
+
161
+ ## Modern Development Patterns
162
+
163
+ ### Dart 3.x Language Features
164
+
165
+ ```dart
166
+ // Enhanced patterns with records and pattern matching
167
+ sealed class NetworkResult<T> {
168
+ const NetworkResult();
169
+ }
170
+
171
+ class Success<T> extends NetworkResult<T> {
172
+ final T data;
173
+ const Success(this.data);
174
+ }
175
+
176
+ class Error<T> extends NetworkResult<T> {
177
+ final String message;
178
+ final Exception? exception;
179
+ const Error(this.message, [this.exception]);
180
+ }
181
+
182
+ class Loading<T> extends NetworkResult<T> {
183
+ const Loading();
184
+ }
185
+
186
+ // Pattern matching with switch expressions
187
+ T handleNetworkResult<T>(NetworkResult<T> result) {
188
+ return switch (result) {
189
+ Success(data: final data) => data,
190
+ Error(message: final message) => throw Exception(message),
191
+ Loading() => throw StateError('Still loading'),
192
+ };
193
+ }
194
+
195
+ // Records for lightweight data structures
196
+ typedef UserInfo = (String name, int age, String email);
197
+
198
+ class UserService {
199
+ UserInfo getUserInfo(int id) {
200
+ return ('John Doe', 30, 'john@example.com');
201
+ }
202
+
203
+ void printUserInfo(UserInfo user) {
204
+ final (name, age, email) = user;
205
+ print('$name, $age years old, email: $email');
206
+ }
207
+ }
208
+
209
+ // Enhanced type inference and const constructors
210
+ class AppConfig {
211
+ static const apiBaseUrl = String.fromEnvironment('API_BASE_URL', defaultValue: 'https://api.example.com');
212
+ static const appVersion = String.fromEnvironment('APP_VERSION', defaultValue: '1.0.0');
213
+ static const isDebug = bool.fromEnvironment('DEBUG', defaultValue: false);
214
+ }
215
+
216
+ // Enhanced enums with methods and properties
217
+ enum ThemeMode {
218
+ light._('Light Theme', '☀️'),
219
+ dark._('Dark Theme', '🌙'),
220
+ system._('System Theme', '💻');
221
+
222
+ const ThemeMode._(this.displayName, this.icon);
223
+
224
+ final String displayName;
225
+ final String icon;
226
+
227
+ Brightness get brightness => switch (this) {
228
+ ThemeMode.light => Brightness.light,
229
+ ThemeMode.dark => Brightness.dark,
230
+ ThemeMode.system => PlatformDispatcher.instance.platformBrightness,
231
+ };
232
+ }
233
+
234
+ // Extension methods for enhanced APIs
235
+ extension StringExtension on String {
236
+ bool get isValidEmail {
237
+ return RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(this);
238
+ }
239
+
240
+ String get capitalize {
241
+ return '${this[0].toUpperCase()}${substring(1)}';
242
+ }
243
+
244
+ String truncate(int length, {String suffix = '...'}) {
245
+ if (this.length <= length) return this;
246
+ return '${substring(0, length)}$suffix';
247
+ }
248
+ }
249
+ ```
250
+
251
+ ### Modern Flutter State Management with Riverpod
252
+
253
+ ```dart
254
+ // Provider setup with Riverpod 2.x
255
+ import 'package:flutter_riverpod/flutter_riverpod.dart';
256
+
257
+ // Model classes with immutability
258
+ @immutable
259
+ class User {
260
+ final String id;
261
+ final String name;
262
+ final String email;
263
+ final String avatarUrl;
264
+
265
+ const User({
266
+ required this.id,
267
+ required this.name,
268
+ required this.email,
269
+ required this.avatarUrl,
270
+ });
271
+
272
+ User copyWith({
273
+ String? id,
274
+ String? name,
275
+ String? email,
276
+ String? avatarUrl,
277
+ }) {
278
+ return User(
279
+ id: id ?? this.id,
280
+ name: name ?? this.name,
281
+ email: email ?? this.email,
282
+ avatarUrl: avatarUrl ?? this.avatarUrl,
283
+ );
284
+ }
285
+
286
+ @override
287
+ bool operator ==(Object other) {
288
+ if (identical(this, other)) return true;
289
+ return other is User &&
290
+ other.id == id &&
291
+ other.name == name &&
292
+ other.email == email;
293
+ }
294
+
295
+ @override
296
+ int get hashCode => id.hashCode ^ name.hashCode ^ email.hashCode;
297
+ }
298
+
299
+ // Repository interface
300
+ abstract class UserRepository {
301
+ Future<User> getUser(String userId);
302
+ Future<List<User>> getUsers({int page = 1, int limit = 20});
303
+ Future<User> updateUser(User user);
304
+ Future<void> deleteUser(String userId);
305
+ }
306
+
307
+ // Implementation with HTTP client
308
+ class HttpUserRepository implements UserRepository {
309
+ final Dio _dio;
310
+
311
+ HttpUserRepository(this._dio);
312
+
313
+ @override
314
+ Future<User> getUser(String userId) async {
315
+ try {
316
+ final response = await _dio.get('/users/$userId');
317
+ return User.fromJson(response.data);
318
+ } on DioException catch (e) {
319
+ throw UserRepositoryException('Failed to get user: $e');
320
+ }
321
+ }
322
+
323
+ @override
324
+ Future<List<User>> getUsers({int page = 1, int limit = 20}) async {
325
+ try {
326
+ final response = await _dio.get('/users', queryParameters: {
327
+ 'page': page,
328
+ 'limit': limit,
329
+ });
330
+
331
+ return (response.data as List)
332
+ .map((json) => User.fromJson(json))
333
+ .toList();
334
+ } on DioException catch (e) {
335
+ throw UserRepositoryException('Failed to get users: $e');
336
+ }
337
+ }
338
+
339
+ @override
340
+ Future<User> updateUser(User user) async {
341
+ try {
342
+ final response = await _dio.put('/users/${user.id}', data: user.toJson());
343
+ return User.fromJson(response.data);
344
+ } on DioException catch (e) {
345
+ throw UserRepositoryException('Failed to update user: $e');
346
+ }
347
+ }
348
+
349
+ @override
350
+ Future<void> deleteUser(String userId) async {
351
+ try {
352
+ await _dio.delete('/users/$userId');
353
+ } on DioException catch (e) {
354
+ throw UserRepositoryException('Failed to delete user: $e');
355
+ }
356
+ }
357
+ }
358
+
359
+ // Riverpod providers
360
+ final dioProvider = Provider<Dio>((ref) {
361
+ final dio = Dio(BaseOptions(baseUrl: AppConfig.apiBaseUrl));
362
+ dio.interceptors.add(LogInterceptor());
363
+ return dio;
364
+ });
365
+
366
+ final userRepositoryProvider = Provider<UserRepository>((ref) {
367
+ return HttpUserRepository(ref.read(dioProvider));
368
+ });
369
+
370
+ // Async providers for data fetching
371
+ final userProvider = FutureProvider.family<User, String>((ref, userId) async {
372
+ final repository = ref.watch(userRepositoryProvider);
373
+ return repository.getUser(userId);
374
+ });
375
+
376
+ final usersProvider = AsyncNotifierProvider<UsersNotifier, List<User>>(UsersNotifier.new);
377
+
378
+ // Notifier for managing state
379
+ class UsersNotifier extends AsyncNotifier<List<User>> {
380
+ int _page = 1;
381
+ final int _limit = 20;
382
+ bool _hasMore = true;
383
+
384
+ @override
385
+ Future<List<User>> build() async {
386
+ return _loadUsers();
387
+ }
388
+
389
+ Future<List<User>> _loadUsers() async {
390
+ if (state.isLoading || !_hasMore) return state.value ?? [];
391
+
392
+ state = const AsyncLoading();
393
+
394
+ try {
395
+ final repository = ref.read(userRepositoryProvider);
396
+ final newUsers = await repository.getUsers(page: _page, limit: _limit);
397
+
398
+ if (newUsers.length < _limit) {
399
+ _hasMore = false;
400
+ }
401
+
402
+ final currentUsers = state.value ?? [];
403
+ final updatedUsers = _page == 1 ? newUsers : [...currentUsers, ...newUsers];
404
+
405
+ state = AsyncData(updatedUsers);
406
+ _page++;
407
+
408
+ return updatedUsers;
409
+ } catch (error, stackTrace) {
410
+ state = AsyncError(error, stackTrace);
411
+ rethrow;
412
+ }
413
+ }
414
+
415
+ Future<void> loadMoreUsers() async {
416
+ await _loadUsers();
417
+ }
418
+
419
+ Future<void> refresh() async {
420
+ _page = 1;
421
+ _hasMore = true;
422
+ await _loadUsers();
423
+ }
424
+ }
425
+
426
+ // State management with Notifier for single user
427
+ final userNotifierProvider = AsyncNotifierProvider.family<UserNotifier, User, String>(UserNotifier.new);
428
+
429
+ class UserNotifier extends FamilyAsyncNotifier<User, String> {
430
+ @override
431
+ Future<User> build(String arg) async {
432
+ final repository = ref.read(userRepositoryProvider);
433
+ return repository.getUser(arg);
434
+ }
435
+
436
+ Future<void> updateUser(User user) async {
437
+ state = const AsyncLoading();
438
+
439
+ try {
440
+ final repository = ref.read(userRepositoryProvider);
441
+ final updatedUser = await repository.updateUser(user);
442
+ state = AsyncData(updatedUser);
443
+ } catch (error, stackTrace) {
444
+ state = AsyncError(error, stackTrace);
445
+ }
446
+ }
447
+ }
448
+
449
+ // App-wide state providers
450
+ final appThemeProvider = StateProvider<ThemeMode>((ref) => ThemeMode.system);
451
+ final appLocaleProvider = StateProvider<Locale>((ref) => const Locale('en', 'US'));
452
+ ```
453
+
454
+ ### Modern Flutter UI with Material 3
455
+
456
+ ```dart
457
+ // Modern app with Material 3 and go_router
458
+ class MyApp extends ConsumerWidget {
459
+ const MyApp({super.key});
460
+
461
+ @override
462
+ Widget build(BuildContext context, WidgetRef ref) {
463
+ final appRouter = ref.watch(goRouterProvider);
464
+ final themeMode = ref.watch(appThemeProvider);
465
+ final appLocale = ref.watch(appLocaleProvider);
466
+
467
+ return MaterialApp.router(
468
+ title: 'My Flutter App',
469
+ debugShowCheckedModeBanner: false,
470
+ themeMode: themeMode,
471
+ theme: AppTheme.lightTheme,
472
+ darkTheme: AppTheme.darkTheme,
473
+ locale: appLocale,
474
+ supportedLocales: const [
475
+ Locale('en', 'US'),
476
+ Locale('es', 'ES'),
477
+ Locale('fr', 'FR'),
478
+ ],
479
+ localizationsDelegates: const [
480
+ AppLocalizations.delegate,
481
+ GlobalMaterialLocalizations.delegate,
482
+ GlobalWidgetsLocalizations.delegate,
483
+ GlobalCupertinoLocalizations.delegate,
484
+ ],
485
+ routerConfig: appRouter,
486
+ );
487
+ }
488
+ }
489
+
490
+ // Modern theme configuration
491
+ class AppTheme {
492
+ static ThemeData get lightTheme {
493
+ return ThemeData(
494
+ useMaterial3: true,
495
+ colorScheme: ColorScheme.fromSeed(
496
+ seedColor: const Color(0xFF6750A4),
497
+ brightness: Brightness.light,
498
+ ),
499
+ appBarTheme: const AppBarTheme(
500
+ centerTitle: true,
501
+ elevation: 0,
502
+ scrolledUnderElevation: 1,
503
+ ),
504
+ cardTheme: CardTheme(
505
+ elevation: 2,
506
+ shape: RoundedRectangleBorder(
507
+ borderRadius: BorderRadius.circular(16),
508
+ ),
509
+ ),
510
+ elevatedButtonTheme: ElevatedButtonThemeData(
511
+ style: ElevatedButton.styleFrom(
512
+ elevation: 1,
513
+ shape: RoundedRectangleBorder(
514
+ borderRadius: BorderRadius.circular(20),
515
+ ),
516
+ padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
517
+ ),
518
+ ),
519
+ inputDecorationTheme: InputDecorationTheme(
520
+ border: OutlineInputBorder(
521
+ borderRadius: BorderRadius.circular(12),
522
+ ),
523
+ contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
524
+ ),
525
+ );
526
+ }
527
+
528
+ static ThemeData get darkTheme {
529
+ return ThemeData(
530
+ useMaterial3: true,
531
+ colorScheme: ColorScheme.fromSeed(
532
+ seedColor: const Color(0xFF6750A4),
533
+ brightness: Brightness.dark,
534
+ ),
535
+ appBarTheme: const AppBarTheme(
536
+ centerTitle: true,
537
+ elevation: 0,
538
+ scrolledUnderElevation: 1,
539
+ ),
540
+ cardTheme: CardTheme(
541
+ elevation: 2,
542
+ shape: RoundedRectangleBorder(
543
+ borderRadius: BorderRadius.circular(16),
544
+ ),
545
+ ),
546
+ );
547
+ }
548
+ }
549
+
550
+ // Modern user list widget with state management
551
+ class UserListScreen extends ConsumerWidget {
552
+ const UserListScreen({super.key});
553
+
554
+ @override
555
+ Widget build(BuildContext context, WidgetRef ref) {
556
+ final usersAsync = ref.watch(usersProvider);
557
+
558
+ return Scaffold(
559
+ appBar: AppBar(
560
+ title: const Text('Users'),
561
+ actions: [
562
+ IconButton(
563
+ icon: const Icon(Icons.refresh),
564
+ onPressed: () {
565
+ ref.read(usersProvider.notifier).refresh();
566
+ },
567
+ ),
568
+ ],
569
+ ),
570
+ body: RefreshIndicator(
571
+ onRefresh: () async {
572
+ await ref.read(usersProvider.notifier).refresh();
573
+ },
574
+ child: usersAsync.when(
575
+ data: (users) {
576
+ if (users.isEmpty) {
577
+ return const EmptyStateWidget(
578
+ message: 'No users found',
579
+ icon: Icons.people_outline,
580
+ );
581
+ }
582
+
583
+ return NotificationListener<ScrollNotification>(
584
+ onNotification: (scrollInfo) {
585
+ if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
586
+ ref.read(usersProvider.notifier).loadMoreUsers();
587
+ }
588
+ return false;
589
+ },
590
+ child: ListView.builder(
591
+ padding: const EdgeInsets.all(16),
592
+ itemCount: users.length + 1, // +1 for loading indicator
593
+ itemBuilder: (context, index) {
594
+ if (index == users.length) {
595
+ return const LoadingIndicator();
596
+ }
597
+
598
+ return UserCard(user: users[index]);
599
+ },
600
+ ),
601
+ );
602
+ },
603
+ loading: () => const Center(child: CircularProgressIndicator()),
604
+ error: (error, stack) => ErrorWidget(
605
+ error: error,
606
+ onRetry: () {
607
+ ref.read(usersProvider.notifier).refresh();
608
+ },
609
+ ),
610
+ ),
611
+ ),
612
+ floatingActionButton: FloatingActionButton.extended(
613
+ onPressed: () {
614
+ context.go('/add-user');
615
+ },
616
+ icon: const Icon(Icons.add),
617
+ label: const Text('Add User'),
618
+ ),
619
+ );
620
+ }
621
+ }
622
+
623
+ // Modern user card widget
624
+ class UserCard extends ConsumerWidget {
625
+ final User user;
626
+
627
+ const UserCard({
628
+ super.key,
629
+ required this.user,
630
+ });
631
+
632
+ @override
633
+ Widget build(BuildContext context, WidgetRef ref) {
634
+ return Card(
635
+ margin: const EdgeInsets.only(bottom: 12),
636
+ child: InkWell(
637
+ onTap: () {
638
+ context.go('/users/${user.id}');
639
+ },
640
+ borderRadius: BorderRadius.circular(16),
641
+ child: Padding(
642
+ padding: const EdgeInsets.all(16),
643
+ child: Row(
644
+ children: [
645
+ CircleAvatar(
646
+ radius: 28,
647
+ backgroundImage: NetworkImage(user.avatarUrl),
648
+ backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
649
+ child: user.avatarUrl.isEmpty
650
+ ? Text(
651
+ user.name.isNotEmpty ? user.name[0].toUpperCase() : '?',
652
+ style: Theme.of(context).textTheme.titleLarge,
653
+ )
654
+ : null,
655
+ ),
656
+ const SizedBox(width: 16),
657
+ Expanded(
658
+ child: Column(
659
+ crossAxisAlignment: CrossAxisAlignment.start,
660
+ children: [
661
+ Text(
662
+ user.name,
663
+ style: Theme.of(context).textTheme.titleMedium,
664
+ ),
665
+ const SizedBox(height: 4),
666
+ Text(
667
+ user.email,
668
+ style: Theme.of(context).textTheme.bodyMedium?.copyWith(
669
+ color: Theme.of(context).colorScheme.onSurfaceVariant,
670
+ ),
671
+ ),
672
+ ],
673
+ ),
674
+ ),
675
+ IconButton(
676
+ icon: const Icon(Icons.more_vert),
677
+ onPressed: () {
678
+ _showUserMenu(context, ref, user);
679
+ },
680
+ ),
681
+ ],
682
+ ),
683
+ ),
684
+ ),
685
+ );
686
+ }
687
+
688
+ void _showUserMenu(BuildContext context, WidgetRef ref, User user) {
689
+ showModalBottomSheet(
690
+ context: context,
691
+ builder: (context) {
692
+ return SafeArea(
693
+ child: Column(
694
+ mainAxisSize: MainAxisSize.min,
695
+ children: [
696
+ ListTile(
697
+ leading: const Icon(Icons.edit),
698
+ title: const Text('Edit User'),
699
+ onTap: () {
700
+ Navigator.pop(context);
701
+ context.go('/users/${user.id}/edit');
702
+ },
703
+ ),
704
+ ListTile(
705
+ leading: const Icon(Icons.delete, color: Colors.red),
706
+ title: const Text('Delete User', style: TextStyle(color: Colors.red)),
707
+ onTap: () async {
708
+ Navigator.pop(context);
709
+
710
+ final confirmed = await _showDeleteConfirmation(context);
711
+ if (confirmed) {
712
+ try {
713
+ await ref.read(userRepositoryProvider).deleteUser(user.id);
714
+ if (context.mounted) {
715
+ ScaffoldMessenger.of(context).showSnackBar(
716
+ const SnackBar(content: Text('User deleted successfully')),
717
+ );
718
+ }
719
+ } catch (error) {
720
+ if (context.mounted) {
721
+ ScaffoldMessenger.of(context).showSnackBar(
722
+ SnackBar(content: Text('Failed to delete user: $error')),
723
+ );
724
+ }
725
+ }
726
+ }
727
+ },
728
+ ),
729
+ ],
730
+ ),
731
+ );
732
+ },
733
+ );
734
+ }
735
+
736
+ Future<bool> _showDeleteConfirmation(BuildContext context) async {
737
+ return await showDialog<bool>(
738
+ context: context,
739
+ builder: (context) {
740
+ return AlertDialog(
741
+ title: const Text('Delete User'),
742
+ content: Text('Are you sure you want to delete ${user.name}?'),
743
+ actions: [
744
+ TextButton(
745
+ onPressed: () => Navigator.pop(context, false),
746
+ child: const Text('Cancel'),
747
+ ),
748
+ TextButton(
749
+ onPressed: () => Navigator.pop(context, true),
750
+ style: TextButton.styleFrom(foregroundColor: Colors.red),
751
+ child: const Text('Delete'),
752
+ ),
753
+ ],
754
+ );
755
+ },
756
+ ) ?? false;
757
+ }
758
+ }
759
+ ```
760
+
761
+ ### Go Router for Navigation
762
+
763
+ ```dart
764
+ // Go router configuration
765
+ final goRouterProvider = Provider<GoRouter>((ref) {
766
+ return GoRouter(
767
+ initialLocation: '/',
768
+ debugLogDiagnostics: AppConfig.isDebug,
769
+ routes: [
770
+ // Shell route for navigation
771
+ ShellRoute(
772
+ builder: (context, state, child) {
773
+ return MainScaffold(child: child);
774
+ },
775
+ routes: [
776
+ // Home route
777
+ GoRoute(
778
+ path: '/',
779
+ builder: (context, state) => const HomeScreen(),
780
+ ),
781
+
782
+ // User routes
783
+ GoRoute(
784
+ path: '/users',
785
+ builder: (context, state) => const UserListScreen(),
786
+ routes: [
787
+ GoRoute(
788
+ path: '/:userId',
789
+ builder: (context, state) {
790
+ final userId = state.pathParameters['userId']!;
791
+ return UserDetailScreen(userId: userId);
792
+ },
793
+ routes: [
794
+ GoRoute(
795
+ path: '/edit',
796
+ builder: (context, state) {
797
+ final userId = state.pathParameters['userId']!;
798
+ return EditUserScreen(userId: userId);
799
+ },
800
+ ),
801
+ ],
802
+ ),
803
+ ],
804
+ ),
805
+
806
+ // Settings route
807
+ GoRoute(
808
+ path: '/settings',
809
+ builder: (context, state) => const SettingsScreen(),
810
+ routes: [
811
+ GoRoute(
812
+ path: '/profile',
813
+ builder: (context, state) => const ProfileSettingsScreen(),
814
+ ),
815
+ GoRoute(
816
+ path: '/appearance',
817
+ builder: (context, state) => const AppearanceSettingsScreen(),
818
+ ),
819
+ ],
820
+ ),
821
+ ],
822
+ ),
823
+
824
+ // Standalone routes
825
+ GoRoute(
826
+ path: '/add-user',
827
+ builder: (context, state) => const AddUserScreen(),
828
+ ),
829
+
830
+ GoRoute(
831
+ path: '/login',
832
+ builder: (context, state) => const LoginScreen(),
833
+ ),
834
+ ],
835
+
836
+ // Error handling
837
+ errorBuilder: (context, state) => ErrorScreen(error: state.error),
838
+
839
+ // Redirects
840
+ redirect: (context, state) {
841
+ // Example: redirect to login if not authenticated
842
+ final isAuthenticated = true; // Check authentication status
843
+
844
+ if (!isAuthenticated && !state.location.startsWith('/login')) {
845
+ return '/login';
846
+ }
847
+
848
+ return null;
849
+ },
850
+ );
851
+ });
852
+
853
+ // Main scaffold with bottom navigation
854
+ class MainScaffold extends ConsumerWidget {
855
+ const MainScaffold({
856
+ required this.child,
857
+ super.key,
858
+ });
859
+
860
+ final Widget child;
861
+
862
+ @override
863
+ Widget build(BuildContext context, WidgetRef ref) {
864
+ final selectedIndex = ref.watch(bottomNavigationIndexProvider);
865
+
866
+ return Scaffold(
867
+ body: child,
868
+ bottomNavigationBar: NavigationBar(
869
+ selectedIndex: selectedIndex,
870
+ onDestinationSelected: (index) {
871
+ ref.read(bottomNavigationIndexProvider.notifier).state = index;
872
+
873
+ switch (index) {
874
+ case 0:
875
+ context.go('/');
876
+ break;
877
+ case 1:
878
+ context.go('/users');
879
+ break;
880
+ case 2:
881
+ context.go('/settings');
882
+ break;
883
+ }
884
+ },
885
+ destinations: const [
886
+ NavigationDestination(
887
+ icon: Icon(Icons.home_outlined),
888
+ selectedIcon: Icon(Icons.home),
889
+ label: 'Home',
890
+ ),
891
+ NavigationDestination(
892
+ icon: Icon(Icons.people_outlined),
893
+ selectedIcon: Icon(Icons.people),
894
+ label: 'Users',
895
+ ),
896
+ NavigationDestination(
897
+ icon: Icon(Icons.settings_outlined),
898
+ selectedIcon: Icon(Icons.settings),
899
+ label: 'Settings',
900
+ ),
901
+ ],
902
+ ),
903
+ );
904
+ }
905
+ }
906
+
907
+ // Provider for bottom navigation state
908
+ final bottomNavigationIndexProvider = StateProvider<int>((ref) => 0);
909
+ ```
910
+
911
+ ## Performance Considerations
912
+
913
+ ### Widget Performance
914
+
915
+ ```dart
916
+ // Performance-optimized widgets with const constructors
917
+ class OptimizedUserCard extends StatelessWidget {
918
+ final User user;
919
+ final VoidCallback? onTap;
920
+ final VoidCallback? onEdit;
921
+ final VoidCallback? onDelete;
922
+
923
+ const OptimizedUserCard({
924
+ super.key,
925
+ required this.user,
926
+ this.onTap,
927
+ this.onEdit,
928
+ this.onDelete,
929
+ });
930
+
931
+ @override
932
+ Widget build(BuildContext context) {
933
+ return Card(
934
+ margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
935
+ child: InkWell(
936
+ onTap: onTap,
937
+ borderRadius: BorderRadius.circular(12),
938
+ child: Padding(
939
+ padding: const EdgeInsets.all(16),
940
+ child: Row(
941
+ children: [
942
+ // Use Hero widget for smooth avatar transitions
943
+ Hero(
944
+ tag: 'user-avatar-${user.id}',
945
+ child: UserAvatar(
946
+ imageUrl: user.avatarUrl,
947
+ name: user.name,
948
+ size: 48,
949
+ ),
950
+ ),
951
+ const SizedBox(width: 16),
952
+ Expanded(
953
+ child: _buildUserInfo(),
954
+ ),
955
+ _buildActionButtons(),
956
+ ],
957
+ ),
958
+ ),
959
+ ),
960
+ );
961
+ }
962
+
963
+ Widget _buildUserInfo() {
964
+ return Column(
965
+ crossAxisAlignment: CrossAxisAlignment.start,
966
+ mainAxisSize: MainAxisSize.min,
967
+ children: [
968
+ Text(
969
+ user.name,
970
+ style: const TextStyle(
971
+ fontSize: 16,
972
+ fontWeight: FontWeight.w600,
973
+ ),
974
+ maxLines: 1,
975
+ overflow: TextOverflow.ellipsis,
976
+ ),
977
+ const SizedBox(height: 4),
978
+ Text(
979
+ user.email,
980
+ style: const TextStyle(
981
+ fontSize: 14,
982
+ color: Colors.grey,
983
+ ),
984
+ maxLines: 1,
985
+ overflow: TextOverflow.ellipsis,
986
+ ),
987
+ ],
988
+ );
989
+ }
990
+
991
+ Widget _buildActionButtons() {
992
+ return Row(
993
+ mainAxisSize: MainAxisSize.min,
994
+ children: [
995
+ if (onEdit != null)
996
+ IconButton(
997
+ icon: const Icon(Icons.edit_outlined),
998
+ onPressed: onEdit,
999
+ visualDensity: VisualDensity.compact,
1000
+ ),
1001
+ if (onDelete != null)
1002
+ IconButton(
1003
+ icon: const Icon(Icons.delete_outline),
1004
+ onPressed: onDelete,
1005
+ visualDensity: VisualDensity.compact,
1006
+ ),
1007
+ ],
1008
+ );
1009
+ }
1010
+ }
1011
+
1012
+ // Efficient image loading and caching
1013
+ class CachedNetworkImage extends StatefulWidget {
1014
+ final String imageUrl;
1015
+ final double? width;
1016
+ final double? height;
1017
+ final Widget? placeholder;
1018
+ final Widget? errorWidget;
1019
+ final BoxFit fit;
1020
+
1021
+ const CachedNetworkImage({
1022
+ super.key,
1023
+ required this.imageUrl,
1024
+ this.width,
1025
+ this.height,
1026
+ this.placeholder,
1027
+ this.errorWidget,
1028
+ this.fit = BoxFit.cover,
1029
+ });
1030
+
1031
+ @override
1032
+ State<CachedNetworkImage> createState() => _CachedNetworkImageState();
1033
+ }
1034
+
1035
+ class _CachedNetworkImageState extends State<CachedNetworkImage> {
1036
+ final Map<String, ui.Image> _imageCache = {};
1037
+ bool _isLoading = true;
1038
+ bool _hasError = false;
1039
+
1040
+ @override
1041
+ void initState() {
1042
+ super.initState();
1043
+ _loadImage();
1044
+ }
1045
+
1046
+ Future<void> _loadImage() async {
1047
+ if (_imageCache.containsKey(widget.imageUrl)) {
1048
+ if (mounted) {
1049
+ setState(() {
1050
+ _isLoading = false;
1051
+ });
1052
+ }
1053
+ return;
1054
+ }
1055
+
1056
+ try {
1057
+ final image = await _fetchImage();
1058
+ _imageCache[widget.imageUrl] = image;
1059
+
1060
+ if (mounted) {
1061
+ setState(() {
1062
+ _isLoading = false;
1063
+ });
1064
+ }
1065
+ } catch (e) {
1066
+ if (mounted) {
1067
+ setState(() {
1068
+ _isLoading = false;
1069
+ _hasError = true;
1070
+ });
1071
+ }
1072
+ }
1073
+ }
1074
+
1075
+ Future<ui.Image> _fetchImage() async {
1076
+ final completer = Completer<ui.Image>();
1077
+ final codec = await ui.instantiateImageCodec(
1078
+ await NetworkAssetBundle(Uri.parse(widget.imageUrl)).load(widget.imageUrl).then((bytes) => bytes.buffer.asUint8List()),
1079
+ );
1080
+ final frame = await codec.getNextFrame();
1081
+ completer.complete(frame.image);
1082
+ return completer.future;
1083
+ }
1084
+
1085
+ @override
1086
+ Widget build(BuildContext context) {
1087
+ if (_isLoading) {
1088
+ return widget.placeholder ??
1089
+ Container(
1090
+ width: widget.width,
1091
+ height: widget.height,
1092
+ color: Colors.grey[200],
1093
+ child: const Center(
1094
+ child: CircularProgressIndicator(),
1095
+ ),
1096
+ );
1097
+ }
1098
+
1099
+ if (_hasError) {
1100
+ return widget.errorWidget ??
1101
+ Container(
1102
+ width: widget.width,
1103
+ height: widget.height,
1104
+ color: Colors.grey[200],
1105
+ child: const Icon(Icons.error),
1106
+ );
1107
+ }
1108
+
1109
+ final image = _imageCache[widget.imageUrl];
1110
+ return CustomPaint(
1111
+ size: Size(widget.width ?? double.infinity, widget.height ?? double.infinity),
1112
+ painter: _ImagePainter(image: image!, fit: widget.fit),
1113
+ );
1114
+ }
1115
+ }
1116
+
1117
+ class _ImagePainter extends CustomPainter {
1118
+ final ui.Image image;
1119
+ final BoxFit fit;
1120
+
1121
+ _ImagePainter({required this.image, required this.fit});
1122
+
1123
+ @override
1124
+ void paint(Canvas canvas, Size size) {
1125
+ final imageSize = Size(image.width.toDouble(), image.height.toDouble());
1126
+ final scales = _calculateScales(imageSize, size);
1127
+
1128
+ final paint = Paint()
1129
+ ..isAntiAlias = true
1130
+ ..filterQuality = FilterQuality.high;
1131
+
1132
+ canvas.save();
1133
+
1134
+ if (fit == BoxFit.cover) {
1135
+ canvas.scale(scales.dx, scales.dy);
1136
+ canvas.drawImageRect(
1137
+ image,
1138
+ Rect.fromLTWH(0, 0, imageSize.width, imageSize.height),
1139
+ Rect.fromLTWH(0, 0, size.width / scales.dx, size.height / scales.dy),
1140
+ paint,
1141
+ );
1142
+ }
1143
+
1144
+ canvas.restore();
1145
+ }
1146
+
1147
+ Offset _calculateScales(Size inputSize, Size outputSize) {
1148
+ final scaleX = outputSize.width / inputSize.width;
1149
+ final scaleY = outputSize.height / inputSize.height;
1150
+ return Offset(scaleX, scaleY);
1151
+ }
1152
+
1153
+ @override
1154
+ bool shouldRepaint(covariant _ImagePainter oldDelegate) {
1155
+ return image != oldDelegate.image || fit != oldDelegate.fit;
1156
+ }
1157
+ }
1158
+
1159
+ // ListView with lazy loading and recycling
1160
+ class OptimizedListView<T> extends StatelessWidget {
1161
+ final List<T> items;
1162
+ final Widget Function(BuildContext context, T item, int index) itemBuilder;
1163
+ final VoidCallback? onLoadMore;
1164
+ final bool hasMore;
1165
+ final bool isLoading;
1166
+
1167
+ const OptimizedListView({
1168
+ super.key,
1169
+ required this.items,
1170
+ required this.itemBuilder,
1171
+ this.onLoadMore,
1172
+ this.hasMore = false,
1173
+ this.isLoading = false,
1174
+ });
1175
+
1176
+ @override
1177
+ Widget build(BuildContext context) {
1178
+ return NotificationListener<ScrollNotification>(
1179
+ onNotification: (notification) {
1180
+ if (notification is ScrollEndNotification &&
1181
+ notification.metrics.extentAfter == 0 &&
1182
+ hasMore &&
1183
+ !isLoading &&
1184
+ onLoadMore != null) {
1185
+ onLoadMore!();
1186
+ }
1187
+ return false;
1188
+ },
1189
+ child: ListView.builder(
1190
+ itemCount: items.length + (hasMore ? 1 : 0),
1191
+ itemBuilder: (context, index) {
1192
+ if (index == items.length) {
1193
+ return const Center(
1194
+ child: Padding(
1195
+ padding: EdgeInsets.all(16.0),
1196
+ child: CircularProgressIndicator(),
1197
+ ),
1198
+ );
1199
+ }
1200
+
1201
+ return itemBuilder(context, items[index], index);
1202
+ },
1203
+ ),
1204
+ );
1205
+ }
1206
+ }
1207
+ ```
1208
+
1209
+ ### Memory Management
1210
+
1211
+ ```dart
1212
+ // Efficient memory usage with ImageCache
1213
+ class ImageCacheManager {
1214
+ static final ImageCacheManager _instance = ImageCacheManager._internal();
1215
+ factory ImageCacheManager() => _instance;
1216
+ ImageCacheManager._internal();
1217
+
1218
+ final PaintingBinding _paintingBinding = PaintingBinding.instance;
1219
+ final Map<String, ui.Image> _memoryCache = {};
1220
+ final int _maxCacheSize = 100 * 1024 * 1024; // 100MB
1221
+ int _currentCacheSize = 0;
1222
+
1223
+ Future<ui.Image?> getImage(String url) async {
1224
+ // Check memory cache first
1225
+ if (_memoryCache.containsKey(url)) {
1226
+ return _memoryCache[url];
1227
+ }
1228
+
1229
+ // Check painting binding cache
1230
+ final cachedImage = _paintingBinding.imageCache?.image;
1231
+ if (cachedImage != null) {
1232
+ return cachedImage;
1233
+ }
1234
+
1235
+ try {
1236
+ final image = await _loadImage(url);
1237
+ _addToMemoryCache(url, image);
1238
+ return image;
1239
+ } catch (e) {
1240
+ return null;
1241
+ }
1242
+ }
1243
+
1244
+ Future<ui.Image> _loadImage(String url) async {
1245
+ final completer = Completer<ui.Image>();
1246
+ final codec = await ui.instantiateImageCodec(
1247
+ await _fetchImageData(url),
1248
+ );
1249
+ final frame = await codec.getNextFrame();
1250
+ completer.complete(frame.image);
1251
+ return completer.future;
1252
+ }
1253
+
1254
+ Future<Uint8List> _fetchImageData(String url) async {
1255
+ final response = await http.get(Uri.parse(url));
1256
+ return response.bodyBytes;
1257
+ }
1258
+
1259
+ void _addToMemoryCache(String url, ui.Image image) {
1260
+ final imageSize = image.width * image.height * 4; // 4 bytes per pixel
1261
+
1262
+ if (_currentCacheSize + imageSize > _maxCacheSize) {
1263
+ _evictLeastRecentlyUsed(imageSize);
1264
+ }
1265
+
1266
+ _memoryCache[url] = image;
1267
+ _currentCacheSize += imageSize;
1268
+ }
1269
+
1270
+ void _evictLeastRecentlyUsed(int requiredSize) {
1271
+ final entries = _memoryCache.entries.toList();
1272
+ entries.sort((a, b) => a.key.compareTo(b.key));
1273
+
1274
+ int freedSize = 0;
1275
+ for (final entry in entries) {
1276
+ final imageSize = entry.value.width * entry.value.height * 4;
1277
+ _memoryCache.remove(entry.key);
1278
+ freedSize += imageSize;
1279
+ _currentCacheSize -= imageSize;
1280
+
1281
+ if (freedSize >= requiredSize) {
1282
+ break;
1283
+ }
1284
+ }
1285
+ }
1286
+
1287
+ void clearCache() {
1288
+ _memoryCache.clear();
1289
+ _currentCacheSize = 0;
1290
+ _paintingBinding.imageCache?.clear();
1291
+ _paintingBinding.imageCache?.clearLiveImages();
1292
+ }
1293
+ }
1294
+
1295
+ // Resource management with automatic cleanup
1296
+ class ResourceManager {
1297
+ final Map<String, StreamSubscription> _subscriptions = {};
1298
+ final Map<String, Timer> _timers = {};
1299
+
1300
+ StreamSubscription<T>? addSubscription<T>(
1301
+ String key,
1302
+ StreamSubscription<T> subscription,
1303
+ ) {
1304
+ _subscriptions[key] = subscription as StreamSubscription;
1305
+ return subscription;
1306
+ }
1307
+
1308
+ Timer? addTimer(String key, Duration duration, VoidCallback callback) {
1309
+ final timer = Timer(duration, callback);
1310
+ _timers[key] = timer;
1311
+ return timer;
1312
+ }
1313
+
1314
+ void removeSubscription(String key) {
1315
+ final subscription = _subscriptions.remove(key);
1316
+ subscription?.cancel();
1317
+ }
1318
+
1319
+ void removeTimer(String key) {
1320
+ final timer = _timers.remove(key);
1321
+ timer?.cancel();
1322
+ }
1323
+
1324
+ void dispose() {
1325
+ for (final subscription in _subscriptions.values) {
1326
+ subscription.cancel();
1327
+ }
1328
+ _subscriptions.clear();
1329
+
1330
+ for (final timer in _timers.values) {
1331
+ timer.cancel();
1332
+ }
1333
+ _timers.clear();
1334
+ }
1335
+ }
1336
+
1337
+ // Widget with automatic resource cleanup
1338
+ class AutoCleanupWidget extends StatefulWidget {
1339
+ final Widget child;
1340
+ final VoidCallback? onInit;
1341
+ final VoidCallback? onDispose;
1342
+
1343
+ const AutoCleanupWidget({
1344
+ super.key,
1345
+ required this.child,
1346
+ this.onInit,
1347
+ this.onDispose,
1348
+ });
1349
+
1350
+ @override
1351
+ State<AutoCleanupWidget> createState() => _AutoCleanupWidgetState();
1352
+ }
1353
+
1354
+ class _AutoCleanupWidgetState extends State<AutoCleanupWidget> {
1355
+ final ResourceManager _resourceManager = ResourceManager();
1356
+
1357
+ @override
1358
+ void initState() {
1359
+ super.initState();
1360
+ widget.onInit?.call();
1361
+ }
1362
+
1363
+ @override
1364
+ void dispose() {
1365
+ _resourceManager.dispose();
1366
+ widget.onDispose?.call();
1367
+ super.dispose();
1368
+ }
1369
+
1370
+ @override
1371
+ Widget build(BuildContext context) {
1372
+ return widget.child;
1373
+ }
1374
+ }
1375
+ ```
1376
+
1377
+ ## Testing Strategy
1378
+
1379
+ ### Unit Testing with Dart Test Framework
1380
+
1381
+ ```dart
1382
+ // Unit tests for business logic
1383
+ void main() {
1384
+ group('UserRepository', () {
1385
+ late UserRepository userRepository;
1386
+ late MockDio mockDio;
1387
+
1388
+ setUp(() {
1389
+ mockDio = MockDio();
1390
+ userRepository = HttpUserRepository(mockDio);
1391
+ });
1392
+
1393
+ test('should return user when getUser is called with valid ID', () async {
1394
+ // Arrange
1395
+ final userId = '123';
1396
+ final userJson = {
1397
+ 'id': userId,
1398
+ 'name': 'John Doe',
1399
+ 'email': 'john@example.com',
1400
+ 'avatarUrl': 'https://example.com/avatar.jpg',
1401
+ };
1402
+
1403
+ when(() => mockDio.get('/users/$userId'))
1404
+ .thenAnswer((_) async => Response(data: userJson, statusCode: 200));
1405
+
1406
+ // Act
1407
+ final result = await userRepository.getUser(userId);
1408
+
1409
+ // Assert
1410
+ expect(result.id, equals(userId));
1411
+ expect(result.name, equals('John Doe'));
1412
+ expect(result.email, equals('john@example.com'));
1413
+ expect(result.avatarUrl, equals('https://example.com/avatar.jpg'));
1414
+
1415
+ verify(() => mockDio.get('/users/$userId')).called(1);
1416
+ });
1417
+
1418
+ test('should throw UserRepositoryException when API call fails', () async {
1419
+ // Arrange
1420
+ final userId = '123';
1421
+
1422
+ when(() => mockDio.get('/users/$userId'))
1423
+ .thenThrow(DioException(requestOptions: RequestOptions(path: '/users/$userId')));
1424
+
1425
+ // Act & Assert
1426
+ expect(
1427
+ () => userRepository.getUser(userId),
1428
+ throwsA(isA<UserRepositoryException>()),
1429
+ );
1430
+
1431
+ verify(() => mockDio.get('/users/$userId')).called(1);
1432
+ });
1433
+
1434
+ test('should return users list when getUsers is called', () async {
1435
+ // Arrange
1436
+ final usersJson = [
1437
+ {
1438
+ 'id': '1',
1439
+ 'name': 'John Doe',
1440
+ 'email': 'john@example.com',
1441
+ 'avatarUrl': 'https://example.com/avatar1.jpg',
1442
+ },
1443
+ {
1444
+ 'id': '2',
1445
+ 'name': 'Jane Smith',
1446
+ 'email': 'jane@example.com',
1447
+ 'avatarUrl': 'https://example.com/avatar2.jpg',
1448
+ },
1449
+ ];
1450
+
1451
+ when(() => mockDio.get('/users', queryParameters: any(named: 'queryParameters')))
1452
+ .thenAnswer((_) async => Response(data: usersJson, statusCode: 200));
1453
+
1454
+ // Act
1455
+ final result = await userRepository.getUsers();
1456
+
1457
+ // Assert
1458
+ expect(result, hasLength(2));
1459
+ expect(result[0].name, equals('John Doe'));
1460
+ expect(result[1].name, equals('Jane Smith'));
1461
+
1462
+ verify(() => mockDio.get('/users', queryParameters: any(named: 'queryParameters'))).called(1);
1463
+ });
1464
+ });
1465
+
1466
+ group('User model', () {
1467
+ test('should create user with valid data', () {
1468
+ // Arrange
1469
+ const user = User(
1470
+ id: '123',
1471
+ name: 'John Doe',
1472
+ email: 'john@example.com',
1473
+ avatarUrl: 'https://example.com/avatar.jpg',
1474
+ );
1475
+
1476
+ // Act & Assert
1477
+ expect(user.id, equals('123'));
1478
+ expect(user.name, equals('John Doe'));
1479
+ expect(user.email, equals('john@example.com'));
1480
+ expect(user.avatarUrl, equals('https://example.com/avatar.jpg'));
1481
+ });
1482
+
1483
+ test('should copy user with updated name', () {
1484
+ // Arrange
1485
+ const originalUser = User(
1486
+ id: '123',
1487
+ name: 'John Doe',
1488
+ email: 'john@example.com',
1489
+ avatarUrl: 'https://example.com/avatar.jpg',
1490
+ );
1491
+
1492
+ // Act
1493
+ final updatedUser = originalUser.copyWith(name: 'Jane Doe');
1494
+
1495
+ // Assert
1496
+ expect(updatedUser.id, equals(originalUser.id));
1497
+ expect(updatedUser.name, equals('Jane Doe'));
1498
+ expect(updatedUser.email, equals(originalUser.email));
1499
+ expect(updatedUser.avatarUrl, equals(originalUser.avatarUrl));
1500
+ });
1501
+
1502
+ test('should compare users correctly', () {
1503
+ // Arrange
1504
+ const user1 = User(
1505
+ id: '123',
1506
+ name: 'John Doe',
1507
+ email: 'john@example.com',
1508
+ avatarUrl: 'https://example.com/avatar.jpg',
1509
+ );
1510
+
1511
+ const user2 = User(
1512
+ id: '123',
1513
+ name: 'John Doe',
1514
+ email: 'john@example.com',
1515
+ avatarUrl: 'https://example.com/avatar.jpg',
1516
+ );
1517
+
1518
+ const user3 = User(
1519
+ id: '456',
1520
+ name: 'John Doe',
1521
+ email: 'john@example.com',
1522
+ avatarUrl: 'https://example.com/avatar.jpg',
1523
+ );
1524
+
1525
+ // Act & Assert
1526
+ expect(user1, equals(user2));
1527
+ expect(user1, isNot(equals(user3)));
1528
+ expect(user1.hashCode, equals(user2.hashCode));
1529
+ expect(user1.hashCode, isNot(equals(user3.hashCode)));
1530
+ });
1531
+ });
1532
+ }
1533
+
1534
+ // Test for extensions
1535
+ void main() {
1536
+ group('StringExtension', () {
1537
+ test('should validate email correctly', () {
1538
+ expect('test@example.com'.isValidEmail, isTrue);
1539
+ expect('test.name@example.com'.isValidEmail, isTrue);
1540
+ expect('test+tag@example.com'.isValidEmail, isTrue);
1541
+
1542
+ expect('invalid-email'.isValidEmail, isFalse);
1543
+ expect('@example.com'.isValidEmail, isFalse);
1544
+ expect('test@'.isValidEmail, isFalse);
1545
+ expect('test@example'.isValidEmail, isFalse);
1546
+ });
1547
+
1548
+ test('should capitalize first letter correctly', () {
1549
+ expect('hello'.capitalize, equals('Hello'));
1550
+ expect('WORLD'.capitalize, equals('WORLD'));
1551
+ expect(''.capitalize, equals(''));
1552
+ });
1553
+
1554
+ test('should truncate string correctly', () {
1555
+ expect('short'.truncate(10), equals('short'));
1556
+ expect('this is a long string'.truncate(10), equals('this is a...'));
1557
+ expect('this is a long string'.truncate(10, suffix: ' [more]'), equals('this is a [more]'));
1558
+ });
1559
+ });
1560
+ }
1561
+ ```
1562
+
1563
+ ### Widget Testing
1564
+
1565
+ ```dart
1566
+ // Widget tests for UI components
1567
+ void main() {
1568
+ group('UserCard Widget Tests', () {
1569
+ testWidgets('should display user information correctly', (WidgetTester tester) async {
1570
+ // Arrange
1571
+ const user = User(
1572
+ id: '123',
1573
+ name: 'John Doe',
1574
+ email: 'john@example.com',
1575
+ avatarUrl: 'https://example.com/avatar.jpg',
1576
+ );
1577
+
1578
+ // Act
1579
+ await tester.pumpWidget(
1580
+ MaterialApp(
1581
+ home: Scaffold(
1582
+ body: UserCard(user: user),
1583
+ ),
1584
+ ),
1585
+ );
1586
+
1587
+ // Assert
1588
+ expect(find.text('John Doe'), findsOneWidget);
1589
+ expect(find.text('john@example.com'), findsOneWidget);
1590
+ expect(find.byType(CircleAvatar), findsOneWidget);
1591
+ });
1592
+
1593
+ testWidgets('should call onTap when card is tapped', (WidgetTester tester) async {
1594
+ // Arrange
1595
+ const user = User(
1596
+ id: '123',
1597
+ name: 'John Doe',
1598
+ email: 'john@example.com',
1599
+ avatarUrl: 'https://example.com/avatar.jpg',
1600
+ );
1601
+
1602
+ bool wasTapped = false;
1603
+
1604
+ // Act
1605
+ await tester.pumpWidget(
1606
+ MaterialApp(
1607
+ home: Scaffold(
1608
+ body: UserCard(
1609
+ user: user,
1610
+ onTap: () => wasTapped = true,
1611
+ ),
1612
+ ),
1613
+ ),
1614
+ );
1615
+
1616
+ await tester.tap(find.byType(UserCard));
1617
+ await tester.pump();
1618
+
1619
+ // Assert
1620
+ expect(wasTapped, isTrue);
1621
+ });
1622
+
1623
+ testWidgets('should show edit and delete buttons when callbacks provided', (WidgetTester tester) async {
1624
+ // Arrange
1625
+ const user = User(
1626
+ id: '123',
1627
+ name: 'John Doe',
1628
+ email: 'john@example.com',
1629
+ avatarUrl: 'https://example.com/avatar.jpg',
1630
+ );
1631
+
1632
+ // Act
1633
+ await tester.pumpWidget(
1634
+ MaterialApp(
1635
+ home: Scaffold(
1636
+ body: UserCard(
1637
+ user: user,
1638
+ onEdit: () {},
1639
+ onDelete: () {},
1640
+ ),
1641
+ ),
1642
+ ),
1643
+ );
1644
+
1645
+ // Assert
1646
+ expect(find.byIcon(Icons.edit_outlined), findsOneWidget);
1647
+ expect(find.byIcon(Icons.delete_outline), findsOneWidget);
1648
+ });
1649
+ });
1650
+
1651
+ group('UserListScreen Widget Tests', () {
1652
+ testWidgets('should show loading indicator initially', (WidgetTester tester) async {
1653
+ // Arrange
1654
+ await tester.pumpWidget(
1655
+ ProviderScope(
1656
+ overrides: [
1657
+ usersProvider.overrideWith((ref) => AsyncValue.loading()),
1658
+ ],
1659
+ child: MaterialApp(
1660
+ home: UserListScreen(),
1661
+ ),
1662
+ ),
1663
+ );
1664
+
1665
+ // Act & Assert
1666
+ expect(find.byType(CircularProgressIndicator), findsOneWidget);
1667
+ });
1668
+
1669
+ testWidgets('should show error message when loading fails', (WidgetTester tester) async {
1670
+ // Arrange
1671
+ const errorMessage = 'Failed to load users';
1672
+
1673
+ await tester.pumpWidget(
1674
+ ProviderScope(
1675
+ overrides: [
1676
+ usersProvider.overrideWith(
1677
+ (ref) => AsyncValue.error(Exception(errorMessage), StackTrace.current),
1678
+ ),
1679
+ ],
1680
+ child: MaterialApp(
1681
+ home: UserListScreen(),
1682
+ ),
1683
+ ),
1684
+ );
1685
+
1686
+ await tester.pump();
1687
+
1688
+ // Act & Assert
1689
+ expect(find.text(errorMessage), findsOneWidget);
1690
+ expect(find.byType(ElevatedButton), findsOneWidget);
1691
+ });
1692
+
1693
+ testWidgets('should show users when loading succeeds', (WidgetTester tester) async {
1694
+ // Arrange
1695
+ final users = [
1696
+ const User(
1697
+ id: '1',
1698
+ name: 'John Doe',
1699
+ email: 'john@example.com',
1700
+ avatarUrl: 'https://example.com/avatar1.jpg',
1701
+ ),
1702
+ const User(
1703
+ id: '2',
1704
+ name: 'Jane Smith',
1705
+ email: 'jane@example.com',
1706
+ avatarUrl: 'https://example.com/avatar2.jpg',
1707
+ ),
1708
+ ];
1709
+
1710
+ await tester.pumpWidget(
1711
+ ProviderScope(
1712
+ overrides: [
1713
+ usersProvider.overrideWith((ref) => AsyncValue.data(users)),
1714
+ ],
1715
+ child: MaterialApp(
1716
+ home: UserListScreen(),
1717
+ ),
1718
+ ),
1719
+ );
1720
+
1721
+ await tester.pump();
1722
+
1723
+ // Act & Assert
1724
+ expect(find.text('John Doe'), findsOneWidget);
1725
+ expect(find.text('Jane Smith'), findsOneWidget);
1726
+ expect(find.text('john@example.com'), findsOneWidget);
1727
+ expect(find.text('jane@example.com'), findsOneWidget);
1728
+ expect(find.byType(UserCard), findsNWidgets(2));
1729
+ });
1730
+ });
1731
+ }
1732
+ ```
1733
+
1734
+ ### Integration Testing
1735
+
1736
+ ```dart
1737
+ // Integration tests with Flutter integration_test package
1738
+ void main() {
1739
+ group('User Management Integration Tests', () {
1740
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
1741
+
1742
+ testWidgets('should complete user creation flow', (WidgetTester tester) async {
1743
+ // Arrange
1744
+ app.main();
1745
+ await tester.pumpAndSettle();
1746
+
1747
+ // Navigate to add user screen
1748
+ await tester.tap(find.byIcon(Icons.add));
1749
+ await tester.pumpAndSettle();
1750
+
1751
+ // Fill out user form
1752
+ await tester.enterText(find.byKey(const Key('name_field')), 'John Doe');
1753
+ await tester.enterText(find.byKey(const Key('email_field')), 'john@example.com');
1754
+
1755
+ // Submit form
1756
+ await tester.tap(find.byKey(const Key('submit_button')));
1757
+ await tester.pumpAndSettle();
1758
+
1759
+ // Assert user appears in list
1760
+ expect(find.text('John Doe'), findsOneWidget);
1761
+ expect(find.text('john@example.com'), findsOneWidget);
1762
+ });
1763
+
1764
+ testWidgets('should navigate to user details and back', (WidgetTester tester) async {
1765
+ // Arrange
1766
+ app.main();
1767
+ await tester.pumpAndSettle();
1768
+
1769
+ // Wait for users to load
1770
+ await tester.pumpAndSettle(const Duration(seconds: 3));
1771
+
1772
+ // Tap on first user
1773
+ await tester.tap(find.byType(UserCard).first);
1774
+ await tester.pumpAndSettle();
1775
+
1776
+ // Assert we're on user details screen
1777
+ expect(find.byType(UserDetailScreen), findsOneWidget);
1778
+
1779
+ // Navigate back
1780
+ await tester.tap(find.byIcon(Icons.arrow_back));
1781
+ await tester.pumpAndSettle();
1782
+
1783
+ // Assert we're back on user list
1784
+ expect(find.byType(UserListScreen), findsOneWidget);
1785
+ });
1786
+
1787
+ testWidgets('should handle network errors gracefully', (WidgetTester tester) async {
1788
+ // Arrange - mock network failure
1789
+ setUpAll(() {
1790
+ HttpOverrides.global = MockHttpOverrides();
1791
+ });
1792
+
1793
+ app.main();
1794
+ await tester.pumpAndSettle();
1795
+
1796
+ // Wait for error to appear
1797
+ await tester.pumpAndSettle(const Duration(seconds: 3));
1798
+
1799
+ // Assert error message is shown
1800
+ expect(find.byType(ErrorWidget), findsOneWidget);
1801
+
1802
+ // Tap retry button
1803
+ await tester.tap(find.byType(ElevatedButton));
1804
+ await tester.pumpAndSettle();
1805
+
1806
+ // Verify retry attempts
1807
+ expect(find.text('Retrying...'), findsOneWidget);
1808
+ });
1809
+ });
1810
+ }
1811
+
1812
+ // Mock HTTP overrides for testing
1813
+ class MockHttpOverrides extends HttpOverrides {
1814
+ @override
1815
+ HttpClient createHttpClient(SecurityContext? context) {
1816
+ return MockHttpClient();
1817
+ }
1818
+ }
1819
+
1820
+ class MockHttpClient extends FakeHttpClient {
1821
+ @override
1822
+ Future<HttpClientRequest> getUrl(Uri url) async {
1823
+ if (url.path.contains('/users')) {
1824
+ throw HttpClientException('Connection failed');
1825
+ }
1826
+ return super.getUrl(url);
1827
+ }
1828
+ }
1829
+
1830
+ // Golden tests for visual regression
1831
+ void main() {
1832
+ group('UserCard Golden Tests', () {
1833
+ testWidgets('should match golden snapshot', (WidgetTester tester) async {
1834
+ // Arrange
1835
+ const user = User(
1836
+ id: '123',
1837
+ name: 'John Doe',
1838
+ email: 'john@example.com',
1839
+ avatarUrl: 'https://example.com/avatar.jpg',
1840
+ );
1841
+
1842
+ // Act
1843
+ await tester.pumpWidget(
1844
+ MaterialApp(
1845
+ theme: ThemeData.light(),
1846
+ home: Scaffold(
1847
+ body: UserCard(user: user),
1848
+ ),
1849
+ ),
1850
+ );
1851
+
1852
+ await tester.pumpAndSettle();
1853
+
1854
+ // Assert
1855
+ await expectLater(
1856
+ find.byType(UserCard),
1857
+ matchesGoldenFile('goldens/user_card.png'),
1858
+ );
1859
+ });
1860
+
1861
+ testWidgets('should match dark mode golden snapshot', (WidgetTester tester) async {
1862
+ // Arrange
1863
+ const user = User(
1864
+ id: '123',
1865
+ name: 'John Doe',
1866
+ email: 'john@example.com',
1867
+ avatarUrl: 'https://example.com/avatar.jpg',
1868
+ );
1869
+
1870
+ // Act
1871
+ await tester.pumpWidget(
1872
+ MaterialApp(
1873
+ theme: ThemeData.dark(),
1874
+ home: Scaffold(
1875
+ body: UserCard(user: user),
1876
+ ),
1877
+ ),
1878
+ );
1879
+
1880
+ await tester.pumpAndSettle();
1881
+
1882
+ // Assert
1883
+ await expectLater(
1884
+ find.byType(UserCard),
1885
+ matchesGoldenFile('goldens/user_card_dark.png'),
1886
+ );
1887
+ });
1888
+ });
1889
+ }
1890
+ ```
1891
+
1892
+ ## Security Best Practices
1893
+
1894
+ ### Input Validation
1895
+
1896
+ ```dart
1897
+ // Input validation utilities
1898
+ class InputValidator {
1899
+ static String? validateEmail(String? value) {
1900
+ if (value == null || value.isEmpty) {
1901
+ return 'Email is required';
1902
+ }
1903
+
1904
+ if (!value.isValidEmail) {
1905
+ return 'Please enter a valid email address';
1906
+ }
1907
+
1908
+ return null;
1909
+ }
1910
+
1911
+ static String? validatePassword(String? value) {
1912
+ if (value == null || value.isEmpty) {
1913
+ return 'Password is required';
1914
+ }
1915
+
1916
+ if (value.length < 8) {
1917
+ return 'Password must be at least 8 characters long';
1918
+ }
1919
+
1920
+ if (!value.contains(RegExp(r'[A-Z]'))) {
1921
+ return 'Password must contain at least one uppercase letter';
1922
+ }
1923
+
1924
+ if (!value.contains(RegExp(r'[a-z]'))) {
1925
+ return 'Password must contain at least one lowercase letter';
1926
+ }
1927
+
1928
+ if (!value.contains(RegExp(r'[0-9]'))) {
1929
+ return 'Password must contain at least one digit';
1930
+ }
1931
+
1932
+ return null;
1933
+ }
1934
+
1935
+ static String? validateName(String? value) {
1936
+ if (value == null || value.isEmpty) {
1937
+ return 'Name is required';
1938
+ }
1939
+
1940
+ if (value.length < 2) {
1941
+ return 'Name must be at least 2 characters long';
1942
+ }
1943
+
1944
+ if (value.length > 50) {
1945
+ return 'Name must be less than 50 characters';
1946
+ }
1947
+
1948
+ if (!value.contains(RegExp(r'^[a-zA-Z\s]+$'))) {
1949
+ return 'Name can only contain letters and spaces';
1950
+ }
1951
+
1952
+ return null;
1953
+ }
1954
+ }
1955
+
1956
+ // Secure storage for sensitive data
1957
+ class SecureStorage {
1958
+ static const _storage = FlutterSecureStorage();
1959
+
1960
+ static Future<void> storeToken(String token) async {
1961
+ await _storage.write(key: 'auth_token', value: token);
1962
+ }
1963
+
1964
+ static Future<String?> getToken() async {
1965
+ return await _storage.read(key: 'auth_token');
1966
+ }
1967
+
1968
+ static Future<void> deleteToken() async {
1969
+ await _storage.delete(key: 'auth_token');
1970
+ }
1971
+
1972
+ static Future<void> storeUserCredentials(String username, String password) async {
1973
+ await _storage.write(key: 'username', value: username);
1974
+ await _storage.write(key: 'password', value: password);
1975
+ }
1976
+
1977
+ static Future<Map<String, String?>> getUserCredentials() async {
1978
+ final username = await _storage.read(key: 'username');
1979
+ final password = await _storage.read(key: 'password');
1980
+ return {'username': username, 'password': password};
1981
+ }
1982
+
1983
+ static Future<void> clearAll() async {
1984
+ await _storage.deleteAll();
1985
+ }
1986
+ }
1987
+
1988
+ // Secure HTTP client with authentication
1989
+ class SecureHttpClient {
1990
+ late final Dio _dio;
1991
+
1992
+ SecureHttpClient() {
1993
+ _dio = Dio(BaseOptions(
1994
+ baseUrl: AppConfig.apiBaseUrl,
1995
+ connectTimeout: const Duration(seconds: 30),
1996
+ receiveTimeout: const Duration(seconds: 30),
1997
+ ));
1998
+
1999
+ _setupInterceptors();
2000
+ }
2001
+
2002
+ void _setupInterceptors() {
2003
+ // Authentication interceptor
2004
+ _dio.interceptors.add(
2005
+ InterceptorsWrapper(
2006
+ onRequest: (options, handler) async {
2007
+ final token = await SecureStorage.getToken();
2008
+ if (token != null) {
2009
+ options.headers['Authorization'] = 'Bearer $token';
2010
+ }
2011
+ handler.next(options);
2012
+ },
2013
+ onError: (error, handler) async {
2014
+ if (error.response?.statusCode == 401) {
2015
+ // Token expired, clear storage and navigate to login
2016
+ await SecureStorage.deleteToken();
2017
+ // Navigate to login screen
2018
+ _navigateToLogin();
2019
+ }
2020
+ handler.next(error);
2021
+ },
2022
+ ),
2023
+ );
2024
+
2025
+ // Logging interceptor (only in debug mode)
2026
+ if (AppConfig.isDebug) {
2027
+ _dio.interceptors.add(LogInterceptor(
2028
+ requestBody: true,
2029
+ responseBody: true,
2030
+ ));
2031
+ }
2032
+
2033
+ // Retry interceptor
2034
+ _dio.interceptors.add(RetryInterceptor(
2035
+ dio: _dio,
2036
+ options: const RetryOptions(
2037
+ retries: 3,
2038
+ retryInterval: Duration(seconds: 1),
2039
+ ),
2040
+ ));
2041
+ }
2042
+
2043
+ void _navigateToLogin() {
2044
+ // Use navigator key to navigate to login screen
2045
+ navigatorKey.currentState?.pushNamedAndRemoveUntil(
2046
+ '/login',
2047
+ (route) => false,
2048
+ );
2049
+ }
2050
+
2051
+ Future<Response<T>> get<T>(
2052
+ String path, {
2053
+ Map<String, dynamic>? queryParameters,
2054
+ Options? options,
2055
+ }) async {
2056
+ return _dio.get<T>(path, queryParameters: queryParameters, options: options);
2057
+ }
2058
+
2059
+ Future<Response<T>> post<T>(
2060
+ String path, {
2061
+ dynamic data,
2062
+ Map<String, dynamic>? queryParameters,
2063
+ Options? options,
2064
+ }) async {
2065
+ return _dio.post<T>(
2066
+ path,
2067
+ data: data,
2068
+ queryParameters: queryParameters,
2069
+ options: options,
2070
+ );
2071
+ }
2072
+
2073
+ Future<Response<T>> put<T>(
2074
+ String path, {
2075
+ dynamic data,
2076
+ Map<String, dynamic>? queryParameters,
2077
+ Options? options,
2078
+ }) async {
2079
+ return _dio.put<T>(
2080
+ path,
2081
+ data: data,
2082
+ queryParameters: queryParameters,
2083
+ options: options,
2084
+ );
2085
+ }
2086
+
2087
+ Future<Response<T>> delete<T>(
2088
+ String path, {
2089
+ dynamic data,
2090
+ Map<String, dynamic>? queryParameters,
2091
+ Options? options,
2092
+ }) async {
2093
+ return _dio.delete<T>(
2094
+ path,
2095
+ data: data,
2096
+ queryParameters: queryParameters,
2097
+ options: options,
2098
+ );
2099
+ }
2100
+ }
2101
+
2102
+ // Local authentication with biometrics
2103
+ class BiometricAuth {
2104
+ static final LocalAuthentication _auth = LocalAuthentication();
2105
+
2106
+ static Future<bool> isAvailable() async {
2107
+ final isAvailable = await _auth.canCheckBiometrics;
2108
+ final isDeviceSupported = await _auth.isDeviceSupported();
2109
+ return isAvailable && isDeviceSupported;
2110
+ }
2111
+
2112
+ static Future<bool> authenticate() async {
2113
+ try {
2114
+ final didAuthenticate = await _auth.authenticate(
2115
+ localizedReason: 'Please authenticate to access this feature',
2116
+ options: const AuthenticationOptions(
2117
+ biometricOnly: false,
2118
+ useErrorDialogs: true,
2119
+ stickyAuth: true,
2120
+ ),
2121
+ );
2122
+ return didAuthenticate;
2123
+ } catch (e) {
2124
+ return false;
2125
+ }
2126
+ }
2127
+
2128
+ static Future<List<BiometricType>> getAvailableBiometrics() async {
2129
+ try {
2130
+ return await _auth.getAvailableBiometrics();
2131
+ } catch (e) {
2132
+ return [];
2133
+ }
2134
+ }
2135
+ }
2136
+ ```
2137
+
2138
+ ### Data Protection
2139
+
2140
+ ```dart
2141
+ // Encrypted data model
2142
+ class SecureUser {
2143
+ final String id;
2144
+ final String encryptedName;
2145
+ final String encryptedEmail;
2146
+
2147
+ SecureUser({
2148
+ required this.id,
2149
+ required this.encryptedName,
2150
+ required this.encryptedEmail,
2151
+ });
2152
+
2153
+ factory SecureUser.fromUser(User user, EncryptionService encryptionService) {
2154
+ return SecureUser(
2155
+ id: user.id,
2156
+ encryptedName: encryptionService.encrypt(user.name),
2157
+ encryptedEmail: encryptionService.encrypt(user.email),
2158
+ );
2159
+ }
2160
+
2161
+ User toUser(EncryptionService encryptionService) {
2162
+ return User(
2163
+ id: id,
2164
+ name: encryptionService.decrypt(encryptedName),
2165
+ email: encryptionService.decrypt(encryptedEmail),
2166
+ avatarUrl: '', // Not encrypted in this example
2167
+ );
2168
+ }
2169
+ }
2170
+
2171
+ // Encryption service
2172
+ class EncryptionService {
2173
+ static final EncryptionService _instance = EncryptionService._internal();
2174
+ factory EncryptionService() => _instance;
2175
+ EncryptionService._internal();
2176
+
2177
+ late final Encrypter _encrypter;
2178
+ late final IV _iv;
2179
+
2180
+ Future<void> initialize() async {
2181
+ final key = await _getOrCreateKey();
2182
+ _encrypter = Encrypter(AES(key));
2183
+ _iv = IV.fromLength(16);
2184
+ }
2185
+
2186
+ Future<Key> _getOrCreateKey() async {
2187
+ const storage = FlutterSecureStorage();
2188
+
2189
+ String? keyString = await storage.read(key: 'encryption_key');
2190
+ if (keyString != null) {
2191
+ return Key.fromBase64(keyString);
2192
+ }
2193
+
2194
+ final key = Key.fromSecureRandom(32);
2195
+ await storage.write(key: 'encryption_key', value: key.base64);
2196
+ return key;
2197
+ }
2198
+
2199
+ String encrypt(String plaintext) {
2200
+ final encrypted = _encrypter.encrypt(plaintext, iv: _iv);
2201
+ return encrypted.base64;
2202
+ }
2203
+
2204
+ String decrypt(String ciphertext) {
2205
+ final encrypted = Encrypted.fromBase64(ciphertext);
2206
+ return _encrypter.decrypt(encrypted, iv: _iv);
2207
+ }
2208
+
2209
+ Future<void> clearKey() async {
2210
+ const storage = FlutterSecureStorage();
2211
+ await storage.delete(key: 'encryption_key');
2212
+ }
2213
+ }
2214
+
2215
+ // API security with rate limiting
2216
+ class RateLimiter {
2217
+ final Map<String, List<DateTime>> _requests = {};
2218
+ final int maxRequests;
2219
+ final Duration timeWindow;
2220
+
2221
+ RateLimiter({
2222
+ this.maxRequests = 100,
2223
+ this.timeWindow = const Duration(minutes: 1),
2224
+ });
2225
+
2226
+ bool canMakeRequest(String identifier) {
2227
+ final now = DateTime.now();
2228
+ final requests = _requests[identifier] ?? [];
2229
+
2230
+ // Remove old requests outside the time window
2231
+ requests.removeWhere((request) => now.difference(request) > timeWindow);
2232
+
2233
+ if (requests.length >= maxRequests) {
2234
+ return false;
2235
+ }
2236
+
2237
+ requests.add(now);
2238
+ _requests[identifier] = requests;
2239
+ return true;
2240
+ }
2241
+
2242
+ Duration? getTimeUntilNextRequest(String identifier) {
2243
+ final now = DateTime.now();
2244
+ final requests = _requests[identifier] ?? [];
2245
+
2246
+ if (requests.length < maxRequests) {
2247
+ return null;
2248
+ }
2249
+
2250
+ final oldestRequest = requests.first;
2251
+ final timeSinceOldest = now.difference(oldestRequest);
2252
+
2253
+ if (timeSinceOldest > timeWindow) {
2254
+ return null;
2255
+ }
2256
+
2257
+ return timeWindow - timeSinceOldest;
2258
+ }
2259
+ }
2260
+
2261
+ // Content security for web applications
2262
+ class ContentSecurityPolicy {
2263
+ static String get policy {
2264
+ return [
2265
+ "default-src 'self'",
2266
+ "script-src 'self' 'unsafe-inline' 'unsafe-eval'",
2267
+ "style-src 'self' 'unsafe-inline'",
2268
+ "img-src 'self' data: https:",
2269
+ "font-src 'self' data:",
2270
+ "connect-src 'self' https://api.example.com",
2271
+ "media-src 'self'",
2272
+ "object-src 'none'",
2273
+ "base-uri 'self'",
2274
+ "form-action 'self'",
2275
+ "frame-ancestors 'none'",
2276
+ "upgrade-insecure-requests",
2277
+ ].join('; ');
2278
+ }
2279
+ }
64
2280
  ```
65
2281
 
66
- ## Inputs
67
- - Language-specific source directories (e.g. `src/`, `app/`).
68
- - Language-specific build/test configuration files (e.g. `package.json`, `pyproject.toml`, `go.mod`).
69
- - Relevant test suites and sample data.
2282
+ ## Integration Patterns
2283
+
2284
+ ### Server-Side Dart with Shelf
70
2285
 
71
- ## Outputs
72
- - Test/lint execution plan tailored to the selected language.
73
- - List of key language idioms and review checkpoints.
2286
+ ```dart
2287
+ // Server-side Dart application
2288
+ import 'dart:io';
2289
+ import 'dart:convert';
2290
+ import 'package:shelf/shelf.dart';
2291
+ import 'package:shelf/shelf_io.dart' as shelf_io;
2292
+ import 'package:shelf_router/shelf_router.dart';
2293
+ import 'package:shelf_cors_headers/shelf_cors_headers.dart';
2294
+ import 'package:shelf_static/shelf_static.dart';
74
2295
 
75
- ## Failure Modes
76
- - When the language runtime or package manager is not installed.
77
- - When the main language cannot be determined in a multilingual project.
2296
+ // User service for server-side
2297
+ class UserService {
2298
+ final Map<String, User> _users = {};
2299
+
2300
+ UserService() {
2301
+ _seedUsers();
2302
+ }
2303
+
2304
+ void _seedUsers() {
2305
+ _users['1'] = const User(
2306
+ id: '1',
2307
+ name: 'John Doe',
2308
+ email: 'john@example.com',
2309
+ avatarUrl: 'https://example.com/avatar1.jpg',
2310
+ );
2311
+ _users['2'] = const User(
2312
+ id: '2',
2313
+ name: 'Jane Smith',
2314
+ email: 'jane@example.com',
2315
+ avatarUrl: 'https://example.com/avatar2.jpg',
2316
+ );
2317
+ }
2318
+
2319
+ List<User> getUsers({int page = 1, int limit = 20}) {
2320
+ final skip = (page - 1) * limit;
2321
+ return _users.values.skip(skip).take(limit).toList();
2322
+ }
2323
+
2324
+ User? getUser(String id) {
2325
+ return _users[id];
2326
+ }
2327
+
2328
+ User createUser(CreateUserRequest request) {
2329
+ final id = (_users.keys.length + 1).toString();
2330
+ final user = User(
2331
+ id: id,
2332
+ name: request.name,
2333
+ email: request.email,
2334
+ avatarUrl: request.avatarUrl ?? '',
2335
+ );
2336
+ _users[id] = user;
2337
+ return user;
2338
+ }
2339
+
2340
+ User? updateUser(String id, UpdateUserRequest request) {
2341
+ final user = _users[id];
2342
+ if (user == null) return null;
2343
+
2344
+ final updatedUser = user.copyWith(
2345
+ name: request.name ?? user.name,
2346
+ email: request.email ?? user.email,
2347
+ avatarUrl: request.avatarUrl ?? user.avatarUrl,
2348
+ );
2349
+
2350
+ _users[id] = updatedUser;
2351
+ return updatedUser;
2352
+ }
2353
+
2354
+ bool deleteUser(String id) {
2355
+ return _users.remove(id) != null;
2356
+ }
2357
+ }
78
2358
 
79
- ## Dependencies
80
- - Access to the project file is required using the Read/Grep tool.
81
- - When used with `Skill("moai-foundation-langs")`, it is easy to share cross-language conventions.
2359
+ // Request handlers
2360
+ Handler getUsersHandler(UserService userService) {
2361
+ return (Request request) async {
2362
+ final page = int.tryParse(request.url.queryParameters['page'] ?? '1') ?? 1;
2363
+ final limit = int.tryParse(request.url.queryParameters['limit'] ?? '20') ?? 20;
2364
+
2365
+ final users = userService.getUsers(page: page, limit: limit);
2366
+
2367
+ final response = {
2368
+ 'users': users.map((u) => u.toJson()).toList(),
2369
+ 'page': page,
2370
+ 'limit': limit,
2371
+ 'total': users.length,
2372
+ };
2373
+
2374
+ return Response.ok(
2375
+ json.encode(response),
2376
+ headers: {'content-type': 'application/json'},
2377
+ );
2378
+ };
2379
+ }
82
2380
 
83
- ## References
84
- - Google. "Dart Language Tour." https://dart.dev/guides/language/language-tour (accessed 2025-03-29).
85
- - Flutter. "Testing." https://docs.flutter.dev/testing (accessed 2025-03-29).
2381
+ Handler getUserHandler(UserService userService) {
2382
+ return (Request request) {
2383
+ final id = request.params['id']!;
2384
+ final user = userService.getUser(id);
2385
+
2386
+ if (user == null) {
2387
+ return Response.notFound(json.encode({'error': 'User not found'}));
2388
+ }
2389
+
2390
+ return Response.ok(
2391
+ json.encode(user.toJson()),
2392
+ headers: {'content-type': 'application/json'},
2393
+ );
2394
+ };
2395
+ }
86
2396
 
87
- ## Changelog
88
- - 2025-03-29: Input/output/failure response/reference information for each language has been specified.
2397
+ Handler createUserHandler(UserService userService) {
2398
+ return (Request request) async {
2399
+ try {
2400
+ final body = await request.readAsString();
2401
+ final jsonData = json.decode(body) as Map<String, dynamic>;
2402
+ final createRequest = CreateUserRequest.fromJson(jsonData);
2403
+
2404
+ final user = userService.createUser(createRequest);
2405
+
2406
+ return Response(201,
2407
+ body: json.encode(user.toJson()),
2408
+ headers: {'content-type': 'application/json'},
2409
+ );
2410
+ } catch (e) {
2411
+ return Response(400,
2412
+ body: json.encode({'error': 'Invalid request data: $e'}),
2413
+ headers: {'content-type': 'application/json'},
2414
+ );
2415
+ }
2416
+ };
2417
+ }
89
2418
 
90
- ## Works well with
2419
+ // Router setup
2420
+ Router setupRouter(UserService userService) {
2421
+ final router = Router();
2422
+
2423
+ // CORS headers
2424
+ router.all('/<ignored|.*>', (Request request) {
2425
+ return Response.ok(null);
2426
+ });
2427
+
2428
+ // API routes
2429
+ router.get('/users', getUsersHandler(userService));
2430
+ router.get('/users/<id>', getUserHandler(userService));
2431
+ router.post('/users', createUserHandler(userService));
2432
+ router.put('/users/<id>', updateUserHandler(userService));
2433
+ router.delete('/users/<id>', deleteUserHandler(userService));
2434
+
2435
+ // Static file serving
2436
+ router.get('/<.*>', (Request request) {
2437
+ final path = request.url.path;
2438
+ if (path.startsWith('/api/')) {
2439
+ return Response.notFound('Not found');
2440
+ }
2441
+
2442
+ return staticHandler('web')(request);
2443
+ });
2444
+
2445
+ return router;
2446
+ }
2447
+
2448
+ // Static file handler
2449
+ Handler staticHandler(String directory) {
2450
+ return createStaticHandler(directory, defaultDocument: 'index.html');
2451
+ }
2452
+
2453
+ // Main server function
2454
+ Future<void> main() async {
2455
+ final userService = UserService();
2456
+ final router = setupRouter(userService);
2457
+
2458
+ // Add CORS middleware
2459
+ final handler = const Pipeline()
2460
+ .addMiddleware(corsHeaders())
2461
+ .addMiddleware(logRequests())
2462
+ .addHandler(router);
2463
+
2464
+ // Start server
2465
+ final server = await shelf_io.serve(
2466
+ handler,
2467
+ InternetAddress.anyIPv4,
2468
+ 8080,
2469
+ );
2470
+
2471
+ print('Server listening on port ${server.port}');
2472
+ }
2473
+
2474
+ // Logging middleware
2475
+ Middleware logRequests() {
2476
+ return (Handler innerHandler) {
2477
+ return (Request request) async {
2478
+ final startTime = DateTime.now();
2479
+
2480
+ try {
2481
+ final response = await innerHandler(request);
2482
+ final duration = DateTime.now().difference(startTime);
2483
+
2484
+ print(
2485
+ '${request.method} ${request.requestedUri} -> '
2486
+ '${response.statusCode} (${duration.inMilliseconds}ms)',
2487
+ );
2488
+
2489
+ return response;
2490
+ } catch (error, stackTrace) {
2491
+ final duration = DateTime.now().difference(startTime);
2492
+
2493
+ print(
2494
+ '${request.method} ${request.requestedUri} -> ERROR ($duration): $error',
2495
+ );
2496
+
2497
+ rethrow;
2498
+ }
2499
+ };
2500
+ };
2501
+ }
2502
+ ```
2503
+
2504
+ ### WebSockets for Real-time Communication
2505
+
2506
+ ```dart
2507
+ // WebSocket server implementation
2508
+ import 'dart:io';
2509
+ import 'dart:convert';
2510
+
2511
+ class WebSocketServer {
2512
+ late HttpServer _server;
2513
+ final Set<WebSocket> _connections = {};
2514
+
2515
+ Future<void> start(int port) async {
2516
+ _server = await HttpServer.bind(InternetAddress.anyIPv4, port);
2517
+ print('WebSocket server listening on port $port');
2518
+
2519
+ await for (HttpRequest request in _server) {
2520
+ if (request.uri.path == '/ws') {
2521
+ await _handleWebSocket(request);
2522
+ } else {
2523
+ request.response.statusCode = HttpStatus.notFound;
2524
+ await request.response.close();
2525
+ }
2526
+ }
2527
+ }
2528
+
2529
+ Future<void> _handleWebSocket(HttpRequest request) async {
2530
+ try {
2531
+ final webSocket = await WebSocketTransformer.upgrade(request);
2532
+ _connections.add(webSocket);
2533
+
2534
+ print('New WebSocket connection: ${webSocket.hashCode}');
2535
+
2536
+ // Send welcome message
2537
+ _sendMessage(webSocket, {
2538
+ 'type': 'welcome',
2539
+ 'message': 'Connected to chat server',
2540
+ 'timestamp': DateTime.now().toIso8601String(),
2541
+ });
2542
+
2543
+ // Listen for messages
2544
+ webSocket.listen(
2545
+ (data) => _handleMessage(webSocket, data),
2546
+ onDone: () => _handleDisconnection(webSocket),
2547
+ onError: (error) => print('WebSocket error: $error'),
2548
+ );
2549
+ } catch (e) {
2550
+ print('Failed to upgrade to WebSocket: $e');
2551
+ request.response.statusCode = HttpStatus.internalServerError;
2552
+ await request.response.close();
2553
+ }
2554
+ }
2555
+
2556
+ void _handleMessage(WebSocket webSocket, dynamic data) {
2557
+ try {
2558
+ final message = json.decode(data as String) as Map<String, dynamic>;
2559
+ final messageWithTimestamp = {
2560
+ ...message,
2561
+ 'timestamp': DateTime.now().toIso8601String(),
2562
+ };
2563
+
2564
+ print('Received message: $messageWithTimestamp');
2565
+
2566
+ // Broadcast message to all connected clients
2567
+ _broadcastMessage(messageWithTimestamp);
2568
+ } catch (e) {
2569
+ print('Error handling message: $e');
2570
+ _sendMessage(webSocket, {
2571
+ 'type': 'error',
2572
+ 'message': 'Invalid message format',
2573
+ 'timestamp': DateTime.now().toIso8601String(),
2574
+ });
2575
+ }
2576
+ }
2577
+
2578
+ void _handleDisconnection(WebSocket webSocket) {
2579
+ _connections.remove(webSocket);
2580
+ print('WebSocket disconnected: ${webSocket.hashCode}');
2581
+
2582
+ _broadcastMessage({
2583
+ 'type': 'user_disconnected',
2584
+ 'message': 'A user left the chat',
2585
+ 'timestamp': DateTime.now().toIso8601String(),
2586
+ });
2587
+ }
2588
+
2589
+ void _sendMessage(WebSocket webSocket, Map<String, dynamic> message) {
2590
+ try {
2591
+ webSocket.add(json.encode(message));
2592
+ } catch (e) {
2593
+ print('Error sending message: $e');
2594
+ }
2595
+ }
2596
+
2597
+ void _broadcastMessage(Map<String, dynamic> message) {
2598
+ final messageString = json.encode(message);
2599
+
2600
+ for (final connection in _connections) {
2601
+ try {
2602
+ connection.add(messageString);
2603
+ } catch (e) {
2604
+ print('Error broadcasting message: $e');
2605
+ }
2606
+ }
2607
+ }
2608
+
2609
+ Future<void> stop() async {
2610
+ await _server.close();
2611
+ for (final connection in _connections) {
2612
+ await connection.close();
2613
+ }
2614
+ }
2615
+ }
2616
+
2617
+ // Chat message models
2618
+ class ChatMessage {
2619
+ final String id;
2620
+ final String username;
2621
+ final String content;
2622
+ final DateTime timestamp;
2623
+
2624
+ ChatMessage({
2625
+ required this.id,
2626
+ required this.username,
2627
+ required this.content,
2628
+ required this.timestamp,
2629
+ });
2630
+
2631
+ Map<String, dynamic> toJson() {
2632
+ return {
2633
+ 'id': id,
2634
+ 'username': username,
2635
+ 'content': content,
2636
+ 'timestamp': timestamp.toIso8601String(),
2637
+ };
2638
+ }
2639
+
2640
+ factory ChatMessage.fromJson(Map<String, dynamic> json) {
2641
+ return ChatMessage(
2642
+ id: json['id'] as String,
2643
+ username: json['username'] as String,
2644
+ content: json['content'] as String,
2645
+ timestamp: DateTime.parse(json['timestamp'] as String),
2646
+ );
2647
+ }
2648
+ }
2649
+
2650
+ // WebSocket client for Flutter
2651
+ class WebSocketService {
2652
+ WebSocketChannel? _channel;
2653
+ final StreamController<ChatMessage> _messageController = StreamController<ChatMessage>.broadcast();
2654
+ final StreamController<String> _statusController = StreamController<String>.broadcast();
2655
+
2656
+ Stream<ChatMessage> get messageStream => _messageController.stream;
2657
+ Stream<String> get statusStream => _statusController.stream;
2658
+
2659
+ Future<void> connect(String url) async {
2660
+ try {
2661
+ _channel = WebSocketChannel.connect(Uri.parse(url));
2662
+ _statusController.add('Connected');
2663
+
2664
+ _channel!.stream.listen(
2665
+ (data) {
2666
+ try {
2667
+ final message = ChatMessage.fromJson(json.decode(data));
2668
+ _messageController.add(message);
2669
+ } catch (e) {
2670
+ print('Error parsing message: $e');
2671
+ }
2672
+ },
2673
+ onDone: () {
2674
+ _statusController.add('Disconnected');
2675
+ },
2676
+ onError: (error) {
2677
+ _statusController.add('Error: $error');
2678
+ },
2679
+ );
2680
+ } catch (e) {
2681
+ _statusController.add('Connection failed: $e');
2682
+ }
2683
+ }
2684
+
2685
+ void sendMessage(ChatMessage message) {
2686
+ if (_channel != null) {
2687
+ _channel!.sink.add(json.encode(message.toJson()));
2688
+ }
2689
+ }
2690
+
2691
+ void disconnect() {
2692
+ _channel?.sink.close();
2693
+ _channel = null;
2694
+ }
2695
+
2696
+ void dispose() {
2697
+ disconnect();
2698
+ _messageController.close();
2699
+ _statusController.close();
2700
+ }
2701
+ }
2702
+ ```
2703
+
2704
+ ## Modern Development Workflow
2705
+
2706
+ ### Project Configuration
2707
+
2708
+ ```yaml
2709
+ # pubspec.yaml
2710
+ name: my_flutter_app
2711
+ description: A comprehensive Flutter application
2712
+ publish_to: 'none'
2713
+
2714
+ version: 1.0.0+1
2715
+
2716
+ environment:
2717
+ sdk: '>=3.5.0 <4.0.0'
2718
+ flutter: ">=3.24.0"
2719
+
2720
+ dependencies:
2721
+ flutter:
2722
+ sdk: flutter
2723
+
2724
+ # State management
2725
+ flutter_riverpod: ^2.5.0
2726
+ provider: ^6.1.2
2727
+
2728
+ # Navigation
2729
+ go_router: ^13.2.0
2730
+
2731
+ # HTTP client
2732
+ dio: ^5.4.3+1
2733
+ retrofit: ^4.0.3
2734
+ json_annotation: ^4.8.1
2735
+
2736
+ # Local storage
2737
+ shared_preferences: ^2.2.3
2738
+ flutter_secure_storage: ^9.0.0
2739
+
2740
+ # Database
2741
+ sqflite: ^2.3.3
2742
+ drift: ^2.17.0
2743
+
2744
+ # Authentication
2745
+ local_auth: ^2.2.0
2746
+
2747
+ # UI components
2748
+ material_color_utilities: ^0.8.0
2749
+ flutter_svg: ^2.0.10+1
2750
+
2751
+ # Utilities
2752
+ uuid: ^4.4.0
2753
+ intl: ^0.19.0
2754
+ equatable: ^2.0.5
2755
+ json_serializable: ^6.7.1
2756
+
2757
+ # Testing
2758
+ flutter_test:
2759
+ sdk: flutter
2760
+ mockito: ^5.4.4
2761
+ build_runner: ^2.4.9
2762
+ retrofit_generator: ^8.0.6
2763
+ json_serializable: ^6.7.1
2764
+ drift_dev: ^2.17.0
2765
+
2766
+ dev_dependencies:
2767
+ flutter_test:
2768
+ sdk: flutter
2769
+
2770
+ # Code generation
2771
+ build_runner: ^2.4.9
2772
+ retrofit_generator: ^8.0.6
2773
+ json_serializable: ^6.7.1
2774
+ drift_dev: ^2.17.0
2775
+
2776
+ # Linting and formatting
2777
+ flutter_lints: ^4.0.0
2778
+ very_good_analysis: ^5.1.0
2779
+
2780
+ # Testing
2781
+ integration_test:
2782
+ sdk: flutter
2783
+ golden_toolkit: ^0.15.0
2784
+ network_image_mock: ^2.1.1
2785
+
2786
+ flutter:
2787
+ uses-material-design: true
2788
+
2789
+ assets:
2790
+ - assets/images/
2791
+ - assets/icons/
2792
+ - assets/config/
2793
+
2794
+ fonts:
2795
+ - family: Roboto
2796
+ fonts:
2797
+ - asset: fonts/Roboto-Regular.ttf
2798
+ - asset: fonts/Roboto-Bold.ttf
2799
+ weight: 700
2800
+ ```
2801
+
2802
+ ### Analysis Configuration
2803
+
2804
+ ```yaml
2805
+ # analysis_options.yaml
2806
+ include: package:very_good_analysis/analysis_options.yaml
2807
+
2808
+ analyzer:
2809
+ exclude:
2810
+ - "**/*.g.dart"
2811
+ - "**/*.freezed.dart"
2812
+
2813
+ language:
2814
+ strict-casts: true
2815
+ strict-inference: true
2816
+ strict-raw-types: true
2817
+
2818
+ errors:
2819
+ invalid_annotation_target: ignore
2820
+ missing_required_param: error
2821
+ missing_return: error
2822
+ todo: ignore
2823
+
2824
+ linter:
2825
+ rules:
2826
+ # Additional rules beyond very_good_analysis
2827
+ prefer_single_quotes: true
2828
+ sort_constructors_first: true
2829
+ sort_unnamed_constructors_first: true
2830
+ always_declare_return_types: true
2831
+ avoid_print: true
2832
+ avoid_unnecessary_containers: true
2833
+ sized_box_for_whitespace: true
2834
+ use_key_in_widget_constructors: true
2835
+ prefer_const_constructors: true
2836
+ prefer_const_declarations: true
2837
+ prefer_const_literals_to_create_immutables: true
2838
+ avoid_web_libraries_in_flutter: true
2839
+ prefer_const_constructors_in_immutables: true
2840
+ prefer_final_fields: true
2841
+ use_full_hex_values_for_flutter_colors: true
2842
+ ```
2843
+
2844
+ ### CI/CD Configuration
2845
+
2846
+ ```yaml
2847
+ # .github/workflows/flutter.yml
2848
+ name: Flutter CI/CD
2849
+
2850
+ on:
2851
+ push:
2852
+ branches: [ main, develop ]
2853
+ pull_request:
2854
+ branches: [ main ]
2855
+
2856
+ jobs:
2857
+ test:
2858
+ runs-on: ubuntu-latest
2859
+
2860
+ steps:
2861
+ - uses: actions/checkout@v4
2862
+
2863
+ - name: Setup Flutter
2864
+ uses: subosito/flutter-action@v2
2865
+ with:
2866
+ channel: stable
2867
+ flutter-version: '3.24.x'
2868
+
2869
+ - name: Install dependencies
2870
+ run: flutter pub get
2871
+
2872
+ - name: Generate code
2873
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
2874
+
2875
+ - name: Analyze code
2876
+ run: flutter analyze
2877
+
2878
+ - name: Run tests
2879
+ run: flutter test --coverage --test-randomize-ordering-seed random
2880
+
2881
+ - name: Upload coverage to Codecov
2882
+ uses: codecov/codecov-action@v3
2883
+ with:
2884
+ file: coverage/lcov.info
2885
+
2886
+ - name: Run widget tests
2887
+ run: flutter test integration_test/
2888
+
2889
+ build_android:
2890
+ needs: test
2891
+ runs-on: ubuntu-latest
2892
+ if: github.ref == 'refs/heads/main'
2893
+
2894
+ steps:
2895
+ - uses: actions/checkout@v4
2896
+
2897
+ - name: Setup Flutter
2898
+ uses: subosito/flutter-action@v2
2899
+ with:
2900
+ channel: stable
2901
+ flutter-version: '3.24.x'
2902
+
2903
+ - name: Install dependencies
2904
+ run: flutter pub get
2905
+
2906
+ - name: Generate code
2907
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
2908
+
2909
+ - name: Build APK
2910
+ run: flutter build apk --release
2911
+
2912
+ - name: Build App Bundle
2913
+ run: flutter build appbundle --release
2914
+
2915
+ - name: Upload APK
2916
+ uses: actions/upload-artifact@v3
2917
+ with:
2918
+ name: android-apk
2919
+ path: build/app/outputs/flutter-apk/app-release.apk
2920
+
2921
+ - name: Upload App Bundle
2922
+ uses: actions/upload-artifact@v3
2923
+ with:
2924
+ name: android-aab
2925
+ path: build/app/outputs/bundle/release/app-release.aab
2926
+
2927
+ build_ios:
2928
+ needs: test
2929
+ runs-on: macos-latest
2930
+ if: github.ref == 'refs/heads/main'
2931
+
2932
+ steps:
2933
+ - uses: actions/checkout@v4
2934
+
2935
+ - name: Setup Flutter
2936
+ uses: subosito/flutter-action@v2
2937
+ with:
2938
+ channel: stable
2939
+ flutter-version: '3.24.x'
2940
+
2941
+ - name: Install dependencies
2942
+ run: flutter pub get
2943
+
2944
+ - name: Generate code
2945
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
2946
+
2947
+ - name: Build iOS
2948
+ run: flutter build ios --release --no-codesign
2949
+
2950
+ - name: Upload iOS build
2951
+ uses: actions/upload-artifact@v3
2952
+ with:
2953
+ name: ios-build
2954
+ path: build/ios/iphoneos/Runner.app
2955
+
2956
+ build_web:
2957
+ needs: test
2958
+ runs-on: ubuntu-latest
2959
+
2960
+ steps:
2961
+ - uses: actions/checkout@v4
2962
+
2963
+ - name: Setup Flutter
2964
+ uses: subosito/flutter-action@v2
2965
+ with:
2966
+ channel: stable
2967
+ flutter-version: '3.24.x'
2968
+
2969
+ - name: Install dependencies
2970
+ run: flutter pub get
2971
+
2972
+ - name: Generate code
2973
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
2974
+
2975
+ - name: Build web
2976
+ run: flutter build web --release
2977
+
2978
+ - name: Deploy to GitHub Pages
2979
+ uses: peaceiris/actions-gh-pages@v3
2980
+ with:
2981
+ github_token: ${{ secrets.GITHUB_TOKEN }}
2982
+ publish_dir: build/web
2983
+ ```
2984
+
2985
+ ---
91
2986
 
92
- - alfred-trust-validation (coverage verification)
93
- - alfred-code-reviewer (Dart-specific review)
94
- - mobile-app-expert (Flutter app development)
2987
+ **Created by**: MoAI Language Skill Factory
2988
+ **Last Updated**: 2025-11-06
2989
+ **Version**: 2.0.0
2990
+ **Dart Target**: 3.5.x with Flutter 3.24.x and modern async patterns
95
2991
 
96
- ## Best Practices
97
- - Enable automatic validation by matching your linter with the language's official style guide.
98
- - Fix test/build pipelines with reproducible commands in CI.
2992
+ This skill provides comprehensive Dart development guidance with 2025 best practices, covering everything from Flutter mobile applications to server-side development and real-time communication with WebSockets.