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,100 +1,1928 @@
1
1
  ---
2
-
3
2
  name: moai-lang-go
4
- description: Go best practices with go test, golint, gofmt, and standard library utilization. Use when writing or reviewing Go code in project workflows.
3
+ version: 2.0.0
4
+ created: 2025-11-06
5
+ updated: 2025-11-06
6
+ status: active
7
+ description: "Go best practices with modern cloud-native development, performance optimization, and concurrent programming for 2025"
8
+ keywords: [go, golang, backend, microservices, cloud-native, performance, concurrency, devops]
5
9
  allowed-tools:
6
10
  - Read
11
+ - Write
12
+ - Edit
7
13
  - Bash
14
+ - WebFetch
15
+ - WebSearch
8
16
  ---
9
17
 
10
- # Go Expert
18
+ # Go Development Mastery
19
+
20
+ **Modern Go Development with 2025 Best Practices**
21
+
22
+ > Comprehensive Go development guidance covering cloud-native services, high-performance concurrent programming, microservices architecture, and production-ready applications using the latest tools and methodologies.
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 | Go code discussions, framework guidance, or file extensions such as .go. |
18
- | Tier | 3 |
26
+ - **Cloud-Native Services**: Kubernetes, Docker, and container-native applications
27
+ - **High-Performance APIs**: Fast HTTP servers with minimal memory footprint
28
+ - **Concurrent Programming**: Goroutines, channels, and advanced patterns
29
+ - **Microservices Architecture**: Service discovery, load balancing, distributed systems
30
+ - **Testing & Quality**: Comprehensive testing, benchmarking, and quality assurance
31
+ - **Database Integration**: SQL, NoSQL, caching, and data pipelines
32
+ - **DevOps Integration**: CI/CD, monitoring, observability, and deployment
33
+ - **Enterprise Patterns**: Clean architecture, domain-driven design, scalability
19
34
 
20
- ## What it does
35
+ ## When to Use
21
36
 
22
- Provides Go-specific expertise for TDD development, including go test framework, golint/staticcheck, gofmt formatting, and effective standard library usage.
37
+ ### Perfect Scenarios
38
+ - **Building microservices and distributed systems**
39
+ - **High-performance network services and APIs**
40
+ - **Cloud-native applications and DevOps tools**
41
+ - **Concurrent and parallel processing applications**
42
+ - **System programming and infrastructure tools**
43
+ - **CLI applications and automation scripts**
44
+ - **Real-time data processing and streaming**
23
45
 
24
- ## When to use
46
+ ### Common Triggers
47
+ - "Create Go microservice"
48
+ - "Set up Go API server"
49
+ - "Go concurrent programming"
50
+ - "Go best practices"
51
+ - "Optimize Go performance"
52
+ - "Deploy Go application"
25
53
 
26
- - Engages when the conversation references Go work, frameworks, or files like .go.
27
- - “Writing Go tests”, “How to use go tests”, “Go standard library”
28
- - Automatically invoked when working with Go projects
29
- - Go SPEC implementation (`/alfred:2-run`)
54
+ ## Tool Version Matrix (2025-11-06)
30
55
 
31
- ## How it works
56
+ ### Core Go
57
+ - **Go**: 1.25.x (latest) / 1.23.x (LTS)
58
+ - **Gin**: 1.10.x - HTTP web framework
59
+ - **Echo**: 4.12.x - High-performance web framework
60
+ - **Chi**: 5.0.x - Lightweight router
61
+ - **Fiber**: 3.x - Express.js-inspired framework
32
62
 
33
- **TDD Framework**:
34
- - **go test**: Built-in testing framework
35
- - **Table-driven tests**: Structured test cases
36
- - **testify/assert**: Optional assertion library
37
- - Test coverage ≥85% with `go test -cover`
63
+ ### Database & Storage
64
+ - **GORM**: 2.0.x - ORM for Go
65
+ - **sqlx**: 1.4.x - SQL extensions
66
+ - **pgx**: 5.6.x - PostgreSQL driver
67
+ - **Redis**: 9.x - Redis client
68
+ - **MongoDB**: 2.x - MongoDB driver
38
69
 
39
- **Code Quality**:
40
- - **gofmt**: Automatic code formatting
41
- - **golint**: Go linter (deprecated, use staticcheck)
42
- - **staticcheck**: Advanced static analysis
43
- - **go vet**: Built-in error detection
70
+ ### Testing Tools
71
+ - **Testify**: 1.9.x - Testing toolkit
72
+ - **GoMock**: 1.6.x - Mock generation
73
+ - **gomock**: Built-in mocking framework
74
+ - **goleak**: 1.3.x - Goroutine leak detection
44
75
 
45
- **Standard Library**:
46
- - Use standard library first before external dependencies
47
- - **net/http**: HTTP server/client
48
- - **encoding/json**: JSON marshaling
49
- - **context**: Context propagation
76
+ ### Development Tools
77
+ - **Air**: 1.53.x - Live reload
78
+ - **Gin-swagger**: 1.6.x - API documentation
79
+ - **Zap**: 1.27.x - Structured logging
80
+ - **Viper**: 1.19.x - Configuration management
81
+ - **golangci-lint**: 1.62.x - Linter aggregator
50
82
 
51
- **Go Patterns**:
52
- - Interfaces for abstraction (small interfaces)
53
- - Error handling with explicit returns
54
- - Defer for cleanup
55
- - Goroutines and channels for concurrency
83
+ ### Observability
84
+ - **Prometheus**: 4.x client - Metrics
85
+ - **Jaeger**: 2.x client - Distributed tracing
86
+ - **OpenTelemetry**: 1.30.x - Observability framework
87
+ - **pprof**: Built-in profiling
56
88
 
57
- **Best Practices**:
58
- - File ≤300 LOC, function ≤50 LOC
59
- - Exported names start with capital letters
60
- - Error handling: `if err != nil { return err }`
61
- - Avoid naked returns in large functions
89
+ ## Ecosystem Overview
90
+
91
+ ### Project Setup (2025 Best Practice)
62
92
 
63
- ## Examples
64
93
  ```bash
65
- go test ./... && golangci-lint run
94
+ # Modern Go project with modules
95
+ go mod init github.com/your-org/your-project
96
+
97
+ # Initialize project structure
98
+ mkdir -p {cmd/server,internal/{handler,service,repository},pkg/{utils,middleware},configs,deployments/{docker,k8s},scripts,test}
99
+
100
+ # Install essential tools
101
+ go install github.com/cosmtrek/air@latest
102
+ go install github.com/swaggo/swag/cmd/swag@latest
103
+ go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
104
+ go install go.uber.org/mock/mockgen@latest
105
+
106
+ # Generate code documentation
107
+ swag init -g cmd/server/main.go
108
+ ```
109
+
110
+ ### Modern Project Structure
111
+
112
+ ```
113
+ my-go-project/
114
+ ├── go.mod
115
+ ├── go.sum
116
+ ├── Makefile # Build commands and utilities
117
+ ├── README.md
118
+ ├── .github/
119
+ │ └── workflows/ # CI/CD pipelines
120
+ ├── cmd/
121
+ │ └── server/
122
+ │ └── main.go # Application entry point
123
+ ├── internal/ # Private application code
124
+ │ ├── handler/ # HTTP handlers
125
+ │ ├── service/ # Business logic
126
+ │ ├── repository/ # Data access layer
127
+ │ ├── model/ # Domain models
128
+ │ └── middleware/ # HTTP middleware
129
+ ├── pkg/ # Public library code
130
+ │ ├── utils/ # Utility functions
131
+ │ ├── config/ # Configuration
132
+ │ └── logger/ # Logging utilities
133
+ ├── configs/ # Configuration files
134
+ ├── deployments/
135
+ │ ├── docker/ # Docker configurations
136
+ │ └── k8s/ # Kubernetes manifests
137
+ ├── scripts/ # Build and utility scripts
138
+ ├── test/ # Integration and e2e tests
139
+ ├── docs/ # API documentation
140
+ └── migrations/ # Database migrations
66
141
  ```
67
142
 
68
- ## Inputs
69
- - Language-specific source directories (e.g. `src/`, `app/`).
70
- - Language-specific build/test configuration files (e.g. `package.json`, `pyproject.toml`, `go.mod`).
71
- - Relevant test suites and sample data.
143
+ ## Modern Go Patterns
144
+
145
+ ### Context-First Design
146
+
147
+ ```go
148
+ // handler/user.go
149
+ package handler
150
+
151
+ import (
152
+ "context"
153
+ "net/http"
154
+ "time"
155
+
156
+ "github.com/gin-gonic/gin"
157
+ "github.com/your-org/your-project/internal/model"
158
+ "github.com/your-org/your-project/internal/service"
159
+ )
160
+
161
+ type UserHandler struct {
162
+ userService service.UserService
163
+ logger Logger
164
+ }
165
+
166
+ func NewUserHandler(userService service.UserService, logger Logger) *UserHandler {
167
+ return &UserHandler{
168
+ userService: userService,
169
+ logger: logger,
170
+ }
171
+ }
172
+
173
+ // CreateUser handles user creation requests
174
+ func (h *UserHandler) CreateUser(c *gin.Context) {
175
+ ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
176
+ defer cancel()
177
+
178
+ var req model.CreateUserRequest
179
+ if err := c.ShouldBindJSON(&req); err != nil {
180
+ h.logger.Error("Invalid request body", "error", err)
181
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
182
+ return
183
+ }
184
+
185
+ user, err := h.userService.CreateUser(ctx, req)
186
+ if err != nil {
187
+ h.logger.Error("Failed to create user", "error", err)
188
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"})
189
+ return
190
+ }
191
+
192
+ c.JSON(http.StatusCreated, user)
193
+ }
194
+
195
+ // GetUser retrieves a user by ID
196
+ func (h *UserHandler) GetUser(c *gin.Context) {
197
+ ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second)
198
+ defer cancel()
199
+
200
+ userID := c.Param("id")
201
+ user, err := h.userService.GetUser(ctx, userID)
202
+ if err != nil {
203
+ if err == service.ErrUserNotFound {
204
+ c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
205
+ return
206
+ }
207
+
208
+ h.logger.Error("Failed to get user", "userID", userID, "error", err)
209
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"})
210
+ return
211
+ }
212
+
213
+ c.JSON(http.StatusOK, user)
214
+ }
215
+ ```
216
+
217
+ ### Service Layer with Error Handling
218
+
219
+ ```go
220
+ // service/user.go
221
+ package service
222
+
223
+ import (
224
+ "context"
225
+ "errors"
226
+ "fmt"
227
+
228
+ "github.com/your-org/your-project/internal/model"
229
+ "github.com/your-org/your-project/internal/repository"
230
+ )
231
+
232
+ var (
233
+ ErrUserNotFound = errors.New("user not found")
234
+ ErrUserExists = errors.New("user already exists")
235
+ ErrInvalidInput = errors.New("invalid input")
236
+ )
237
+
238
+ type UserService interface {
239
+ CreateUser(ctx context.Context, req model.CreateUserRequest) (*model.User, error)
240
+ GetUser(ctx context.Context, id string) (*model.User, error)
241
+ UpdateUser(ctx context.Context, id string, req model.UpdateUserRequest) (*model.User, error)
242
+ DeleteUser(ctx context.Context, id string) error
243
+ ListUsers(ctx context.Context, filter model.UserFilter) ([]*model.User, int, error)
244
+ }
245
+
246
+ type userService struct {
247
+ userRepo repository.UserRepository
248
+ logger Logger
249
+ }
250
+
251
+ func NewUserService(userRepo repository.UserRepository, logger Logger) UserService {
252
+ return &userService{
253
+ userRepo: userRepo,
254
+ logger: logger,
255
+ }
256
+ }
257
+
258
+ func (s *userService) CreateUser(ctx context.Context, req model.CreateUserRequest) (*model.User, error) {
259
+ // Validate input
260
+ if err := req.Validate(); err != nil {
261
+ s.logger.Warn("Invalid user creation request", "error", err)
262
+ return nil, fmt.Errorf("%w: %v", ErrInvalidInput, err)
263
+ }
264
+
265
+ // Check if user already exists
266
+ existing, err := s.userRepo.GetByEmail(ctx, req.Email)
267
+ if err == nil && existing != nil {
268
+ s.logger.Warn("User already exists", "email", req.Email)
269
+ return nil, ErrUserExists
270
+ }
271
+
272
+ // Create user
273
+ user := &model.User{
274
+ ID: generateID(),
275
+ Email: req.Email,
276
+ Name: req.Name,
277
+ CreatedAt: time.Now(),
278
+ UpdatedAt: time.Now(),
279
+ }
280
+
281
+ if err := s.userRepo.Create(ctx, user); err != nil {
282
+ s.logger.Error("Failed to create user", "error", err)
283
+ return nil, fmt.Errorf("failed to create user: %w", err)
284
+ }
285
+
286
+ s.logger.Info("User created successfully", "userID", user.ID)
287
+ return user, nil
288
+ }
289
+
290
+ func (s *userService) GetUser(ctx context.Context, id string) (*model.User, error) {
291
+ user, err := s.userRepo.GetByID(ctx, id)
292
+ if err != nil {
293
+ if errors.Is(err, repository.ErrNotFound) {
294
+ return nil, ErrUserNotFound
295
+ }
296
+ return nil, fmt.Errorf("failed to get user: %w", err)
297
+ }
298
+
299
+ return user, nil
300
+ }
301
+ ```
302
+
303
+ ### Repository Pattern with SQLx
304
+
305
+ ```go
306
+ // repository/user.go
307
+ package repository
308
+
309
+ import (
310
+ "context"
311
+ "database/sql"
312
+ "errors"
313
+ "fmt"
314
+
315
+ "github.com/jmoiron/sqlx"
316
+ _ "github.com/lib/pq" // PostgreSQL driver
317
+ "github.com/your-org/your-project/internal/model"
318
+ )
319
+
320
+ var (
321
+ ErrNotFound = errors.New("record not found")
322
+ ErrDuplicate = errors.New("duplicate record")
323
+ )
324
+
325
+ type UserRepository interface {
326
+ Create(ctx context.Context, user *model.User) error
327
+ GetByID(ctx context.Context, id string) (*model.User, error)
328
+ GetByEmail(ctx context.Context, email string) (*model.User, error)
329
+ Update(ctx context.Context, user *model.User) error
330
+ Delete(ctx context.Context, id string) error
331
+ List(ctx context.Context, filter UserFilter) ([]*model.User, int, error)
332
+ }
333
+
334
+ type userRepository struct {
335
+ db *sqlx.DB
336
+ }
337
+
338
+ func NewUserRepository(db *sqlx.DB) UserRepository {
339
+ return &userRepository{db: db}
340
+ }
341
+
342
+ func (r *userRepository) Create(ctx context.Context, user *model.User) error {
343
+ query := `
344
+ INSERT INTO users (id, email, name, created_at, updated_at)
345
+ VALUES ($1, $2, $3, $4, $5)
346
+ ON CONFLICT (email) DO NOTHING
347
+ `
348
+
349
+ result, err := r.db.ExecContext(ctx, query, user.ID, user.Email, user.Name, user.CreatedAt, user.UpdatedAt)
350
+ if err != nil {
351
+ return fmt.Errorf("failed to insert user: %w", err)
352
+ }
353
+
354
+ rowsAffected, err := result.RowsAffected()
355
+ if err != nil {
356
+ return fmt.Errorf("failed to get rows affected: %w", err)
357
+ }
358
+
359
+ if rowsAffected == 0 {
360
+ return ErrDuplicate
361
+ }
362
+
363
+ return nil
364
+ }
365
+
366
+ func (r *userRepository) GetByID(ctx context.Context, id string) (*model.User, error) {
367
+ query := `
368
+ SELECT id, email, name, created_at, updated_at
369
+ FROM users
370
+ WHERE id = $1
371
+ `
372
+
373
+ var user model.User
374
+ err := r.db.GetContext(ctx, &user, query, id)
375
+ if err != nil {
376
+ if errors.Is(err, sql.ErrNoRows) {
377
+ return nil, ErrNotFound
378
+ }
379
+ return nil, fmt.Errorf("failed to get user by ID: %w", err)
380
+ }
381
+
382
+ return &user, nil
383
+ }
384
+
385
+ func (r *userRepository) List(ctx context.Context, filter UserFilter) ([]*model.User, int, error) {
386
+ // Build dynamic query
387
+ baseQuery := `
388
+ SELECT id, email, name, created_at, updated_at
389
+ FROM users
390
+ WHERE 1=1
391
+ `
392
+
393
+ countQuery := `
394
+ SELECT COUNT(*)
395
+ FROM users
396
+ WHERE 1=1
397
+ `
398
+
399
+ var args []interface{}
400
+ conditions := []string{}
401
+
402
+ if filter.Email != "" {
403
+ conditions = append(conditions, "email = $"+fmt.Sprintf("%d", len(args)+1))
404
+ args = append(args, filter.Email)
405
+ }
406
+
407
+ if len(conditions) > 0 {
408
+ whereClause := " AND " + fmt.Sprintf(" AND ", conditions)
409
+ baseQuery += whereClause
410
+ countQuery += whereClause
411
+ }
412
+
413
+ // Get total count
414
+ var total int
415
+ err := r.db.GetContext(ctx, &total, countQuery, args...)
416
+ if err != nil {
417
+ return nil, 0, fmt.Errorf("failed to count users: %w", err)
418
+ }
419
+
420
+ // Add pagination
421
+ if filter.Limit > 0 {
422
+ baseQuery += fmt.Sprintf(" LIMIT $%d OFFSET $%d", len(args)+1, len(args)+2)
423
+ args = append(args, filter.Limit, filter.Offset)
424
+ }
425
+
426
+ var users []*model.User
427
+ err = r.db.SelectContext(ctx, &users, baseQuery, args...)
428
+ if err != nil {
429
+ return nil, 0, fmt.Errorf("failed to list users: %w", err)
430
+ }
431
+
432
+ return users, total, nil
433
+ }
434
+ ```
435
+
436
+ ## Concurrent Programming
437
+
438
+ ### Worker Pool Pattern
439
+
440
+ ```go
441
+ // pkg/worker/pool.go
442
+ package worker
443
+
444
+ import (
445
+ "context"
446
+ "sync"
447
+ "time"
448
+ )
449
+
450
+ type Task[T any] interface {
451
+ Execute(ctx context.Context) (T, error)
452
+ }
453
+
454
+ type Result[T any] struct {
455
+ Value T
456
+ Error error
457
+ }
458
+
459
+ type WorkerPool[T any] struct {
460
+ workers int
461
+ taskQueue chan Task[T]
462
+ wg sync.WaitGroup
463
+ ctx context.Context
464
+ cancel context.CancelFunc
465
+ }
466
+
467
+ func NewWorkerPool[T any](workers int) *WorkerPool[T] {
468
+ ctx, cancel := context.WithCancel(context.Background())
469
+
470
+ return &WorkerPool[T]{
471
+ workers: workers,
472
+ taskQueue: make(chan Task[T], workers*2),
473
+ ctx: ctx,
474
+ cancel: cancel,
475
+ }
476
+ }
72
477
 
73
- ## Outputs
74
- - Test/lint execution plan tailored to the selected language.
75
- - List of key language idioms and review checkpoints.
478
+ func (p *WorkerPool[T]) Start() {
479
+ for i := 0; i < p.workers; i++ {
480
+ p.wg.Add(1)
481
+ go p.worker(i)
482
+ }
483
+ }
76
484
 
77
- ## Failure Modes
78
- - When the language runtime or package manager is not installed.
79
- - When the main language cannot be determined in a multilingual project.
485
+ func (p *WorkerPool[T]) worker(id int) {
486
+ defer p.wg.Done()
487
+
488
+ for {
489
+ select {
490
+ case task := <-p.taskQueue:
491
+ if task == nil {
492
+ return
493
+ }
494
+
495
+ result, err := task.Execute(p.ctx)
496
+ if err != nil {
497
+ // Handle error (could use error channel or logging)
498
+ continue
499
+ }
500
+
501
+ // Process result
502
+
503
+ case <-p.ctx.Done():
504
+ return
505
+ }
506
+ }
507
+ }
80
508
 
81
- ## Dependencies
82
- - Access to the project file is required using the Read/Grep tool.
83
- - When used with `Skill("moai-foundation-langs")`, it is easy to share cross-language conventions.
509
+ func (p *WorkerPool[T]) Submit(task Task[T]) {
510
+ select {
511
+ case p.taskQueue <- task:
512
+ case <-p.ctx.Done():
513
+ return
514
+ }
515
+ }
84
516
 
85
- ## References
86
- - The Go Authors. "Effective Go." https://go.dev/doc/effective_go (accessed 2025-03-29).
87
- - GolangCI. "golangci-lint Documentation." https://golangci-lint.run/usage/quick-start/ (accessed 2025-03-29).
517
+ func (p *WorkerPool[T]) Stop() {
518
+ close(p.taskQueue)
519
+ p.cancel()
520
+ p.wg.Wait()
521
+ }
522
+
523
+ // Example usage
524
+ type ImageProcessingTask struct {
525
+ ImagePath string
526
+ }
527
+
528
+ func (t *ImageProcessingTask) Execute(ctx context.Context) (string, error) {
529
+ // Simulate image processing
530
+ time.Sleep(100 * time.Millisecond)
531
+ return "processed_" + t.ImagePath, nil
532
+ }
533
+
534
+ func ProcessImages(imagePaths []string) []string {
535
+ pool := NewWorkerPool[string](10)
536
+ pool.Start()
537
+ defer pool.Stop()
538
+
539
+ var results []string
540
+ var mu sync.Mutex
541
+
542
+ for _, path := range imagePaths {
543
+ task := &ImageProcessingTask{ImagePath: path}
544
+
545
+ go func(t *ImageProcessingTask) {
546
+ result, err := t.Execute(context.Background())
547
+ if err == nil {
548
+ mu.Lock()
549
+ results = append(results, result)
550
+ mu.Unlock()
551
+ }
552
+ }(task)
553
+ }
554
+
555
+ return results
556
+ }
557
+ ```
558
+
559
+ ### Fan-In/Fan-Out Pattern
560
+
561
+ ```go
562
+ // pkg/concurrent/fan.go
563
+ package concurrent
564
+
565
+ import (
566
+ "context"
567
+ "sync"
568
+ )
569
+
570
+ // FanIn merges multiple input channels into a single output channel
571
+ func FanIn[T any](ctx context.Context, channels ...<-chan T) <-chan T {
572
+ var wg sync.WaitGroup
573
+ out := make(chan T)
574
+
575
+ output := func(c <-chan T) {
576
+ defer wg.Done()
577
+ for {
578
+ select {
579
+ case v, ok := <-c:
580
+ if !ok {
581
+ return
582
+ }
583
+ select {
584
+ case out <- v:
585
+ case <-ctx.Done():
586
+ return
587
+ }
588
+ case <-ctx.Done():
589
+ return
590
+ }
591
+ }
592
+ }
593
+
594
+ wg.Add(len(channels))
595
+ for _, c := range channels {
596
+ go output(c)
597
+ }
598
+
599
+ go func() {
600
+ wg.Wait()
601
+ close(out)
602
+ }()
603
+
604
+ return out
605
+ }
606
+
607
+ // FanOut distributes input across multiple output channels
608
+ func FanOut[T any](ctx context.Context, in <-chan T, n int) []<-chan T {
609
+ outs := make([]chan T, n)
610
+ for i := 0; i < n; i++ {
611
+ outs[i] = make(chan T)
612
+ }
613
+
614
+ distribute := func() {
615
+ defer func() {
616
+ for _, out := range outs {
617
+ close(out)
618
+ }
619
+ }()
620
+
621
+ for {
622
+ select {
623
+ case v, ok := <-in:
624
+ if !ok {
625
+ return
626
+ }
627
+
628
+ for _, out := range outs {
629
+ select {
630
+ case out <- v:
631
+ case <-ctx.Done():
632
+ return
633
+ }
634
+ }
635
+
636
+ case <-ctx.Done():
637
+ return
638
+ }
639
+ }
640
+ }
641
+
642
+ go distribute()
643
+ return outs
644
+ }
645
+
646
+ // Pipeline combines fan-out and fan-in for parallel processing
647
+ func Pipeline[T, R any](
648
+ ctx context.Context,
649
+ input []T,
650
+ workers int,
651
+ process func(context.Context, T) (R, error),
652
+ ) (<-chan R, <-chan error) {
653
+ out := make(chan R, workers)
654
+ errChan := make(chan error, workers)
655
+
656
+ // Create input channel
657
+ in := make(chan T, len(input))
658
+ for _, item := range input {
659
+ in <- item
660
+ }
661
+ close(in)
662
+
663
+ // Fan out to workers
664
+ channels := FanOut(ctx, in, workers)
665
+
666
+ // Process each item
667
+ var wg sync.WaitGroup
668
+ for _, ch := range channels {
669
+ wg.Add(1)
670
+ go func(c <-chan T) {
671
+ defer wg.Done()
672
+ for item := range c {
673
+ result, err := process(ctx, item)
674
+ if err != nil {
675
+ select {
676
+ case errChan <- err:
677
+ case <-ctx.Done():
678
+ return
679
+ }
680
+ continue
681
+ }
682
+
683
+ select {
684
+ case out <- result:
685
+ case <-ctx.Done():
686
+ return
687
+ }
688
+ }
689
+ }(ch)
690
+ }
691
+
692
+ go func() {
693
+ wg.Wait()
694
+ close(out)
695
+ close(errChan)
696
+ }()
697
+
698
+ return out, errChan
699
+ }
700
+ ```
701
+
702
+ ## Performance Optimization
703
+
704
+ ### Memory Pooling
705
+
706
+ ```go
707
+ // pkg/pool/buffer.go
708
+ package pool
709
+
710
+ import (
711
+ "sync"
712
+ )
713
+
714
+ var (
715
+ bufferPool = sync.Pool{
716
+ New: func() interface{} {
717
+ return make([]byte, 0, 1024) // Pre-allocate 1KB
718
+ },
719
+ }
720
+ )
721
+
722
+ // GetBuffer returns a buffer from the pool
723
+ func GetBuffer() []byte {
724
+ return bufferPool.Get().([]byte)
725
+ }
726
+
727
+ // PutBuffer returns a buffer to the pool
728
+ func PutBuffer(buf []byte) {
729
+ if cap(buf) <= 64*1024 { // Don't pool large buffers
730
+ bufferPool.Put(buf[:0]) // Reset length but keep capacity
731
+ }
732
+ }
733
+
734
+ // Usage example
735
+ func ProcessData(data []byte) ([]byte, error) {
736
+ buf := GetBuffer()
737
+ defer PutBuffer(buf)
738
+
739
+ // Process data using the pooled buffer
740
+ buf = append(buf, data...)
741
+ // ... processing logic ...
742
+
743
+ result := make([]byte, len(buf))
744
+ copy(result, buf)
745
+
746
+ return result, nil
747
+ }
748
+ ```
749
+
750
+ ### String Building Optimization
751
+
752
+ ```go
753
+ // pkg/utils/strings.go
754
+ package utils
755
+
756
+ import (
757
+ "strings"
758
+ "sync"
759
+ )
760
+
761
+ var stringBuilderPool = sync.Pool{
762
+ New: func() interface{} {
763
+ return &strings.Builder{}
764
+ },
765
+ }
766
+
767
+ // StringBuilderPool provides a thread-safe string builder pool
768
+ func GetStringBuilder() *strings.Builder {
769
+ sb := stringBuilderPool.Get().(*strings.Builder)
770
+ sb.Reset()
771
+ return sb
772
+ }
773
+
774
+ func PutStringBuilder(sb *strings.Builder) {
775
+ if sb.Cap() <= 4096 { // Don't pool large builders
776
+ stringBuilderPool.Put(sb)
777
+ }
778
+ }
779
+
780
+ // FastJoin efficiently joins strings using a pooled builder
781
+ func FastJoin(strs ...string) string {
782
+ if len(strs) == 0 {
783
+ return ""
784
+ }
785
+ if len(strs) == 1 {
786
+ return strs[0]
787
+ }
788
+
789
+ sb := GetStringBuilder()
790
+ defer PutStringBuilder(sb)
791
+
792
+ for _, s := range strs {
793
+ sb.WriteString(s)
794
+ }
795
+
796
+ return sb.String()
797
+ }
798
+
799
+ // Usage example
800
+ func BuildMessage(parts []string) string {
801
+ sb := GetStringBuilder()
802
+ defer PutStringBuilder(sb)
803
+
804
+ for i, part := range parts {
805
+ if i > 0 {
806
+ sb.WriteString(" ")
807
+ }
808
+ sb.WriteString(part)
809
+ }
810
+
811
+ return sb.String()
812
+ }
813
+ ```
814
+
815
+ ## Testing Strategies
816
+
817
+ ### Comprehensive Unit Testing
818
+
819
+ ```go
820
+ // service/user_test.go
821
+ package service
822
+
823
+ import (
824
+ "context"
825
+ "errors"
826
+ "testing"
827
+ "time"
828
+
829
+ "github.com/stretchr/testify/assert"
830
+ "github.com/stretchr/testify/mock"
831
+ "github.com/stretchr/testify/require"
832
+ "github.com/your-org/your-project/internal/model"
833
+ "github.com/your-org/your-project/internal/repository"
834
+ )
835
+
836
+ // MockUserRepository is a mock implementation of UserRepository
837
+ type MockUserRepository struct {
838
+ mock.Mock
839
+ }
840
+
841
+ func (m *MockUserRepository) Create(ctx context.Context, user *model.User) error {
842
+ args := m.Called(ctx, user)
843
+ return args.Error(0)
844
+ }
845
+
846
+ func (m *MockUserRepository) GetByID(ctx context.Context, id string) (*model.User, error) {
847
+ args := m.Called(ctx, id)
848
+ if args.Get(0) == nil {
849
+ return nil, args.Error(1)
850
+ }
851
+ return args.Get(0).(*model.User), args.Error(1)
852
+ }
853
+
854
+ func (m *MockUserRepository) GetByEmail(ctx context.Context, email string) (*model.User, error) {
855
+ args := m.Called(ctx, email)
856
+ if args.Get(0) == nil {
857
+ return nil, args.Error(1)
858
+ }
859
+ return args.Get(0).(*model.User), args.Error(1)
860
+ }
861
+
862
+ func TestUserService_CreateUser_Success(t *testing.T) {
863
+ // Arrange
864
+ mockRepo := new(MockUserRepository)
865
+ mockLogger := &MockLogger{} // Assume you have this
866
+ service := NewUserService(mockRepo, mockLogger)
867
+
868
+ req := model.CreateUserRequest{
869
+ Email: "test@example.com",
870
+ Name: "Test User",
871
+ }
872
+
873
+ expectedUser := &model.User{
874
+ ID: "user-123",
875
+ Email: req.Email,
876
+ Name: req.Name,
877
+ }
878
+
879
+ mockRepo.On("GetByEmail", mock.Anything, req.Email).Return(nil, repository.ErrNotFound)
880
+ mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*model.User")).Return(nil)
881
+
882
+ // Act
883
+ ctx := context.Background()
884
+ user, err := service.CreateUser(ctx, req)
885
+
886
+ // Assert
887
+ require.NoError(t, err)
888
+ assert.NotNil(t, user)
889
+ assert.Equal(t, req.Email, user.Email)
890
+ assert.Equal(t, req.Name, user.Name)
891
+ mockRepo.AssertExpectations(t)
892
+ }
893
+
894
+ func TestUserService_CreateUser_EmailExists(t *testing.T) {
895
+ // Arrange
896
+ mockRepo := new(MockUserRepository)
897
+ mockLogger := &MockLogger{}
898
+ service := NewUserService(mockRepo, mockLogger)
899
+
900
+ req := model.CreateUserRequest{
901
+ Email: "existing@example.com",
902
+ Name: "Test User",
903
+ }
904
+
905
+ existingUser := &model.User{
906
+ ID: "existing-123",
907
+ Email: req.Email,
908
+ }
909
+
910
+ mockRepo.On("GetByEmail", mock.Anything, req.Email).Return(existingUser, nil)
911
+
912
+ // Act
913
+ ctx := context.Background()
914
+ user, err := service.CreateUser(ctx, req)
915
+
916
+ // Assert
917
+ require.Error(t, err)
918
+ assert.Nil(t, user)
919
+ assert.Equal(t, ErrUserExists, err)
920
+ mockRepo.AssertExpectations(t)
921
+ }
922
+
923
+ func TestUserService_GetUser_NotFound(t *testing.T) {
924
+ // Arrange
925
+ mockRepo := new(MockUserRepository)
926
+ mockLogger := &MockLogger{}
927
+ service := NewUserService(mockRepo, mockLogger)
928
+
929
+ userID := "nonexistent"
930
+ mockRepo.On("GetByID", mock.Anything, userID).Return(nil, repository.ErrNotFound)
931
+
932
+ // Act
933
+ ctx := context.Background()
934
+ user, err := service.GetUser(ctx, userID)
935
+
936
+ // Assert
937
+ require.Error(t, err)
938
+ assert.Nil(t, user)
939
+ assert.Equal(t, ErrUserNotFound, err)
940
+ mockRepo.AssertExpectations(t)
941
+ }
942
+
943
+ // Benchmark example
944
+ func BenchmarkUserService_CreateUser(b *testing.B) {
945
+ mockRepo := new(MockUserRepository)
946
+ mockLogger := &MockLogger{}
947
+ service := NewUserService(mockRepo, mockLogger)
948
+
949
+ req := model.CreateUserRequest{
950
+ Email: "test@example.com",
951
+ Name: "Test User",
952
+ }
953
+
954
+ mockRepo.On("GetByEmail", mock.Anything, req.Email).Return(nil, repository.ErrNotFound)
955
+ mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*model.User")).Return(nil)
956
+
957
+ ctx := context.Background()
958
+
959
+ b.ResetTimer()
960
+ for i := 0; i < b.N; i++ {
961
+ _, err := service.CreateUser(ctx, req)
962
+ if err != nil {
963
+ b.Fatal(err)
964
+ }
965
+ }
966
+ }
967
+ ```
968
+
969
+ ### Integration Testing with Testcontainers
970
+
971
+ ```go
972
+ // test/integration/user_test.go
973
+ package integration
974
+
975
+ import (
976
+ "context"
977
+ "fmt"
978
+ "testing"
979
+ "time"
980
+
981
+ "github.com/stretchr/testify/assert"
982
+ "github.com/stretchr/testify/require"
983
+ "github.com/testcontainers/testcontainers-go"
984
+ "github.com/testcontainers/testcontainers-go/wait"
985
+
986
+ "github.com/your-org/your-project/internal/model"
987
+ "github.com/your-org/your-project/internal/repository"
988
+ "github.com/your-org/your-project/internal/service"
989
+ "github.com/your-org/your-project/pkg/config"
990
+ )
991
+
992
+ func TestUserService_Integration(t *testing.T) {
993
+ // Setup test database container
994
+ ctx := context.Background()
995
+
996
+ req := testcontainers.ContainerRequest{
997
+ Image: "postgres:16",
998
+ ExposedPorts: []string{"5432/tcp"},
999
+ Env: map[string]string{
1000
+ "POSTGRES_DB": "testdb",
1001
+ "POSTGRES_USER": "test",
1002
+ "POSTGRES_PASSWORD": "test",
1003
+ },
1004
+ WaitingFor: wait.ForLog("database system is ready to accept connections"),
1005
+ }
1006
+
1007
+ container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
1008
+ ContainerRequest: req,
1009
+ Started: true,
1010
+ })
1011
+ require.NoError(t, err)
1012
+ defer container.Terminate(ctx)
1013
+
1014
+ // Get database connection info
1015
+ host, err := container.Host(ctx)
1016
+ require.NoError(t, err)
1017
+
1018
+ port, err := container.MappedPort(ctx, "5432")
1019
+ require.NoError(t, err)
1020
+
1021
+ // Connect to database
1022
+ dbConfig := config.Database{
1023
+ Host: host,
1024
+ Port: port.Int(),
1025
+ User: "test",
1026
+ Password: "test",
1027
+ DBName: "testdb",
1028
+ SSLMode: "disable",
1029
+ }
1030
+
1031
+ db, err := setupTestDB(dbConfig)
1032
+ require.NoError(t, err)
1033
+ defer db.Close()
1034
+
1035
+ // Run migrations
1036
+ err = runMigrations(db)
1037
+ require.NoError(t, err)
1038
+
1039
+ // Setup service
1040
+ userRepo := repository.NewUserRepository(db)
1041
+ userService := service.NewUserService(userRepo, &MockLogger{})
1042
+
1043
+ // Test user creation
1044
+ t.Run("Create and Get User", func(t *testing.T) {
1045
+ req := model.CreateUserRequest{
1046
+ Email: "integration@example.com",
1047
+ Name: "Integration Test User",
1048
+ }
1049
+
1050
+ // Create user
1051
+ user, err := userService.CreateUser(ctx, req)
1052
+ require.NoError(t, err)
1053
+ assert.NotEmpty(t, user.ID)
1054
+ assert.Equal(t, req.Email, user.Email)
1055
+ assert.Equal(t, req.Name, user.Name)
1056
+ assert.False(t, user.CreatedAt.IsZero())
1057
+
1058
+ // Get user
1059
+ retrievedUser, err := userService.GetUser(ctx, user.ID)
1060
+ require.NoError(t, err)
1061
+ assert.Equal(t, user.ID, retrievedUser.ID)
1062
+ assert.Equal(t, user.Email, retrievedUser.Email)
1063
+ assert.Equal(t, user.Name, retrievedUser.Name)
1064
+ })
1065
+
1066
+ t.Run("List Users", func(t *testing.T) {
1067
+ // Create multiple users
1068
+ for i := 0; i < 5; i++ {
1069
+ req := model.CreateUserRequest{
1070
+ Email: fmt.Sprintf("user%d@example.com", i),
1071
+ Name: fmt.Sprintf("User %d", i),
1072
+ }
1073
+ _, err := userService.CreateUser(ctx, req)
1074
+ require.NoError(t, err)
1075
+ }
1076
+
1077
+ // List users
1078
+ users, total, err := userService.ListUsers(ctx, model.UserFilter{
1079
+ Limit: 10,
1080
+ Offset: 0,
1081
+ })
1082
+
1083
+ require.NoError(t, err)
1084
+ assert.Equal(t, 6, total) // 5 new users + 1 from previous test
1085
+ assert.Equal(t, 6, len(users))
1086
+ })
1087
+ }
1088
+
1089
+ // Helper functions
1090
+ func setupTestDB(cfg config.Database) (*sqlx.DB, error) {
1091
+ dsn := fmt.Sprintf(
1092
+ "host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
1093
+ cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.DBName, cfg.SSLMode,
1094
+ )
1095
+
1096
+ db, err := sqlx.Connect(context.Background(), "postgres", dsn)
1097
+ if err != nil {
1098
+ return nil, err
1099
+ }
1100
+
1101
+ // Wait for database to be ready
1102
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1103
+ defer cancel()
1104
+
1105
+ for {
1106
+ err := db.PingContext(ctx)
1107
+ if err == nil {
1108
+ break
1109
+ }
1110
+
1111
+ select {
1112
+ case <-time.After(1 * time.Second):
1113
+ continue
1114
+ case <-ctx.Done():
1115
+ return nil, ctx.Err()
1116
+ }
1117
+ }
1118
+
1119
+ return db, nil
1120
+ }
1121
+ ```
88
1122
 
89
- ## Changelog
90
- - 2025-03-29: Input/output/failure response/reference information for each language has been specified.
1123
+ ## Security Best Practices
91
1124
 
92
- ## Works well with
1125
+ ### Input Validation and Sanitization
1126
+
1127
+ ```go
1128
+ // pkg/validation/validator.go
1129
+ package validation
1130
+
1131
+ import (
1132
+ "regexp"
1133
+ "strings"
1134
+ "unicode"
1135
+
1136
+ "github.com/go-playground/validator/v10"
1137
+ )
1138
+
1139
+ var (
1140
+ validate = validator.New()
1141
+
1142
+ // Email regex pattern
1143
+ emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
1144
+
1145
+ // Strong password regex
1146
+ passwordRegex = regexp.MustCompile(`^.{8,}$`) // At least 8 characters
1147
+ )
1148
+
1149
+ // ValidationResult represents validation result
1150
+ type ValidationResult struct {
1151
+ Valid bool
1152
+ Errors map[string]string
1153
+ }
1154
+
1155
+ // New creates a new validator
1156
+ func New() *Validator {
1157
+ return &Validator{}
1158
+ }
1159
+
1160
+ // Validator handles input validation
1161
+ type Validator struct{}
1162
+
1163
+ // ValidateStruct validates a struct using validator tags
1164
+ func (v *Validator) ValidateStruct(s interface{}) ValidationResult {
1165
+ err := validate.Struct(s)
1166
+ if err == nil {
1167
+ return ValidationResult{Valid: true}
1168
+ }
1169
+
1170
+ errors := make(map[string]string)
1171
+ for _, err := range err.(validator.ValidationErrors) {
1172
+ field := err.Field()
1173
+ switch err.Tag() {
1174
+ case "required":
1175
+ errors[field] = field + " is required"
1176
+ case "email":
1177
+ errors[field] = field + " must be a valid email address"
1178
+ case "min":
1179
+ errors[field] = field + " must be at least " + err.Param() + " characters"
1180
+ case "max":
1181
+ errors[field] = field + " must be at most " + err.Param() + " characters"
1182
+ default:
1183
+ errors[field] = field + " is invalid"
1184
+ }
1185
+ }
1186
+
1187
+ return ValidationResult{Valid: false, Errors: errors}
1188
+ }
1189
+
1190
+ // ValidateEmail validates email format
1191
+ func (v *Validator) ValidateEmail(email string) bool {
1192
+ email = strings.TrimSpace(strings.ToLower(email))
1193
+ return emailRegex.MatchString(email) && len(email) <= 254
1194
+ }
1195
+
1196
+ // ValidatePassword validates password strength
1197
+ func (v *Validator) ValidatePassword(password string) ValidationResult {
1198
+ errors := make(map[string]string)
1199
+
1200
+ if len(password) < 8 {
1201
+ errors["length"] = "Password must be at least 8 characters long"
1202
+ }
1203
+
1204
+ if !containsUppercase(password) {
1205
+ errors["uppercase"] = "Password must contain at least one uppercase letter"
1206
+ }
1207
+
1208
+ if !containsLowercase(password) {
1209
+ errors["lowercase"] = "Password must contain at least one lowercase letter"
1210
+ }
1211
+
1212
+ if !containsDigit(password) {
1213
+ errors["digit"] = "Password must contain at least one digit"
1214
+ }
1215
+
1216
+ if !containsSpecialChar(password) {
1217
+ errors["special"] = "Password must contain at least one special character"
1218
+ }
1219
+
1220
+ return ValidationResult{
1221
+ Valid: len(errors) == 0,
1222
+ Errors: errors,
1223
+ }
1224
+ }
1225
+
1226
+ // SanitizeInput sanitizes user input
1227
+ func (v *Validator) SanitizeInput(input string) string {
1228
+ // Remove potentially dangerous characters
1229
+ sanitized := strings.ReplaceAll(input, "<", "&lt;")
1230
+ sanitized = strings.ReplaceAll(sanitized, ">", "&gt;")
1231
+ sanitized = strings.ReplaceAll(sanitized, "&", "&amp;")
1232
+ sanitized = strings.ReplaceAll(sanitized, "\"", "&quot;")
1233
+ sanitized = strings.ReplaceAll(sanitized, "'", "&#x27;")
1234
+
1235
+ // Trim whitespace
1236
+ return strings.TrimSpace(sanitized)
1237
+ }
1238
+
1239
+ // Helper functions
1240
+ func containsUppercase(s string) bool {
1241
+ for _, r := range s {
1242
+ if unicode.IsUpper(r) {
1243
+ return true
1244
+ }
1245
+ }
1246
+ return false
1247
+ }
1248
+
1249
+ func containsLowercase(s string) bool {
1250
+ for _, r := range s {
1251
+ if unicode.IsLower(r) {
1252
+ return true
1253
+ }
1254
+ }
1255
+ return false
1256
+ }
1257
+
1258
+ func containsDigit(s string) bool {
1259
+ for _, r := range s {
1260
+ if unicode.IsDigit(r) {
1261
+ return true
1262
+ }
1263
+ }
1264
+ return false
1265
+ }
1266
+
1267
+ func containsSpecialChar(s string) bool {
1268
+ for _, r := range s {
1269
+ if !unicode.IsLetter(r) && !unicode.IsDigit(r) {
1270
+ return true
1271
+ }
1272
+ }
1273
+ return false
1274
+ }
1275
+ ```
1276
+
1277
+ ### Authentication and Authorization
1278
+
1279
+ ```go
1280
+ // pkg/auth/jwt.go
1281
+ package auth
1282
+
1283
+ import (
1284
+ "fmt"
1285
+ "time"
1286
+
1287
+ "github.com/golang-jwt/jwt/v5"
1288
+ )
1289
+
1290
+ // Claims represents JWT claims
1291
+ type Claims struct {
1292
+ UserID string `json:"user_id"`
1293
+ Email string `json:"email"`
1294
+ Role string `json:"role"`
1295
+ jwt.RegisteredClaims
1296
+ }
1297
+
1298
+ // JWTManager handles JWT token operations
1299
+ type JWTManager struct {
1300
+ secretKey []byte
1301
+ expiration time.Duration
1302
+ }
1303
+
1304
+ // NewJWTManager creates a new JWT manager
1305
+ func NewJWTManager(secretKey string, expiration time.Duration) *JWTManager {
1306
+ return &JWTManager{
1307
+ secretKey: []byte(secretKey),
1308
+ expiration: expiration,
1309
+ }
1310
+ }
1311
+
1312
+ // GenerateToken generates a new JWT token
1313
+ func (m *JWTManager) GenerateToken(userID, email, role string) (string, error) {
1314
+ claims := &Claims{
1315
+ UserID: userID,
1316
+ Email: email,
1317
+ Role: role,
1318
+ RegisteredClaims: jwt.RegisteredClaims{
1319
+ ExpiresAt: jwt.NewNumericDate(time.Now().Add(m.expiration)),
1320
+ IssuedAt: jwt.NewNumericDate(time.Now()),
1321
+ NotBefore: jwt.NewNumericDate(time.Now()),
1322
+ Issuer: "your-app",
1323
+ Subject: userID,
1324
+ },
1325
+ }
1326
+
1327
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
1328
+ return token.SignedString(m.secretKey)
1329
+ }
1330
+
1331
+ // ValidateToken validates and parses a JWT token
1332
+ func (m *JWTManager) ValidateToken(tokenString string) (*Claims, error) {
1333
+ token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
1334
+ if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
1335
+ return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
1336
+ }
1337
+ return m.secretKey, nil
1338
+ })
1339
+
1340
+ if err != nil {
1341
+ return nil, err
1342
+ }
1343
+
1344
+ claims, ok := token.Claims.(*Claims)
1345
+ if !ok || !token.Valid {
1346
+ return nil, fmt.Errorf("invalid token")
1347
+ }
1348
+
1349
+ return claims, nil
1350
+ }
1351
+
1352
+ // RefreshToken generates a new token with extended expiration
1353
+ func (m *JWTManager) RefreshToken(claims *Claims) (string, error) {
1354
+ claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(m.expiration))
1355
+ claims.IssuedAt = jwt.NewNumericDate(time.Now())
1356
+
1357
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
1358
+ return token.SignedString(m.secretKey)
1359
+ }
1360
+
1361
+ // Middleware for authentication
1362
+ func (m *JWTManager) AuthMiddleware(next http.Handler) http.Handler {
1363
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1364
+ authHeader := r.Header.Get("Authorization")
1365
+ if authHeader == "" {
1366
+ http.Error(w, "Authorization header required", http.StatusUnauthorized)
1367
+ return
1368
+ }
1369
+
1370
+ tokenString := strings.Replace(authHeader, "Bearer ", "", 1)
1371
+ claims, err := m.ValidateToken(tokenString)
1372
+ if err != nil {
1373
+ http.Error(w, "Invalid token", http.StatusUnauthorized)
1374
+ return
1375
+ }
1376
+
1377
+ // Add claims to context
1378
+ ctx := context.WithValue(r.Context(), "user_claims", claims)
1379
+ next.ServeHTTP(w, r.WithContext(ctx))
1380
+ })
1381
+ }
1382
+
1383
+ // Role-based authorization middleware
1384
+ func (m *JWTManager) RequireRole(requiredRole string) func(http.Handler) http.Handler {
1385
+ return func(next http.Handler) http.Handler {
1386
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1387
+ claims, ok := r.Context().Value("user_claims").(*Claims)
1388
+ if !ok {
1389
+ http.Error(w, "User claims not found", http.StatusUnauthorized)
1390
+ return
1391
+ }
1392
+
1393
+ if claims.Role != requiredRole {
1394
+ http.Error(w, "Insufficient permissions", http.StatusForbidden)
1395
+ return
1396
+ }
1397
+
1398
+ next.ServeHTTP(w, r)
1399
+ })
1400
+ }
1401
+ }
1402
+ ```
1403
+
1404
+ ## Integration Patterns
1405
+
1406
+ ### gRPC Service Implementation
1407
+
1408
+ ```go
1409
+ // api/proto/user.proto
1410
+ syntax = "proto3";
1411
+
1412
+ package user.v1;
1413
+
1414
+ option go_package = "github.com/your-org/your-project/api/user/v1;userv1";
1415
+
1416
+ service UserService {
1417
+ rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
1418
+ rpc GetUser(GetUserRequest) returns (GetUserResponse);
1419
+ rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
1420
+ rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);
1421
+ rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
1422
+ }
1423
+
1424
+ message User {
1425
+ string id = 1;
1426
+ string email = 2;
1427
+ string name = 3;
1428
+ google.protobuf.Timestamp created_at = 4;
1429
+ google.protobuf.Timestamp updated_at = 5;
1430
+ }
1431
+
1432
+ message CreateUserRequest {
1433
+ string email = 1;
1434
+ string name = 2;
1435
+ }
1436
+
1437
+ message CreateUserResponse {
1438
+ User user = 1;
1439
+ }
1440
+
1441
+ // server/grpc/user_service.go
1442
+ package grpc
1443
+
1444
+ import (
1445
+ "context"
1446
+
1447
+ "google.golang.org/grpc/codes"
1448
+ "google.golang.org/grpc/status"
1449
+ "google.golang.org/protobuf/types/known/timestamppb"
1450
+
1451
+ "github.com/your-org/your-project/api/user/v1"
1452
+ "github.com/your-org/your-project/internal/service"
1453
+ )
1454
+
1455
+ type GRPCUserServer struct {
1456
+ userv1.UnimplementedUserServiceServer
1457
+ userService service.UserService
1458
+ }
1459
+
1460
+ func NewGRPCUserServer(userService service.UserService) *GRPCUserServer {
1461
+ return &GRPCUserServer{
1462
+ userService: userService,
1463
+ }
1464
+ }
1465
+
1466
+ func (s *GRPCUserServer) CreateUser(ctx context.Context, req *userv1.CreateUserRequest) (*userv1.CreateUserResponse, error) {
1467
+ // Convert protobuf to domain model
1468
+ createReq := model.CreateUserRequest{
1469
+ Email: req.GetEmail(),
1470
+ Name: req.GetName(),
1471
+ }
1472
+
1473
+ // Call service layer
1474
+ user, err := s.userService.CreateUser(ctx, createReq)
1475
+ if err != nil {
1476
+ if errors.Is(err, service.ErrUserExists) {
1477
+ return nil, status.Error(codes.AlreadyExists, "user already exists")
1478
+ }
1479
+ if errors.Is(err, service.ErrInvalidInput) {
1480
+ return nil, status.Error(codes.InvalidArgument, err.Error())
1481
+ }
1482
+ return nil, status.Error(codes.Internal, "internal server error")
1483
+ }
1484
+
1485
+ // Convert domain model to protobuf
1486
+ return &userv1.CreateUserResponse{
1487
+ User: s.userToProto(user),
1488
+ }, nil
1489
+ }
1490
+
1491
+ func (s *GRPCUserServer) GetUser(ctx context.Context, req *userv1.GetUserRequest) (*userv1.GetUserResponse, error) {
1492
+ user, err := s.userService.GetUser(ctx, req.GetId())
1493
+ if err != nil {
1494
+ if errors.Is(err, service.ErrUserNotFound) {
1495
+ return nil, status.Error(codes.NotFound, "user not found")
1496
+ }
1497
+ return nil, status.Error(codes.Internal, "internal server error")
1498
+ }
1499
+
1500
+ return &userv1.GetUserResponse{
1501
+ User: s.userToProto(user),
1502
+ }, nil
1503
+ }
1504
+
1505
+ func (s *GRPCUserServer) userToProto(user *model.User) *userv1.User {
1506
+ return &userv1.User{
1507
+ Id: user.ID,
1508
+ Email: user.Email,
1509
+ Name: user.Name,
1510
+ CreatedAt: timestamppb.New(user.CreatedAt),
1511
+ UpdatedAt: timestamppb.New(user.UpdatedAt),
1512
+ }
1513
+ }
1514
+ ```
1515
+
1516
+ ### Message Queue Integration
1517
+
1518
+ ```go
1519
+ // pkg/messaging/nats.go
1520
+ package messaging
1521
+
1522
+ import (
1523
+ "context"
1524
+ "encoding/json"
1525
+ "fmt"
1526
+ "time"
1527
+
1528
+ "github.com/nats-io/nats.go"
1529
+ )
1530
+
1531
+ // Message represents a message payload
1532
+ type Message struct {
1533
+ ID string `json:"id"`
1534
+ Type string `json:"type"`
1535
+ Data map[string]interface{} `json:"data"`
1536
+ Timestamp time.Time `json:"timestamp"`
1537
+ }
1538
+
1539
+ // MessageHandler handles incoming messages
1540
+ type MessageHandler func(ctx context.Context, msg *Message) error
1541
+
1542
+ // MessageBroker defines message broker interface
1543
+ type MessageBroker interface {
1544
+ Publish(ctx context.Context, subject string, msg *Message) error
1545
+ Subscribe(ctx context.Context, subject string, handler MessageHandler) error
1546
+ Close() error
1547
+ }
1548
+
1549
+ // NATSMessageBroker implements MessageBroker using NATS
1550
+ type NATSMessageBroker struct {
1551
+ conn *nats.Conn
1552
+ js nats.JetStreamContext
1553
+ }
1554
+
1555
+ func NewNATSMessageBroker(url string) (*NATSMessageBroker, error) {
1556
+ conn, err := nats.Connect(url,
1557
+ nats.ReconnectWait(2*time.Second),
1558
+ nats.MaxReconnects(5),
1559
+ nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
1560
+ fmt.Printf("NATS disconnected: %v\n", err)
1561
+ }),
1562
+ nats.ReconnectHandler(func(nc *nats.Conn) {
1563
+ fmt.Printf("NATS reconnected to %v\n", nc.ConnectedUrl())
1564
+ }),
1565
+ )
1566
+ if err != nil {
1567
+ return nil, fmt.Errorf("failed to connect to NATS: %w", err)
1568
+ }
1569
+
1570
+ js, err := conn.JetStream()
1571
+ if err != nil {
1572
+ return nil, fmt.Errorf("failed to get JetStream context: %w", err)
1573
+ }
1574
+
1575
+ return &NATSMessageBroker{
1576
+ conn: conn,
1577
+ js: js,
1578
+ }, nil
1579
+ }
1580
+
1581
+ func (b *NATSMessageBroker) Publish(ctx context.Context, subject string, msg *Message) error {
1582
+ data, err := json.Marshal(msg)
1583
+ if err != nil {
1584
+ return fmt.Errorf("failed to marshal message: %w", err)
1585
+ }
1586
+
1587
+ // Use JetStream for persistent messaging
1588
+ _, err = b.js.Publish(ctx, subject, data)
1589
+ if err != nil {
1590
+ return fmt.Errorf("failed to publish message: %w", err)
1591
+ }
1592
+
1593
+ return nil
1594
+ }
1595
+
1596
+ func (b *NATSMessageBroker) Subscribe(ctx context.Context, subject string, handler MessageHandler) error {
1597
+ // Create stream if it doesn't exist
1598
+ streamConfig := &nats.StreamConfig{
1599
+ Name: "events",
1600
+ Subjects: []string{subject},
1601
+ Retention: nats.WorkQueuePolicy,
1602
+ MaxBytes: 1024 * 1024 * 1024, // 1GB
1603
+ Storage: nats.FileStorage,
1604
+ Replicas: 1,
1605
+ }
1606
+
1607
+ _, err := b.js.AddStream(streamConfig)
1608
+ if err != nil && !errors.Is(err, nats.ErrStreamNameAlreadyInUse) {
1609
+ return fmt.Errorf("failed to create stream: %w", err)
1610
+ }
1611
+
1612
+ // Create consumer
1613
+ consumerConfig := &nats.ConsumerConfig{
1614
+ Durable: "worker",
1615
+ AckPolicy: nats.AckExplicitPolicy,
1616
+ }
1617
+
1618
+ _, err = b.js.AddConsumer("events", consumerConfig)
1619
+ if err != nil && !errors.Is(err, nats.ErrConsumerAlreadyExists) {
1620
+ return fmt.Errorf("failed to create consumer: %w", err)
1621
+ }
1622
+
1623
+ // Subscribe to messages
1624
+ _, err = b.js.Subscribe(subject, func(msg *nats.Msg) {
1625
+ var message Message
1626
+ if err := json.Unmarshal(msg.Data, &message); err != nil {
1627
+ fmt.Printf("Failed to unmarshal message: %v\n", err)
1628
+ msg.Nak()
1629
+ return
1630
+ }
1631
+
1632
+ if err := handler(ctx, &message); err != nil {
1633
+ fmt.Printf("Handler failed: %v\n", err)
1634
+ msg.Nak()
1635
+ return
1636
+ }
1637
+
1638
+ msg.Ack()
1639
+ }, nats.Durable("worker"))
1640
+
1641
+ if err != nil {
1642
+ return fmt.Errorf("failed to subscribe: %w", err)
1643
+ }
1644
+
1645
+ return nil
1646
+ }
1647
+
1648
+ func (b *NATSMessageBroker) Close() error {
1649
+ b.conn.Close()
1650
+ return nil
1651
+ }
1652
+
1653
+ // Usage example
1654
+ func setupEventHandlers(broker MessageBroker) {
1655
+ // User created event handler
1656
+ broker.Subscribe(context.Background(), "user.created", func(ctx context.Context, msg *Message) error {
1657
+ fmt.Printf("User created: %v\n", msg)
1658
+ // Send welcome email, update analytics, etc.
1659
+ return nil
1660
+ })
1661
+
1662
+ // User updated event handler
1663
+ broker.Subscribe(context.Background(), "user.updated", func(ctx context.Context, msg *Message) error {
1664
+ fmt.Printf("User updated: %v\n", msg)
1665
+ // Update search index, notify other services, etc.
1666
+ return nil
1667
+ })
1668
+ }
1669
+ ```
1670
+
1671
+ ## Modern Development Workflow
1672
+
1673
+ ### Configuration Management
1674
+
1675
+ ```go
1676
+ // pkg/config/config.go
1677
+ package config
1678
+
1679
+ import (
1680
+ "fmt"
1681
+ "os"
1682
+ "strconv"
1683
+ "time"
1684
+
1685
+ "github.com/spf13/viper"
1686
+ )
1687
+
1688
+ // Config holds application configuration
1689
+ type Config struct {
1690
+ Server ServerConfig `mapstructure:"server"`
1691
+ Database DatabaseConfig `mapstructure:"database"`
1692
+ Redis RedisConfig `mapstructure:"redis"`
1693
+ Auth AuthConfig `mapstructure:"auth"`
1694
+ Logging LoggingConfig `mapstructure:"logging"`
1695
+ Monitoring MonitoringConfig `mapstructure:"monitoring"`
1696
+ }
1697
+
1698
+ // ServerConfig holds server configuration
1699
+ type ServerConfig struct {
1700
+ Host string `mapstructure:"host"`
1701
+ Port int `mapstructure:"port"`
1702
+ ReadTimeout time.Duration `mapstructure:"read_timeout"`
1703
+ WriteTimeout time.Duration `mapstructure:"write_timeout"`
1704
+ GracefulShutdownTimeout time.Duration `mapstructure:"graceful_shutdown_timeout"`
1705
+ }
1706
+
1707
+ // DatabaseConfig holds database configuration
1708
+ type DatabaseConfig struct {
1709
+ Host string `mapstructure:"host"`
1710
+ Port int `mapstructure:"port"`
1711
+ User string `mapstructure:"user"`
1712
+ Password string `mapstructure:"password"`
1713
+ DBName string `mapstructure:"db_name"`
1714
+ SSLMode string `mapstructure:"ssl_mode"`
1715
+ MaxOpenConns int `mapstructure:"max_open_conns"`
1716
+ MaxIdleConns int `mapstructure:"max_idle_conns"`
1717
+ ConnMaxLifetime time.Duration `mapstructure:"conn_max_lifetime"`
1718
+ }
1719
+
1720
+ // Load loads configuration from file and environment variables
1721
+ func Load() (*Config, error) {
1722
+ // Set default values
1723
+ setDefaults()
1724
+
1725
+ // Load from config file
1726
+ viper.SetConfigName("config")
1727
+ viper.SetConfigType("yaml")
1728
+ viper.AddConfigPath("./configs")
1729
+ viper.AddConfigPath(".")
1730
+
1731
+ // Load environment variables
1732
+ viper.AutomaticEnv()
1733
+ viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
1734
+
1735
+ if err := viper.ReadInConfig(); err != nil {
1736
+ if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
1737
+ return nil, fmt.Errorf("failed to read config file: %w", err)
1738
+ }
1739
+ // Config file not found is OK, we'll use defaults and env vars
1740
+ }
1741
+
1742
+ var config Config
1743
+ if err := viper.Unmarshal(&config); err != nil {
1744
+ return nil, fmt.Errorf("failed to unmarshal config: %w", err)
1745
+ }
1746
+
1747
+ // Validate configuration
1748
+ if err := validate(&config); err != nil {
1749
+ return nil, fmt.Errorf("invalid configuration: %w", err)
1750
+ }
1751
+
1752
+ return &config, nil
1753
+ }
1754
+
1755
+ func setDefaults() {
1756
+ viper.SetDefault("server.host", "0.0.0.0")
1757
+ viper.SetDefault("server.port", 8080)
1758
+ viper.SetDefault("server.read_timeout", 30*time.Second)
1759
+ viper.SetDefault("server.write_timeout", 30*time.Second)
1760
+ viper.SetDefault("server.graceful_shutdown_timeout", 30*time.Second)
1761
+
1762
+ viper.SetDefault("database.host", "localhost")
1763
+ viper.SetDefault("database.port", 5432)
1764
+ viper.SetDefault("database.ssl_mode", "disable")
1765
+ viper.SetDefault("database.max_open_conns", 25)
1766
+ viper.SetDefault("database.max_idle_conns", 25)
1767
+ viper.SetDefault("database.conn_max_lifetime", 5*time.Minute)
1768
+
1769
+ viper.SetDefault("redis.host", "localhost")
1770
+ viper.SetDefault("redis.port", 6379)
1771
+ viper.SetDefault("redis.db", 0)
1772
+
1773
+ viper.SetDefault("auth.jwt.expiration", 24*time.Hour)
1774
+
1775
+ viper.SetDefault("logging.level", "info")
1776
+ viper.SetDefault("logging.format", "json")
1777
+ }
1778
+
1779
+ func validate(config *Config) error {
1780
+ if config.Server.Port <= 0 || config.Server.Port > 65535 {
1781
+ return fmt.Errorf("invalid server port: %d", config.Server.Port)
1782
+ }
1783
+
1784
+ if config.Database.Host == "" {
1785
+ return fmt.Errorf("database host is required")
1786
+ }
1787
+
1788
+ if config.Database.User == "" {
1789
+ return fmt.Errorf("database user is required")
1790
+ }
1791
+
1792
+ return nil
1793
+ }
1794
+
1795
+ // GetDSN returns database connection string
1796
+ func (c *DatabaseConfig) GetDSN() string {
1797
+ return fmt.Sprintf(
1798
+ "host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
1799
+ c.Host, c.Port, c.User, c.Password, c.DBName, c.SSLMode,
1800
+ )
1801
+ }
1802
+
1803
+ // GetRedisAddr returns Redis connection address
1804
+ func (c *RedisConfig) GetAddr() string {
1805
+ return fmt.Sprintf("%s:%d", c.Host, c.Port)
1806
+ }
1807
+
1808
+ // GetServerAddr returns server address
1809
+ func (c *ServerConfig) GetAddr() string {
1810
+ return fmt.Sprintf("%s:%d", c.Host, c.Port)
1811
+ }
1812
+ ```
1813
+
1814
+ ### Makefile for Development
1815
+
1816
+ ```makefile
1817
+ # Makefile
1818
+ .PHONY: help build run test clean lint format docker-build docker-run
1819
+
1820
+ # Variables
1821
+ APP_NAME := your-app
1822
+ VERSION := $(shell git describe --tags --always --dirty)
1823
+ BUILD_TIME := $(shell date -u '+%Y-%m-%d_%H:%M:%S')
1824
+ LDFLAGS := -ldflags "-X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME)"
1825
+
1826
+ # Docker variables
1827
+ DOCKER_REGISTRY := your-registry
1828
+ DOCKER_TAG := $(DOCKER_REGISTRY)/$(APP_NAME):$(VERSION)
1829
+
1830
+ # Help
1831
+ help:
1832
+ @echo "Available commands:"
1833
+ @echo " build Build the application"
1834
+ @echo " run Run the application"
1835
+ @echo " test Run tests"
1836
+ @echo " test-coverage Run tests with coverage"
1837
+ @echo " lint Run linter"
1838
+ @echo " format Format code"
1839
+ @echo " clean Clean build artifacts"
1840
+ @echo " deps Install dependencies"
1841
+ @echo " migrate Run database migrations"
1842
+ @echo " docker-build Build Docker image"
1843
+ @echo " docker-run Run Docker container"
1844
+ @echo " generate Generate code (mocks, protobuf, etc.)"
1845
+
1846
+ # Build
1847
+ build:
1848
+ go build $(LDFLAGS) -o bin/$(APP_NAME) cmd/server/main.go
1849
+
1850
+ # Run
1851
+ run:
1852
+ go run $(LDFLAGS) cmd/server/main.go
1853
+
1854
+ # Development mode with hot reload
1855
+ dev:
1856
+ air
1857
+
1858
+ # Tests
1859
+ test:
1860
+ go test -v ./...
1861
+
1862
+ test-coverage:
1863
+ go test -v -race -coverprofile=coverage.out ./...
1864
+ go tool cover -html=coverage.out -o coverage.html
1865
+
1866
+ test-bench:
1867
+ go test -bench=. -benchmem ./...
1868
+
1869
+ # Linting
1870
+ lint:
1871
+ golangci-lint run
1872
+
1873
+ # Formatting
1874
+ format:
1875
+ go fmt ./...
1876
+ goimports -w .
1877
+
1878
+ # Dependencies
1879
+ deps:
1880
+ go mod download
1881
+ go mod tidy
1882
+
1883
+ # Generate code
1884
+ generate:
1885
+ go generate ./...
1886
+ mockgen -source=internal/service/user.go -destination=test/mocks/user_service_mock.go
1887
+ protoc --go_out=. --go-grpc_out=. api/proto/user.proto
1888
+
1889
+ # Database
1890
+ migrate-up:
1891
+ migrate -path migrations -database "$(shell grep -A5 'database:' configs/config.yaml | tail -n1 | cut -d' ' -f2)" up
1892
+
1893
+ migrate-down:
1894
+ migrate -path migrations -database "$(shell grep -A5 'database:' configs/config.yaml | tail -n1 | cut -d' ' -f2)" down
1895
+
1896
+ # Clean
1897
+ clean:
1898
+ rm -rf bin/
1899
+ rm -f coverage.out coverage.html
1900
+
1901
+ # Docker
1902
+ docker-build:
1903
+ docker build -t $(DOCKER_TAG) .
1904
+
1905
+ docker-run:
1906
+ docker run -p 8080:8080 $(DOCKER_TAG)
1907
+
1908
+ docker-push:
1909
+ docker push $(DOCKER_TAG)
1910
+
1911
+ # Install tools
1912
+ install-tools:
1913
+ go install github.com/cosmtrek/air@latest
1914
+ go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
1915
+ go install golang.org/x/tools/cmd/goimports@latest
1916
+ go install github.com/golang/mock/mockgen@latest
1917
+ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
1918
+ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
1919
+ ```
1920
+
1921
+ ---
93
1922
 
94
- - alfred-trust-validation (coverage verification)
95
- - alfred-code-reviewer (Go-specific review)
96
- - alfred-performance-optimizer (Go profiling)
1923
+ **Created by**: MoAI Language Skill Factory
1924
+ **Last Updated**: 2025-11-06
1925
+ **Version**: 2.0.0
1926
+ **Go Target**: 1.25+ with latest language features
97
1927
 
98
- ## Best Practices
99
- - Enable automatic validation by matching your linter with the language's official style guide.
100
- - Fix test/build pipelines with reproducible commands in CI.
1928
+ This skill provides comprehensive Go development guidance with 2025 best practices, covering everything from basic concurrent programming to advanced cloud-native patterns and enterprise-grade applications.