@stackonward/cli 0.0.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (638) hide show
  1. package/dist/index.js +4588 -205
  2. package/dist/index.js.map +1 -1
  3. package/dist/resources/apple/.claude/docs/architecture-template.md +54 -0
  4. package/dist/resources/apple/.claude/docs/architecture.md +52 -0
  5. package/dist/resources/apple/.claude/docs/index.md +13 -0
  6. package/dist/resources/apple/.claude/docs/security-lifecycle.md +57 -0
  7. package/dist/resources/apple/.claude/docs/stack.md +93 -0
  8. package/dist/resources/apple/.claude/docs/verification.md +63 -0
  9. package/dist/resources/apple/AGENTS.md +397 -0
  10. package/dist/resources/apple/CLAUDE.md +397 -0
  11. package/dist/resources/apple/Gemfile +2 -0
  12. package/dist/resources/apple/Gemfile.lock +365 -0
  13. package/dist/resources/apple/_gitignore +14 -0
  14. package/dist/resources/apple/fastlane/Fastfile +123 -0
  15. package/dist/resources/components/nuxt/site-source/app/app.vue +42 -0
  16. package/dist/resources/components/nuxt/site-source/app/assets/css/site-shell.css +1035 -0
  17. package/dist/resources/components/nuxt/site-source/app/assets/icons/brand/.gitkeep +0 -0
  18. package/dist/resources/components/nuxt/site-source/app/assets/icons/common/.gitkeep +0 -0
  19. package/dist/resources/components/nuxt/site-source/app/components/site/ApplicationHeader.vue +35 -0
  20. package/dist/resources/components/nuxt/site-source/app/components/site/ApplicationShell.vue +56 -0
  21. package/dist/resources/components/nuxt/site-source/app/components/site/ApplicationSidebar.vue +40 -0
  22. package/dist/resources/components/nuxt/site-source/app/components/site/BackToTop.vue +42 -0
  23. package/dist/resources/components/nuxt/site-source/app/components/site/ContentArticlePage.vue +40 -0
  24. package/dist/resources/components/nuxt/site-source/app/components/site/ContentListPage.vue +30 -0
  25. package/dist/resources/components/nuxt/site-source/app/components/site/CookieConsent.vue +18 -0
  26. package/dist/resources/components/nuxt/site-source/app/components/site/MarketingFooter.vue +52 -0
  27. package/dist/resources/components/nuxt/site-source/app/components/site/MarketingHeader.vue +106 -0
  28. package/dist/resources/components/nuxt/site-source/app/components/site/MarketingShell.vue +35 -0
  29. package/dist/resources/components/nuxt/site-source/app/components/site/SiteBrand.vue +10 -0
  30. package/dist/resources/components/nuxt/site-source/app/components/site/StaticPage.vue +21 -0
  31. package/dist/resources/components/nuxt/site-source/app/components/site/ToastViewport.vue +25 -0
  32. package/dist/resources/components/nuxt/site-source/app/components/ui/BaseButton.vue +86 -0
  33. package/dist/resources/components/nuxt/site-source/app/components/ui/BaseGradientBorder.vue +59 -0
  34. package/dist/resources/components/nuxt/site-source/app/components/ui/BaseModal.vue +131 -0
  35. package/dist/resources/components/nuxt/site-source/app/components/ui/BasePopover.vue +150 -0
  36. package/dist/resources/components/nuxt/site-source/app/components/ui/BaseText.vue +138 -0
  37. package/dist/resources/components/nuxt/site-source/app/components/ui/CheckoutStatus.vue +112 -0
  38. package/dist/resources/components/nuxt/site-source/app/components/ui/CheckoutSummary.vue +172 -0
  39. package/dist/resources/components/nuxt/site-source/app/components/ui/GoogleSignInButton.vue +113 -0
  40. package/dist/resources/components/nuxt/site-source/app/components/ui/InfiniteScroll.vue +123 -0
  41. package/dist/resources/components/nuxt/site-source/app/components/ui/YoutubeEmbed.vue +126 -0
  42. package/dist/resources/components/nuxt/site-source/app/composables/useAnalytics.ts +24 -0
  43. package/dist/resources/components/nuxt/site-source/app/composables/useCheckout.ts +121 -0
  44. package/dist/resources/components/nuxt/site-source/app/composables/useConsent.ts +31 -0
  45. package/dist/resources/components/nuxt/site-source/app/composables/useGoogleIdentity.ts +163 -0
  46. package/dist/resources/components/nuxt/site-source/app/composables/useNavigation.ts +11 -0
  47. package/dist/resources/components/nuxt/site-source/app/composables/useSeo.ts +33 -0
  48. package/dist/resources/components/nuxt/site-source/app/composables/useSiteShell.ts +58 -0
  49. package/dist/resources/components/nuxt/site-source/app/composables/useToasts.ts +48 -0
  50. package/dist/resources/components/nuxt/site-source/app/layouts/app.vue +5 -0
  51. package/dist/resources/components/nuxt/site-source/app/layouts/default.vue +5 -0
  52. package/dist/resources/components/nuxt/site-source/app/plugins/analytics.client.ts +121 -0
  53. package/dist/resources/components/nuxt/site-source/app/plugins/google-identity.client.ts +24 -0
  54. package/dist/resources/components/nuxt/site-source/app/theme/accordion.ts +9 -0
  55. package/dist/resources/components/nuxt/site-source/app/theme/breadcrumb.ts +8 -0
  56. package/dist/resources/components/nuxt/site-source/app/theme/button.ts +92 -0
  57. package/dist/resources/components/nuxt/site-source/app/theme/carousel.ts +11 -0
  58. package/dist/resources/components/nuxt/site-source/app/theme/checkbox.ts +12 -0
  59. package/dist/resources/components/nuxt/site-source/app/theme/index.ts +30 -0
  60. package/dist/resources/components/nuxt/site-source/app/theme/input.ts +47 -0
  61. package/dist/resources/components/nuxt/site-source/app/theme/modal.ts +9 -0
  62. package/dist/resources/components/nuxt/site-source/app/theme/pagination.ts +6 -0
  63. package/dist/resources/components/nuxt/site-source/app/theme/select.ts +23 -0
  64. package/dist/resources/components/nuxt/site-source/app/theme/stepper.ts +10 -0
  65. package/dist/resources/components/nuxt/site-source/app/theme/toast.ts +8 -0
  66. package/dist/resources/components/nuxt/site-source/app/theme/tooltip.ts +6 -0
  67. package/dist/resources/components/nuxt/site-source/app/types/site-shell.ts +85 -0
  68. package/dist/resources/components/react/ui/Button.tsx +73 -0
  69. package/dist/resources/components/react/ui/Input.tsx +44 -0
  70. package/dist/resources/components/registry.json +355 -0
  71. package/dist/resources/components/vue/feedback/Toast.vue +120 -0
  72. package/dist/resources/components/vue/feedback/useToast.ts +70 -0
  73. package/dist/resources/components/vue/media/FileUpload.vue +229 -0
  74. package/dist/resources/components/vue/media/VideoPlayer.vue +157 -0
  75. package/dist/resources/components/vue/ui/AppImage.vue +147 -0
  76. package/dist/resources/components/vue/ui/BottomSheet.vue +217 -0
  77. package/dist/resources/components/vue/ui/Button.vue +154 -0
  78. package/dist/resources/components/vue/ui/Card.vue +111 -0
  79. package/dist/resources/components/vue/ui/Input.vue +113 -0
  80. package/dist/resources/components/vue/ui/Modal.vue +193 -0
  81. package/dist/resources/components/vue/ui/ScrollArea.vue +163 -0
  82. package/dist/resources/components/vue/ui/Tooltip.vue +115 -0
  83. package/dist/resources/registry.json +158 -0
  84. package/dist/resources/snippets/node/cache.ts +116 -0
  85. package/dist/resources/snippets/node/date.ts +126 -0
  86. package/dist/resources/snippets/node/logger.ts +104 -0
  87. package/dist/resources/snippets/node/validation.ts +132 -0
  88. package/dist/resources/snippets/react/useDebounce.ts +90 -0
  89. package/dist/resources/snippets/registry.json +65 -0
  90. package/dist/resources/snippets/vue/useAsync.ts +96 -0
  91. package/dist/resources/snippets/vue/usePagination.ts +102 -0
  92. package/dist/resources/templates/base/.claude/docs/architecture-template.md +459 -0
  93. package/dist/resources/templates/base/.claude/docs/architecture.md +137 -0
  94. package/dist/resources/templates/base/.claude/docs/index.md +42 -0
  95. package/dist/resources/templates/base/.claude/docs/security-lifecycle.md +129 -0
  96. package/dist/resources/templates/base/.claude/docs/verification.md +121 -0
  97. package/dist/resources/templates/base/AGENTS.md +415 -0
  98. package/dist/resources/templates/base/CLAUDE.md +415 -0
  99. package/dist/resources/templates/go-backend/.claude/docs/api-design.md +486 -0
  100. package/dist/resources/templates/go-backend/.claude/docs/architecture-template.md +449 -0
  101. package/dist/resources/templates/go-backend/.claude/docs/check-list.md +155 -0
  102. package/dist/resources/templates/go-backend/.claude/docs/database.md +369 -0
  103. package/dist/resources/templates/go-backend/.claude/docs/e2e-standards.md +161 -0
  104. package/dist/resources/templates/go-backend/.claude/docs/error-handling.md +558 -0
  105. package/dist/resources/templates/go-backend/.claude/docs/event-runtime-boundary.md +124 -0
  106. package/dist/resources/templates/go-backend/.claude/docs/identifier-contract.md +195 -0
  107. package/dist/resources/templates/go-backend/.claude/docs/index.md +22 -0
  108. package/dist/resources/templates/go-backend/.claude/docs/logging.md +314 -0
  109. package/dist/resources/templates/go-backend/.claude/docs/mediagen-provider-onboarding-sop.md +917 -0
  110. package/dist/resources/templates/go-backend/.claude/docs/mediagen-provider-quick-reference.md +195 -0
  111. package/dist/resources/templates/go-backend/.claude/docs/module-standards.md +309 -0
  112. package/dist/resources/templates/go-backend/.claude/docs/openapi-contract.md +141 -0
  113. package/dist/resources/templates/go-backend/.claude/docs/payment-gateway-onboarding.md +283 -0
  114. package/dist/resources/templates/go-backend/.claude/docs/platform-boundary.md +191 -0
  115. package/dist/resources/templates/go-backend/.claude/docs/quality-gates.md +112 -0
  116. package/dist/resources/templates/go-backend/.dockerignore +6 -0
  117. package/dist/resources/templates/go-backend/.env.example +13 -0
  118. package/dist/resources/templates/go-backend/.gitattributes +2 -0
  119. package/dist/resources/templates/go-backend/AGENTS.md +1139 -0
  120. package/dist/resources/templates/go-backend/CLAUDE.md +1139 -0
  121. package/dist/resources/templates/go-backend/Dockerfile +14 -0
  122. package/dist/resources/templates/go-backend/Makefile +71 -0
  123. package/dist/resources/templates/go-backend/README.md +66 -0
  124. package/dist/resources/templates/go-backend/_gitignore +10 -0
  125. package/dist/resources/templates/go-backend/api/openapi/README.md +29 -0
  126. package/dist/resources/templates/go-backend/api/openapi/dist/artifact-manifest.json +19 -0
  127. package/dist/resources/templates/go-backend/api/openapi/dist/conformance-matrix.json +276 -0
  128. package/dist/resources/templates/go-backend/api/openapi/document.go +30 -0
  129. package/dist/resources/templates/go-backend/api/openapi/package.json +28 -0
  130. package/dist/resources/templates/go-backend/api/openapi/pnpm-lock.yaml +3052 -0
  131. package/dist/resources/templates/go-backend/api/openapi/redocly-source.yaml +18 -0
  132. package/dist/resources/templates/go-backend/api/openapi/redocly.yaml +8 -0
  133. package/dist/resources/templates/go-backend/api/openapi/sdk-generators.json +16 -0
  134. package/dist/resources/templates/go-backend/api/openapi/service-registry.json +39 -0
  135. package/dist/resources/templates/go-backend/api/openapi/services/product-api/conformance/runtime.arazzo.yaml +65 -0
  136. package/dist/resources/templates/go-backend/api/openapi/services/product-api/dist/internal.openapi.json +327 -0
  137. package/dist/resources/templates/go-backend/api/openapi/services/product-api/dist/runtime-contract.json +56 -0
  138. package/dist/resources/templates/go-backend/api/openapi/services/product-api/openapi.yaml +222 -0
  139. package/dist/resources/templates/go-backend/api/openapi/services/worker/conformance/runtime.arazzo.yaml +65 -0
  140. package/dist/resources/templates/go-backend/api/openapi/services/worker/dist/internal.openapi.json +327 -0
  141. package/dist/resources/templates/go-backend/api/openapi/services/worker/dist/runtime-contract.json +56 -0
  142. package/dist/resources/templates/go-backend/api/openapi/services/worker/openapi.yaml +222 -0
  143. package/dist/resources/templates/go-backend/api/openapi/tooling/breaking.mjs +416 -0
  144. package/dist/resources/templates/go-backend/api/openapi/tooling/build.mjs +103 -0
  145. package/dist/resources/templates/go-backend/api/openapi/tooling/conformance_coverage.mjs +111 -0
  146. package/dist/resources/templates/go-backend/api/openapi/tooling/contract_compiler.mjs +62 -0
  147. package/dist/resources/templates/go-backend/api/openapi/tooling/contract_policy.mjs +208 -0
  148. package/dist/resources/templates/go-backend/api/openapi/tooling/delegated_contract.mjs +302 -0
  149. package/dist/resources/templates/go-backend/api/openapi/tooling/deterministic_archive.mjs +69 -0
  150. package/dist/resources/templates/go-backend/api/openapi/tooling/documentation_example_privacy.mjs +93 -0
  151. package/dist/resources/templates/go-backend/api/openapi/tooling/documentation_projection.mjs +498 -0
  152. package/dist/resources/templates/go-backend/api/openapi/tooling/documentation_quality.mjs +346 -0
  153. package/dist/resources/templates/go-backend/api/openapi/tooling/git_artifact_history.mjs +188 -0
  154. package/dist/resources/templates/go-backend/api/openapi/tooling/manifest.mjs +170 -0
  155. package/dist/resources/templates/go-backend/api/openapi/tooling/overlay.mjs +98 -0
  156. package/dist/resources/templates/go-backend/api/openapi/tooling/project.mjs +549 -0
  157. package/dist/resources/templates/go-backend/api/openapi/tooling/route_contract.mjs +156 -0
  158. package/dist/resources/templates/go-backend/api/openapi/tooling/runtime_conformance.mjs +193 -0
  159. package/dist/resources/templates/go-backend/api/openapi/tooling/scalar_asset_localization.mjs +164 -0
  160. package/dist/resources/templates/go-backend/api/openapi/tooling/sdk_generator.mjs +229 -0
  161. package/dist/resources/templates/go-backend/api/openapi/tooling/semantic_version.mjs +64 -0
  162. package/dist/resources/templates/go-backend/api/openapi/tooling/service_contract_inputs.mjs +16 -0
  163. package/dist/resources/templates/go-backend/api/openapi/tooling/test/breaking.test.mjs +365 -0
  164. package/dist/resources/templates/go-backend/api/openapi/tooling/test/build.test.mjs +42 -0
  165. package/dist/resources/templates/go-backend/api/openapi/tooling/test/conformance_coverage.test.mjs +88 -0
  166. package/dist/resources/templates/go-backend/api/openapi/tooling/test/contract_policy.test.mjs +257 -0
  167. package/dist/resources/templates/go-backend/api/openapi/tooling/test/delegated_contract.test.mjs +205 -0
  168. package/dist/resources/templates/go-backend/api/openapi/tooling/test/documentation_example_privacy.test.mjs +51 -0
  169. package/dist/resources/templates/go-backend/api/openapi/tooling/test/documentation_projection.test.mjs +368 -0
  170. package/dist/resources/templates/go-backend/api/openapi/tooling/test/documentation_quality.test.mjs +151 -0
  171. package/dist/resources/templates/go-backend/api/openapi/tooling/test/git_artifact_history.test.mjs +60 -0
  172. package/dist/resources/templates/go-backend/api/openapi/tooling/test/head_policy.test.mjs +8 -0
  173. package/dist/resources/templates/go-backend/api/openapi/tooling/test/overlay.test.mjs +44 -0
  174. package/dist/resources/templates/go-backend/api/openapi/tooling/test/projection.test.mjs +270 -0
  175. package/dist/resources/templates/go-backend/api/openapi/tooling/test/redocly_documentation_rules.test.mjs +146 -0
  176. package/dist/resources/templates/go-backend/api/openapi/tooling/test/release_manifest.test.mjs +76 -0
  177. package/dist/resources/templates/go-backend/api/openapi/tooling/test/route_contract.test.mjs +119 -0
  178. package/dist/resources/templates/go-backend/api/openapi/tooling/test/runtime_conformance.test.mjs +75 -0
  179. package/dist/resources/templates/go-backend/api/openapi/tooling/test/scalar_asset_localization.test.mjs +50 -0
  180. package/dist/resources/templates/go-backend/api/openapi/tooling/test/sdk_generator.test.mjs +31 -0
  181. package/dist/resources/templates/go-backend/api/openapi/tooling/test/semantic_version.test.mjs +60 -0
  182. package/dist/resources/templates/go-backend/api/openapi/tooling/test/service_contract_inputs.test.mjs +27 -0
  183. package/dist/resources/templates/go-backend/cmd/internal/runtime/resources.go +125 -0
  184. package/dist/resources/templates/go-backend/cmd/internal/runtime/runtime.go +102 -0
  185. package/dist/resources/templates/go-backend/cmd/internal/runtime/runtime_test.go +70 -0
  186. package/dist/resources/templates/go-backend/cmd/product-api/lifecycle_test.go +58 -0
  187. package/dist/resources/templates/go-backend/cmd/product-api/main.go +32 -0
  188. package/dist/resources/templates/go-backend/cmd/product-api/wire.go +13 -0
  189. package/dist/resources/templates/go-backend/cmd/product-api/wire_gen.go +94 -0
  190. package/dist/resources/templates/go-backend/cmd/worker/main.go +47 -0
  191. package/dist/resources/templates/go-backend/cmd/worker/wire.go +14 -0
  192. package/dist/resources/templates/go-backend/cmd/worker/wire_gen.go +111 -0
  193. package/dist/resources/templates/go-backend/configs/config.yaml +37 -0
  194. package/dist/resources/templates/go-backend/deployments/compose.yaml +71 -0
  195. package/dist/resources/templates/go-backend/docs/openapi-provenance.json +489 -0
  196. package/dist/resources/templates/go-backend/docs/runtime-provenance.json +175 -0
  197. package/dist/resources/templates/go-backend/docs/source-provenance.json +3568 -0
  198. package/dist/resources/templates/go-backend/docs/standards-provenance.json +1624 -0
  199. package/dist/resources/templates/go-backend/go.mod +256 -0
  200. package/dist/resources/templates/go-backend/go.sum +805 -0
  201. package/dist/resources/templates/go-backend/internal/common/canonicaljson/canonical.go +370 -0
  202. package/dist/resources/templates/go-backend/internal/common/canonicaljson/canonical_test.go +223 -0
  203. package/dist/resources/templates/go-backend/internal/common/checkoutbff/contracts.go +125 -0
  204. package/dist/resources/templates/go-backend/internal/common/checkoutbff/platform_client.go +212 -0
  205. package/dist/resources/templates/go-backend/internal/common/checkoutbff/platform_client_test.go +319 -0
  206. package/dist/resources/templates/go-backend/internal/common/contentaccess/contentaccess.go +50 -0
  207. package/dist/resources/templates/go-backend/internal/common/contracts/contact.go +85 -0
  208. package/dist/resources/templates/go-backend/internal/common/ctxutil/identity.go +20 -0
  209. package/dist/resources/templates/go-backend/internal/common/ctxutil/product.go +53 -0
  210. package/dist/resources/templates/go-backend/internal/common/enumdomain/payment.go +12 -0
  211. package/dist/resources/templates/go-backend/internal/common/enums/dto_admin.go +9 -0
  212. package/dist/resources/templates/go-backend/internal/common/enums/enum.go +1247 -0
  213. package/dist/resources/templates/go-backend/internal/common/enums/handler_admin.go +66 -0
  214. package/dist/resources/templates/go-backend/internal/common/enums/module.go +46 -0
  215. package/dist/resources/templates/go-backend/internal/common/enums/provider.go +10 -0
  216. package/dist/resources/templates/go-backend/internal/common/enums/register.go +11 -0
  217. package/dist/resources/templates/go-backend/internal/common/enums/register_audit.go +274 -0
  218. package/dist/resources/templates/go-backend/internal/common/enums/register_command_replay.go +12 -0
  219. package/dist/resources/templates/go-backend/internal/common/enums/register_config.go +27 -0
  220. package/dist/resources/templates/go-backend/internal/common/enums/register_locale.go +37 -0
  221. package/dist/resources/templates/go-backend/internal/common/enums/register_ops.go +14 -0
  222. package/dist/resources/templates/go-backend/internal/common/enums/register_outbox.go +15 -0
  223. package/dist/resources/templates/go-backend/internal/common/enums/register_rule_expression.go +63 -0
  224. package/dist/resources/templates/go-backend/internal/common/enums/registry.go +77 -0
  225. package/dist/resources/templates/go-backend/internal/common/httporigin/origin.go +62 -0
  226. package/dist/resources/templates/go-backend/internal/common/httporigin/origin_test.go +38 -0
  227. package/dist/resources/templates/go-backend/internal/common/iamcredential/plaintext.go +35 -0
  228. package/dist/resources/templates/go-backend/internal/common/iamcredential/plaintext_test.go +29 -0
  229. package/dist/resources/templates/go-backend/internal/common/iamscope/scope.go +212 -0
  230. package/dist/resources/templates/go-backend/internal/common/iamscope/scope_binding.go +26 -0
  231. package/dist/resources/templates/go-backend/internal/common/iamscope/scope_filter.go +173 -0
  232. package/dist/resources/templates/go-backend/internal/common/iamscope/scope_filter_test.go +279 -0
  233. package/dist/resources/templates/go-backend/internal/common/internalapi/authorization_details.go +10 -0
  234. package/dist/resources/templates/go-backend/internal/common/internalapi/route_permission_policies.go +660 -0
  235. package/dist/resources/templates/go-backend/internal/common/internalapi/route_permission_policies_test.go +331 -0
  236. package/dist/resources/templates/go-backend/internal/common/internalservice/audience_token_source.go +166 -0
  237. package/dist/resources/templates/go-backend/internal/common/internalservice/bootstrap_token_exchanger.go +183 -0
  238. package/dist/resources/templates/go-backend/internal/common/internalservice/bound_service_token_signer.go +52 -0
  239. package/dist/resources/templates/go-backend/internal/common/internalservice/delegated_access_token_exchanger.go +189 -0
  240. package/dist/resources/templates/go-backend/internal/common/internalservice/delegated_access_token_exchanger_test.go +159 -0
  241. package/dist/resources/templates/go-backend/internal/common/internalservice/product_scoped_service_token_signer.go +92 -0
  242. package/dist/resources/templates/go-backend/internal/common/internalservice/provider.go +25 -0
  243. package/dist/resources/templates/go-backend/internal/common/internalservice/request_signer.go +86 -0
  244. package/dist/resources/templates/go-backend/internal/common/internalservice/resolver.go +69 -0
  245. package/dist/resources/templates/go-backend/internal/common/internalservice/resolver_test.go +42 -0
  246. package/dist/resources/templates/go-backend/internal/common/internalservice/route_scope.go +95 -0
  247. package/dist/resources/templates/go-backend/internal/common/internalservice/route_scope_test.go +78 -0
  248. package/dist/resources/templates/go-backend/internal/common/internalservice/service_identity_test.go +387 -0
  249. package/dist/resources/templates/go-backend/internal/common/jsonschema/compiler.go +100 -0
  250. package/dist/resources/templates/go-backend/internal/common/jsonschema/compiler_test.go +41 -0
  251. package/dist/resources/templates/go-backend/internal/common/jwksapi/handler.go +83 -0
  252. package/dist/resources/templates/go-backend/internal/common/jwksapi/handler_test.go +104 -0
  253. package/dist/resources/templates/go-backend/internal/common/locale/locale.go +145 -0
  254. package/dist/resources/templates/go-backend/internal/common/locale/locale_test.go +75 -0
  255. package/dist/resources/templates/go-backend/internal/common/mediaref/mediaref.go +54 -0
  256. package/dist/resources/templates/go-backend/internal/common/mediaref/mediaref_test.go +77 -0
  257. package/dist/resources/templates/go-backend/internal/common/middleware/apikey_auth.go +320 -0
  258. package/dist/resources/templates/go-backend/internal/common/middleware/apikey_throttle.go +158 -0
  259. package/dist/resources/templates/go-backend/internal/common/middleware/auth.go +40 -0
  260. package/dist/resources/templates/go-backend/internal/common/middleware/auth_test.go +50 -0
  261. package/dist/resources/templates/go-backend/internal/common/middleware/client_context.go +86 -0
  262. package/dist/resources/templates/go-backend/internal/common/middleware/cors.go +68 -0
  263. package/dist/resources/templates/go-backend/internal/common/middleware/event_context.go +18 -0
  264. package/dist/resources/templates/go-backend/internal/common/middleware/gateway_identity.go +279 -0
  265. package/dist/resources/templates/go-backend/internal/common/middleware/helpers.go +159 -0
  266. package/dist/resources/templates/go-backend/internal/common/middleware/iam_delegated_route_permission.go +171 -0
  267. package/dist/resources/templates/go-backend/internal/common/middleware/iam_delegated_token_auth.go +151 -0
  268. package/dist/resources/templates/go-backend/internal/common/middleware/iam_delegated_token_auth_test.go +99 -0
  269. package/dist/resources/templates/go-backend/internal/common/middleware/iam_service_identity.go +138 -0
  270. package/dist/resources/templates/go-backend/internal/common/middleware/iam_service_token_auth.go +74 -0
  271. package/dist/resources/templates/go-backend/internal/common/middleware/idempotent.go +273 -0
  272. package/dist/resources/templates/go-backend/internal/common/middleware/idempotent_test.go +83 -0
  273. package/dist/resources/templates/go-backend/internal/common/middleware/internal_route_permission.go +45 -0
  274. package/dist/resources/templates/go-backend/internal/common/middleware/internal_route_permission_test.go +186 -0
  275. package/dist/resources/templates/go-backend/internal/common/middleware/logging.go +191 -0
  276. package/dist/resources/templates/go-backend/internal/common/middleware/metrics.go +45 -0
  277. package/dist/resources/templates/go-backend/internal/common/middleware/middleware_test.go +1516 -0
  278. package/dist/resources/templates/go-backend/internal/common/middleware/principal_context.go +160 -0
  279. package/dist/resources/templates/go-backend/internal/common/middleware/principal_context_test.go +355 -0
  280. package/dist/resources/templates/go-backend/internal/common/middleware/product_context.go +100 -0
  281. package/dist/resources/templates/go-backend/internal/common/middleware/recovery.go +40 -0
  282. package/dist/resources/templates/go-backend/internal/common/middleware/referral_attribution.go +178 -0
  283. package/dist/resources/templates/go-backend/internal/common/middleware/requestid.go +48 -0
  284. package/dist/resources/templates/go-backend/internal/common/middleware/resource_permission.go +790 -0
  285. package/dist/resources/templates/go-backend/internal/common/middleware/resource_permission_test.go +440 -0
  286. package/dist/resources/templates/go-backend/internal/common/middleware/service_credential_auth.go +67 -0
  287. package/dist/resources/templates/go-backend/internal/common/middleware/tenant.go +148 -0
  288. package/dist/resources/templates/go-backend/internal/common/middleware/throttle.go +310 -0
  289. package/dist/resources/templates/go-backend/internal/common/middleware/trusted_client_ip.go +23 -0
  290. package/dist/resources/templates/go-backend/internal/common/middleware/trusted_client_ip_test.go +60 -0
  291. package/dist/resources/templates/go-backend/internal/common/money/currency.go +25 -0
  292. package/dist/resources/templates/go-backend/internal/common/money/errors.go +23 -0
  293. package/dist/resources/templates/go-backend/internal/common/money/format.go +123 -0
  294. package/dist/resources/templates/go-backend/internal/common/money/format_test.go +204 -0
  295. package/dist/resources/templates/go-backend/internal/common/money/gateway.go +144 -0
  296. package/dist/resources/templates/go-backend/internal/common/money/gateway_test.go +165 -0
  297. package/dist/resources/templates/go-backend/internal/common/money/rounding.go +56 -0
  298. package/dist/resources/templates/go-backend/internal/common/money/rounding_test.go +51 -0
  299. package/dist/resources/templates/go-backend/internal/common/principal/context.go +56 -0
  300. package/dist/resources/templates/go-backend/internal/common/principal/principal.go +49 -0
  301. package/dist/resources/templates/go-backend/internal/common/productcode/code.go +24 -0
  302. package/dist/resources/templates/go-backend/internal/common/productcode/code_test.go +35 -0
  303. package/dist/resources/templates/go-backend/internal/common/providerconfig/schema.go +577 -0
  304. package/dist/resources/templates/go-backend/internal/common/providerconfig/schema_test.go +47 -0
  305. package/dist/resources/templates/go-backend/internal/common/requestprivacy/request.go +246 -0
  306. package/dist/resources/templates/go-backend/internal/common/requestprivacy/request_test.go +170 -0
  307. package/dist/resources/templates/go-backend/internal/common/response/pagination.go +60 -0
  308. package/dist/resources/templates/go-backend/internal/common/response/response.go +110 -0
  309. package/dist/resources/templates/go-backend/internal/common/response/response_test.go +463 -0
  310. package/dist/resources/templates/go-backend/internal/common/ruleexpression/ast.go +141 -0
  311. package/dist/resources/templates/go-backend/internal/common/ruleexpression/ast_test.go +81 -0
  312. package/dist/resources/templates/go-backend/internal/common/ruleexpression/canonical.go +184 -0
  313. package/dist/resources/templates/go-backend/internal/common/ruleexpression/canonical_test.go +319 -0
  314. package/dist/resources/templates/go-backend/internal/common/ruleexpression/decoder.go +555 -0
  315. package/dist/resources/templates/go-backend/internal/common/ruleexpression/decoder_test.go +260 -0
  316. package/dist/resources/templates/go-backend/internal/common/ruleexpression/errors.go +55 -0
  317. package/dist/resources/templates/go-backend/internal/common/ruleexpression/evaluator.go +96 -0
  318. package/dist/resources/templates/go-backend/internal/common/ruleexpression/evaluator_test.go +220 -0
  319. package/dist/resources/templates/go-backend/internal/common/ruleexpression/fuzz_test.go +116 -0
  320. package/dist/resources/templates/go-backend/internal/common/ruleexpression/limits.go +331 -0
  321. package/dist/resources/templates/go-backend/internal/common/ruleexpression/schema.go +412 -0
  322. package/dist/resources/templates/go-backend/internal/common/ruleexpression/schema_test.go +164 -0
  323. package/dist/resources/templates/go-backend/internal/common/runtimeinput/runtime_input.go +627 -0
  324. package/dist/resources/templates/go-backend/internal/common/runtimeinput/runtime_input_test.go +245 -0
  325. package/dist/resources/templates/go-backend/internal/common/semver/errors.go +6 -0
  326. package/dist/resources/templates/go-backend/internal/common/semver/semver.go +125 -0
  327. package/dist/resources/templates/go-backend/internal/common/semver/semver_test.go +205 -0
  328. package/dist/resources/templates/go-backend/internal/common/serviceidentity/audience.go +48 -0
  329. package/dist/resources/templates/go-backend/internal/common/serviceidentity/audience_test.go +35 -0
  330. package/dist/resources/templates/go-backend/internal/common/serviceidentity/resource_identifier.go +33 -0
  331. package/dist/resources/templates/go-backend/internal/common/serviceidentity/resource_identifier_test.go +32 -0
  332. package/dist/resources/templates/go-backend/internal/common/tradeno/generator.go +99 -0
  333. package/dist/resources/templates/go-backend/internal/common/tradeno/generator_test.go +396 -0
  334. package/dist/resources/templates/go-backend/internal/common/tradeno/prefix.go +247 -0
  335. package/dist/resources/templates/go-backend/internal/common/types/asset_url.go +11 -0
  336. package/dist/resources/templates/go-backend/internal/common/types/billing.go +89 -0
  337. package/dist/resources/templates/go-backend/internal/common/types/billing_test.go +77 -0
  338. package/dist/resources/templates/go-backend/internal/common/types/country.go +74 -0
  339. package/dist/resources/templates/go-backend/internal/common/types/country_test.go +28 -0
  340. package/dist/resources/templates/go-backend/internal/common/types/currency.go +60 -0
  341. package/dist/resources/templates/go-backend/internal/common/types/identifiers.go +41 -0
  342. package/dist/resources/templates/go-backend/internal/common/types/operator.go +28 -0
  343. package/dist/resources/templates/go-backend/internal/common/types/subscription_entitlement.go +24 -0
  344. package/dist/resources/templates/go-backend/internal/common/types/subscription_entitlement_test.go +35 -0
  345. package/dist/resources/templates/go-backend/internal/common/types/tier.go +72 -0
  346. package/dist/resources/templates/go-backend/internal/common/types/types.go +411 -0
  347. package/dist/resources/templates/go-backend/internal/common/types/types_test.go +295 -0
  348. package/dist/resources/templates/go-backend/internal/common/utils/constants.go +100 -0
  349. package/dist/resources/templates/go-backend/internal/common/utils/crypto.go +158 -0
  350. package/dist/resources/templates/go-backend/internal/common/utils/crypto_test.go +345 -0
  351. package/dist/resources/templates/go-backend/internal/common/utils/duration.go +25 -0
  352. package/dist/resources/templates/go-backend/internal/common/utils/helpers.go +18 -0
  353. package/dist/resources/templates/go-backend/internal/common/utils/json.go +62 -0
  354. package/dist/resources/templates/go-backend/internal/common/utils/json_test.go +76 -0
  355. package/dist/resources/templates/go-backend/internal/common/utils/pagination.go +51 -0
  356. package/dist/resources/templates/go-backend/internal/common/utils/pagination_test.go +45 -0
  357. package/dist/resources/templates/go-backend/internal/common/utils/pointer.go +107 -0
  358. package/dist/resources/templates/go-backend/internal/common/utils/pointer_test.go +15 -0
  359. package/dist/resources/templates/go-backend/internal/common/utils/slice.go +24 -0
  360. package/dist/resources/templates/go-backend/internal/common/utils/snowflake.go +110 -0
  361. package/dist/resources/templates/go-backend/internal/common/utils/snowflake_test.go +316 -0
  362. package/dist/resources/templates/go-backend/internal/common/utils/string.go +16 -0
  363. package/dist/resources/templates/go-backend/internal/common/utils/timefmt.go +42 -0
  364. package/dist/resources/templates/go-backend/internal/common/validator/validator.go +136 -0
  365. package/dist/resources/templates/go-backend/internal/common/validator/validator_test.go +240 -0
  366. package/dist/resources/templates/go-backend/internal/common/youtubeapi/client.go +224 -0
  367. package/dist/resources/templates/go-backend/internal/core/apicontract/document.go +269 -0
  368. package/dist/resources/templates/go-backend/internal/core/apicontract/document_test.go +104 -0
  369. package/dist/resources/templates/go-backend/internal/core/apicontract/route_validator.go +78 -0
  370. package/dist/resources/templates/go-backend/internal/core/apicontract/route_validator_test.go +108 -0
  371. package/dist/resources/templates/go-backend/internal/core/apidocs/assets/scalar-api-reference.js +2385 -0
  372. package/dist/resources/templates/go-backend/internal/core/apidocs/assets/scalar-api-reference.metadata.json +10 -0
  373. package/dist/resources/templates/go-backend/internal/core/apidocs/route.go +107 -0
  374. package/dist/resources/templates/go-backend/internal/core/apidocs/route_test.go +200 -0
  375. package/dist/resources/templates/go-backend/internal/core/apidocs/scalar.go +117 -0
  376. package/dist/resources/templates/go-backend/internal/core/apidocs/scalar_test.go +99 -0
  377. package/dist/resources/templates/go-backend/internal/core/audit/access_log_policy.go +91 -0
  378. package/dist/resources/templates/go-backend/internal/core/audit/access_log_policy_test.go +51 -0
  379. package/dist/resources/templates/go-backend/internal/core/audit/actor_resolver.go +36 -0
  380. package/dist/resources/templates/go-backend/internal/core/audit/constants.go +30 -0
  381. package/dist/resources/templates/go-backend/internal/core/audit/context.go +119 -0
  382. package/dist/resources/templates/go-backend/internal/core/audit/context_test.go +310 -0
  383. package/dist/resources/templates/go-backend/internal/core/audit/dto.go +468 -0
  384. package/dist/resources/templates/go-backend/internal/core/audit/dto_admin.go +172 -0
  385. package/dist/resources/templates/go-backend/internal/core/audit/enum.go +460 -0
  386. package/dist/resources/templates/go-backend/internal/core/audit/enum_test.go +314 -0
  387. package/dist/resources/templates/go-backend/internal/core/audit/errors.go +9 -0
  388. package/dist/resources/templates/go-backend/internal/core/audit/handler.go +568 -0
  389. package/dist/resources/templates/go-backend/internal/core/audit/listener.go +319 -0
  390. package/dist/resources/templates/go-backend/internal/core/audit/listener_test.go +98 -0
  391. package/dist/resources/templates/go-backend/internal/core/audit/middleware.go +669 -0
  392. package/dist/resources/templates/go-backend/internal/core/audit/middleware_test.go +268 -0
  393. package/dist/resources/templates/go-backend/internal/core/audit/model.go +306 -0
  394. package/dist/resources/templates/go-backend/internal/core/audit/partition_job.go +316 -0
  395. package/dist/resources/templates/go-backend/internal/core/audit/ports.go +9 -0
  396. package/dist/resources/templates/go-backend/internal/core/audit/provider.go +30 -0
  397. package/dist/resources/templates/go-backend/internal/core/audit/repository.go +1007 -0
  398. package/dist/resources/templates/go-backend/internal/core/audit/repository_test.go +934 -0
  399. package/dist/resources/templates/go-backend/internal/core/audit/router.go +85 -0
  400. package/dist/resources/templates/go-backend/internal/core/audit/service.go +770 -0
  401. package/dist/resources/templates/go-backend/internal/core/audit/service_test.go +331 -0
  402. package/dist/resources/templates/go-backend/internal/core/audit/vo_admin.go +475 -0
  403. package/dist/resources/templates/go-backend/internal/core/cache/config.go +30 -0
  404. package/dist/resources/templates/go-backend/internal/core/cache/key.go +41 -0
  405. package/dist/resources/templates/go-backend/internal/core/cache/key_test.go +62 -0
  406. package/dist/resources/templates/go-backend/internal/core/cache/l1.go +153 -0
  407. package/dist/resources/templates/go-backend/internal/core/cache/l1_test.go +212 -0
  408. package/dist/resources/templates/go-backend/internal/core/cache/manager.go +278 -0
  409. package/dist/resources/templates/go-backend/internal/core/cache/manager_provider.go +24 -0
  410. package/dist/resources/templates/go-backend/internal/core/cache/metrics.go +126 -0
  411. package/dist/resources/templates/go-backend/internal/core/cache/namespace.go +46 -0
  412. package/dist/resources/templates/go-backend/internal/core/cache/namespace_test.go +90 -0
  413. package/dist/resources/templates/go-backend/internal/core/cache/options.go +39 -0
  414. package/dist/resources/templates/go-backend/internal/core/cache/options_test.go +96 -0
  415. package/dist/resources/templates/go-backend/internal/core/cache/redis.go +311 -0
  416. package/dist/resources/templates/go-backend/internal/core/cache/redis_test.go +51 -0
  417. package/dist/resources/templates/go-backend/internal/core/cache/serializer.go +31 -0
  418. package/dist/resources/templates/go-backend/internal/core/cache/serializer_test.go +139 -0
  419. package/dist/resources/templates/go-backend/internal/core/cache/singleflight.go +53 -0
  420. package/dist/resources/templates/go-backend/internal/core/cache/singleflight_test.go +211 -0
  421. package/dist/resources/templates/go-backend/internal/core/cache/warming.go +86 -0
  422. package/dist/resources/templates/go-backend/internal/core/clock/clock.go +66 -0
  423. package/dist/resources/templates/go-backend/internal/core/clock/clock_test.go +26 -0
  424. package/dist/resources/templates/go-backend/internal/core/clock/runtime_clock.go +283 -0
  425. package/dist/resources/templates/go-backend/internal/core/clock/runtime_clock_test.go +98 -0
  426. package/dist/resources/templates/go-backend/internal/core/commandreplay/errors.go +6 -0
  427. package/dist/resources/templates/go-backend/internal/core/commandreplay/model.go +90 -0
  428. package/dist/resources/templates/go-backend/internal/core/commandreplay/model_test.go +79 -0
  429. package/dist/resources/templates/go-backend/internal/core/commandreplay/namespace.go +7 -0
  430. package/dist/resources/templates/go-backend/internal/core/commandreplay/persistence.go +269 -0
  431. package/dist/resources/templates/go-backend/internal/core/commandreplay/persistence_test.go +185 -0
  432. package/dist/resources/templates/go-backend/internal/core/commandreplay/provider.go +9 -0
  433. package/dist/resources/templates/go-backend/internal/core/commandreplay/repository.go +22 -0
  434. package/dist/resources/templates/go-backend/internal/core/commandreplay/service.go +853 -0
  435. package/dist/resources/templates/go-backend/internal/core/commandreplay/service_persistence_test.go +432 -0
  436. package/dist/resources/templates/go-backend/internal/core/commandreplay/service_test.go +891 -0
  437. package/dist/resources/templates/go-backend/internal/core/commandreplay/types.go +121 -0
  438. package/dist/resources/templates/go-backend/internal/core/config/config.go +2069 -0
  439. package/dist/resources/templates/go-backend/internal/core/config/config_test.go +1122 -0
  440. package/dist/resources/templates/go-backend/internal/core/config/contract/contract_test.go +388 -0
  441. package/dist/resources/templates/go-backend/internal/core/config/contract/docs.go +198 -0
  442. package/dist/resources/templates/go-backend/internal/core/config/contract/verify.go +424 -0
  443. package/dist/resources/templates/go-backend/internal/core/config/enum.go +46 -0
  444. package/dist/resources/templates/go-backend/internal/core/config/metadata.go +717 -0
  445. package/dist/resources/templates/go-backend/internal/core/config/metadata_test.go +228 -0
  446. package/dist/resources/templates/go-backend/internal/core/config/product_admin_config_test.go +210 -0
  447. package/dist/resources/templates/go-backend/internal/core/crypto/aes_gcm.go +111 -0
  448. package/dist/resources/templates/go-backend/internal/core/crypto/aes_gcm_test.go +364 -0
  449. package/dist/resources/templates/go-backend/internal/core/crypto/encryptor.go +12 -0
  450. package/dist/resources/templates/go-backend/internal/core/crypto/envelope_encryptor.go +134 -0
  451. package/dist/resources/templates/go-backend/internal/core/crypto/envelope_encryptor_test.go +118 -0
  452. package/dist/resources/templates/go-backend/internal/core/crypto/pem.go +112 -0
  453. package/dist/resources/templates/go-backend/internal/core/crypto/pem_test.go +44 -0
  454. package/dist/resources/templates/go-backend/internal/core/crypto/provider.go +130 -0
  455. package/dist/resources/templates/go-backend/internal/core/crypto/provider_test.go +92 -0
  456. package/dist/resources/templates/go-backend/internal/core/database/base_model.go +24 -0
  457. package/dist/resources/templates/go-backend/internal/core/database/clickhouse.go +121 -0
  458. package/dist/resources/templates/go-backend/internal/core/database/database.go +112 -0
  459. package/dist/resources/templates/go-backend/internal/core/database/database_logger_test.go +95 -0
  460. package/dist/resources/templates/go-backend/internal/core/database/errors.go +25 -0
  461. package/dist/resources/templates/go-backend/internal/core/database/metrics_plugin.go +105 -0
  462. package/dist/resources/templates/go-backend/internal/core/database/pool_collector.go +71 -0
  463. package/dist/resources/templates/go-backend/internal/core/database/read_replica.go +520 -0
  464. package/dist/resources/templates/go-backend/internal/core/database/transaction.go +170 -0
  465. package/dist/resources/templates/go-backend/internal/core/database/transaction_test.go +282 -0
  466. package/dist/resources/templates/go-backend/internal/core/distlock/lock.go +353 -0
  467. package/dist/resources/templates/go-backend/internal/core/distlock/lock_test.go +106 -0
  468. package/dist/resources/templates/go-backend/internal/core/errors/handler.go +189 -0
  469. package/dist/resources/templates/go-backend/internal/core/errors/handler_test.go +515 -0
  470. package/dist/resources/templates/go-backend/internal/core/eventbus/eventbus.go +667 -0
  471. package/dist/resources/templates/go-backend/internal/core/eventbus/eventbus_test.go +792 -0
  472. package/dist/resources/templates/go-backend/internal/core/eventstream/noop.go +22 -0
  473. package/dist/resources/templates/go-backend/internal/core/eventstream/provider.go +20 -0
  474. package/dist/resources/templates/go-backend/internal/core/eventstream/publisher.go +38 -0
  475. package/dist/resources/templates/go-backend/internal/core/eventstream/redis.go +109 -0
  476. package/dist/resources/templates/go-backend/internal/core/eventstream/routing.go +104 -0
  477. package/dist/resources/templates/go-backend/internal/core/eventstream/routing_test.go +71 -0
  478. package/dist/resources/templates/go-backend/internal/core/geoip/model.go +19 -0
  479. package/dist/resources/templates/go-backend/internal/core/geoip/service.go +88 -0
  480. package/dist/resources/templates/go-backend/internal/core/health/health.go +333 -0
  481. package/dist/resources/templates/go-backend/internal/core/health/health_test.go +27 -0
  482. package/dist/resources/templates/go-backend/internal/core/httpclient/client.go +772 -0
  483. package/dist/resources/templates/go-backend/internal/core/httpclient/client_test.go +287 -0
  484. package/dist/resources/templates/go-backend/internal/core/httpclient/download.go +578 -0
  485. package/dist/resources/templates/go-backend/internal/core/httpclient/download_test.go +374 -0
  486. package/dist/resources/templates/go-backend/internal/core/jwtkeyring/jwk.go +38 -0
  487. package/dist/resources/templates/go-backend/internal/core/jwtkeyring/keyring.go +144 -0
  488. package/dist/resources/templates/go-backend/internal/core/jwtkeyring/keyring_test.go +128 -0
  489. package/dist/resources/templates/go-backend/internal/core/jwtkeyring/registry.go +60 -0
  490. package/dist/resources/templates/go-backend/internal/core/logger/logger.go +53 -0
  491. package/dist/resources/templates/go-backend/internal/core/logger/logger_test.go +194 -0
  492. package/dist/resources/templates/go-backend/internal/core/observability/metrics.go +358 -0
  493. package/dist/resources/templates/go-backend/internal/core/observability/sentry.go +445 -0
  494. package/dist/resources/templates/go-backend/internal/core/observability/sentry_privacy_test.go +175 -0
  495. package/dist/resources/templates/go-backend/internal/core/observability/tracing.go +187 -0
  496. package/dist/resources/templates/go-backend/internal/core/outbox/model.go +314 -0
  497. package/dist/resources/templates/go-backend/internal/core/outbox/model_test.go +77 -0
  498. package/dist/resources/templates/go-backend/internal/core/outbox/persistence.go +51 -0
  499. package/dist/resources/templates/go-backend/internal/core/outbox/provider.go +23 -0
  500. package/dist/resources/templates/go-backend/internal/core/outbox/relay.go +1138 -0
  501. package/dist/resources/templates/go-backend/internal/core/outbox/relay_postgres_test.go +257 -0
  502. package/dist/resources/templates/go-backend/internal/core/outbox/relay_test.go +690 -0
  503. package/dist/resources/templates/go-backend/internal/core/outbox/rescheduler.go +164 -0
  504. package/dist/resources/templates/go-backend/internal/core/outbox/rescheduler_test.go +209 -0
  505. package/dist/resources/templates/go-backend/internal/core/outbox/writer.go +249 -0
  506. package/dist/resources/templates/go-backend/internal/core/outbox/writer_postgres_test.go +170 -0
  507. package/dist/resources/templates/go-backend/internal/core/outbox/writer_test.go +123 -0
  508. package/dist/resources/templates/go-backend/internal/core/provider.go +198 -0
  509. package/dist/resources/templates/go-backend/internal/core/queue/metrics_middleware.go +38 -0
  510. package/dist/resources/templates/go-backend/internal/core/queue/metrics_middleware_test.go +12 -0
  511. package/dist/resources/templates/go-backend/internal/core/queue/queue.go +288 -0
  512. package/dist/resources/templates/go-backend/internal/core/queue/queue_test.go +159 -0
  513. package/dist/resources/templates/go-backend/internal/core/resilience/bulkhead.go +514 -0
  514. package/dist/resources/templates/go-backend/internal/core/resilience/bulkhead_test.go +984 -0
  515. package/dist/resources/templates/go-backend/internal/core/resilience/circuitbreaker.go +358 -0
  516. package/dist/resources/templates/go-backend/internal/core/resilience/circuitbreaker_test.go +788 -0
  517. package/dist/resources/templates/go-backend/internal/core/resilience/retry.go +318 -0
  518. package/dist/resources/templates/go-backend/internal/core/resilience/retry_test.go +735 -0
  519. package/dist/resources/templates/go-backend/internal/core/schedule/recorder.go +305 -0
  520. package/dist/resources/templates/go-backend/internal/core/schedule/run_context.go +124 -0
  521. package/dist/resources/templates/go-backend/internal/core/schedule/run_context_test.go +85 -0
  522. package/dist/resources/templates/go-backend/internal/core/schedule/scheduler.go +1589 -0
  523. package/dist/resources/templates/go-backend/internal/core/schedule/scheduler_control_test.go +808 -0
  524. package/dist/resources/templates/go-backend/internal/core/storage/oss_provider.go +398 -0
  525. package/dist/resources/templates/go-backend/internal/core/storage/oss_provider_test.go +89 -0
  526. package/dist/resources/templates/go-backend/internal/core/storage/path.go +110 -0
  527. package/dist/resources/templates/go-backend/internal/core/storage/path_test.go +301 -0
  528. package/dist/resources/templates/go-backend/internal/core/storage/s3_provider.go +489 -0
  529. package/dist/resources/templates/go-backend/internal/core/storage/s3_provider_test.go +60 -0
  530. package/dist/resources/templates/go-backend/internal/core/storage/storage.go +268 -0
  531. package/dist/resources/templates/go-backend/internal/core/storage/validation.go +225 -0
  532. package/dist/resources/templates/go-backend/internal/core/storage/validation_test.go +495 -0
  533. package/dist/resources/templates/go-backend/internal/core/temporal/logger.go +38 -0
  534. package/dist/resources/templates/go-backend/internal/core/temporal/provider.go +126 -0
  535. package/dist/resources/templates/go-backend/internal/core/temporal/provider_test.go +67 -0
  536. package/dist/resources/templates/go-backend/internal/core/websocket/client.go +282 -0
  537. package/dist/resources/templates/go-backend/internal/core/websocket/client_test.go +81 -0
  538. package/dist/resources/templates/go-backend/internal/core/websocket/config.go +58 -0
  539. package/dist/resources/templates/go-backend/internal/core/websocket/handler.go +53 -0
  540. package/dist/resources/templates/go-backend/internal/core/websocket/hub.go +269 -0
  541. package/dist/resources/templates/go-backend/internal/core/websocket/message.go +273 -0
  542. package/dist/resources/templates/go-backend/internal/core/websocket/notifier.go +92 -0
  543. package/dist/resources/templates/go-backend/internal/core/websocket/provider.go +33 -0
  544. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/action.go +77 -0
  545. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/action_test.go +238 -0
  546. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/condition.go +107 -0
  547. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/decision.go +256 -0
  548. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/enum.go +643 -0
  549. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/errors.go +102 -0
  550. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/principal_record.go +21 -0
  551. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/product_context.go +486 -0
  552. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/resource.go +215 -0
  553. package/dist/resources/templates/go-backend/internal/integrations/onex/iam/resource_test.go +242 -0
  554. package/dist/resources/templates/go-backend/internal/products/README.md +5 -0
  555. package/dist/resources/templates/go-backend/internal/sharedevents/README.md +5 -0
  556. package/dist/resources/templates/go-backend/migrations/000001_infrastructure.down.sql +13 -0
  557. package/dist/resources/templates/go-backend/migrations/000001_infrastructure.up.sql +886 -0
  558. package/dist/resources/templates/go-backend/pkg/apierror/error.go +327 -0
  559. package/dist/resources/templates/go-backend/pkg/apierror/error_code.go +65 -0
  560. package/dist/resources/templates/go-backend/pkg/apierror/error_test.go +41 -0
  561. package/dist/resources/templates/go-backend/pkg/apierror/error_type.go +14 -0
  562. package/dist/resources/templates/go-backend/pkg/apierror/http_response.go +216 -0
  563. package/dist/resources/templates/go-backend/pkg/apierror/http_response_test.go +216 -0
  564. package/dist/resources/templates/go-backend/scripts/check-openapi-clean-deletion.sh +54 -0
  565. package/dist/resources/templates/go-backend/scripts/test-migrations.sh +32 -0
  566. package/dist/resources/templates/go-backend/tests/infrastructure.sql +69 -0
  567. package/dist/resources/templates/mcp-server/.claude/docs/stack.md +338 -0
  568. package/dist/resources/templates/mcp-server/.editorconfig +13 -0
  569. package/dist/resources/templates/mcp-server/.env.example +8 -0
  570. package/dist/resources/templates/mcp-server/.github/ISSUE_TEMPLATE/bug_report.yml +104 -0
  571. package/dist/resources/templates/mcp-server/.github/ISSUE_TEMPLATE/feature_request.yml +54 -0
  572. package/dist/resources/templates/mcp-server/.github/PULL_REQUEST_TEMPLATE.md +36 -0
  573. package/dist/resources/templates/mcp-server/.github/workflows/ci.yml +78 -0
  574. package/dist/resources/templates/mcp-server/.husky/commit-msg +1 -0
  575. package/dist/resources/templates/mcp-server/.husky/pre-commit +1 -0
  576. package/dist/resources/templates/mcp-server/.lintstagedrc.json +4 -0
  577. package/dist/resources/templates/mcp-server/.nvmrc +1 -0
  578. package/dist/resources/templates/mcp-server/.prettierrc +8 -0
  579. package/dist/resources/templates/mcp-server/CONTRIBUTING.md +184 -0
  580. package/dist/resources/templates/mcp-server/Dockerfile +23 -0
  581. package/dist/resources/templates/mcp-server/LICENSE +21 -0
  582. package/dist/resources/templates/mcp-server/README.md +123 -0
  583. package/dist/resources/templates/mcp-server/_gitignore +26 -0
  584. package/dist/resources/templates/mcp-server/commitlint.config.js +24 -0
  585. package/dist/resources/templates/mcp-server/eslint.config.js +30 -0
  586. package/dist/resources/templates/mcp-server/package.json +72 -0
  587. package/dist/resources/templates/mcp-server/src/index.ts +27 -0
  588. package/dist/resources/templates/mcp-server/src/resources.ts +33 -0
  589. package/dist/resources/templates/mcp-server/src/services/.gitkeep +0 -0
  590. package/dist/resources/templates/mcp-server/src/tools.ts +43 -0
  591. package/dist/resources/templates/mcp-server/src/types/index.ts +19 -0
  592. package/dist/resources/templates/mcp-server/src/utils/index.ts +31 -0
  593. package/dist/resources/templates/mcp-server/tsconfig.json +22 -0
  594. package/dist/resources/templates/mcp-server/tsup.config.ts +14 -0
  595. package/dist/resources/templates/mcp-server/vitest.config.ts +15 -0
  596. package/dist/resources/templates/nuxt/.claude/docs/stack.md +666 -0
  597. package/dist/resources/templates/nuxt/.editorconfig +15 -0
  598. package/dist/resources/templates/nuxt/.env.example +22 -0
  599. package/dist/resources/templates/nuxt/.github/workflows/ci.yml +34 -0
  600. package/dist/resources/templates/nuxt/.husky/commit-msg +1 -0
  601. package/dist/resources/templates/nuxt/.husky/pre-commit +1 -0
  602. package/dist/resources/templates/nuxt/.nvmrc +1 -0
  603. package/dist/resources/templates/nuxt/.prettierignore +9 -0
  604. package/dist/resources/templates/nuxt/.prettierrc +1 -0
  605. package/dist/resources/templates/nuxt/README.md +23 -0
  606. package/dist/resources/templates/nuxt/_gitignore +7 -0
  607. package/dist/resources/templates/nuxt/app/app.config.ts +105 -0
  608. package/dist/resources/templates/nuxt/app/i18n/locales/en.json +5 -0
  609. package/dist/resources/templates/nuxt/app/pages/app/index.vue +224 -0
  610. package/dist/resources/templates/nuxt/app/pages/authors/[slug].vue +37 -0
  611. package/dist/resources/templates/nuxt/app/pages/blog/[slug].vue +55 -0
  612. package/dist/resources/templates/nuxt/app/pages/blog/category/[category].vue +38 -0
  613. package/dist/resources/templates/nuxt/app/pages/blog/index.vue +46 -0
  614. package/dist/resources/templates/nuxt/app/pages/index.vue +626 -0
  615. package/dist/resources/templates/nuxt/app/pages/legal/privacy.vue +21 -0
  616. package/dist/resources/templates/nuxt/app/pages/legal/terms.vue +21 -0
  617. package/dist/resources/templates/nuxt/app/pages/ui/index.vue +397 -0
  618. package/dist/resources/templates/nuxt/commitlint.config.mjs +1 -0
  619. package/dist/resources/templates/nuxt/eslint.config.mjs +4 -0
  620. package/dist/resources/templates/nuxt/lint-staged.config.mjs +8 -0
  621. package/dist/resources/templates/nuxt/nuxt.config.ts +71 -0
  622. package/dist/resources/templates/nuxt/package.json +67 -0
  623. package/dist/resources/templates/nuxt/public/apple-touch-icon.png +0 -0
  624. package/dist/resources/templates/nuxt/public/favicon.ico +0 -0
  625. package/dist/resources/templates/nuxt/public/favicon.svg +5 -0
  626. package/dist/resources/templates/nuxt/public/icon-16x16.png +0 -0
  627. package/dist/resources/templates/nuxt/public/icon-192x192.png +0 -0
  628. package/dist/resources/templates/nuxt/public/icon-32x32.png +0 -0
  629. package/dist/resources/templates/nuxt/public/icon-512x512.png +0 -0
  630. package/dist/resources/templates/nuxt/public/logo.svg +6 -0
  631. package/dist/resources/templates/nuxt/public/media/hero-product-gallery.png +0 -0
  632. package/dist/resources/templates/nuxt/server/api/content/sitemap-urls.get.ts +12 -0
  633. package/dist/resources/templates/nuxt/server/api/preview.get.ts +9 -0
  634. package/dist/resources/templates/nuxt/stylelint.config.mjs +3 -0
  635. package/dist/resources/templates/nuxt/test/e2e/rendering.test.ts +13 -0
  636. package/dist/resources/templates/nuxt/tsconfig.json +3 -0
  637. package/dist/resources/templates/nuxt/vitest.config.ts +8 -0
  638. package/package.json +8 -5
@@ -0,0 +1,1139 @@
1
+ # {{projectName}} Backend
2
+
3
+ > **适用范围**:本文件完整继承 OneX Go 工程标准。产品后端的运行入口为 `cmd/product-api` 和 `cmd/worker`;平台 Identity、IAM、交易、Viewer、产品注册表及其服务拓扑属于上游 OneX。文中的平台模块、表、路由和运维命令按该所有者解释,不表示本仓库重新实现平台业务。通用编码、安全、事务、审计、事件、契约、测试规则均适用于本仓库。具体运行命令以本仓库 `Makefile` 为准,平台专属质量门禁在 OneX 执行。
4
+ > **规则优先级**:用户明确范围与语义影响分级优先;审计路径遵循本文 Audit 的事件信封或请求上下文二选一,不产生重复记录。
5
+ > **来源**:`docs/standards-provenance.json` 记录原文版本、完整性和逐项适配。
6
+
7
+
8
+ > **Stack**: Go 1.24 | Gin | GORM | PostgreSQL 16 | Redis 7.0 | Asynq
9
+ > **Architecture**: Full-stack Monorepo (backend/ + frontend/ + admin/) — 无自建网关,使用 APISIX
10
+ > **Products**: Multi-product platform architecture (unified platform API + external product BFFs routed by APISIX)
11
+
12
+ ---
13
+
14
+ ## Product Backend Commands
15
+
16
+ Run in the generated backend directory:
17
+
18
+ ```bash
19
+ make build
20
+ make test
21
+ make test-cov
22
+ make test-race
23
+ make lint
24
+ make wire
25
+ make run-api
26
+ make run-worker
27
+ make migrate-up
28
+ make migrate-down
29
+ make migrate-create name=create_resource
30
+ make migrate-version
31
+ make docker-dev
32
+ make docker-down
33
+ make openapi-install
34
+ make openapi-generate
35
+ make openapi-check
36
+ make openapi-test
37
+ make openapi-sdk
38
+ make openapi-breaking
39
+ make openapi-conformance
40
+ make openapi-clean-deletion
41
+ make test-migrations
42
+ make check
43
+ ```
44
+
45
+ ## Upstream Platform Commands
46
+
47
+ > 所有 `make` 命令在 `backend/` 目录下执行。
48
+
49
+ ```bash
50
+ # Development (run from backend/)
51
+ make run-platform # Platform API (:3002)
52
+ make run-worker # Worker (daemon)
53
+ make docker-dev # Docker 全栈开发环境(Air 热重载,不需要手动 rebuild)
54
+ make docker-down # 停止 Docker 开发环境
55
+
56
+ # Build (run from backend/)
57
+ make build # 构建全部 cmd/
58
+ make build-platform # 构建 Platform API
59
+ make build-worker # 构建 Worker
60
+
61
+ # Database (run from backend/)
62
+ make migrate-up # 执行 golang-migrate 迁移
63
+ make migrate-down # 回滚上次迁移
64
+ make migrate-create name=xxx # 创建新迁移文件
65
+
66
+ # Quality (run from backend/)
67
+ make lint # golangci-lint run
68
+ make test # go test ./...
69
+ make test-cov # 覆盖率
70
+ make test-e2e # E2E 测试
71
+
72
+ # Code Generation (run from backend/)
73
+ make generate # 生成 Wire 与 OpenAPI 制品
74
+ make openapi-generate # 生成 OpenAPI 投影与运行时制品
75
+ make openapi-check # 校验契约、确定性与 tracked 制品
76
+ make openapi-breaking # 校验受保护基线与外部承诺兼容性
77
+ make wire # 生成 Wire 依赖注入代码
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Upstream Platform Project Structure
83
+
84
+ ```
85
+ backend/ # Go 后端服务
86
+ cmd/
87
+ platform-api/ # 统一平台服务 (:3002) - Identity + Commerce + Credit + Quota
88
+ admin-api/ # Admin BFF (:3003) - 管理后台路由
89
+ worker/ # 后台任务 (Asynq consumer)
90
+ internal/
91
+ core/ # 基础设施
92
+ config/ database/ cache/ logger/ errors/ # 基础: 配置/DB/缓存/日志/错误
93
+ eventbus/ queue/ httpclient/ # 通信: 事件总线/队列/HTTP
94
+ health/ schedule/ observability/ # 运维: 健康检查/定时/可观测性
95
+ resilience/ distlock/ # 弹性: 熔断重试/分布式锁
96
+ common/ # 通用工具
97
+ middleware/ response/ validator/ types/ bffadapter/
98
+ platform/ # 平台领域
99
+ identity/ # 认证 (JWT + OAuth2)
100
+ user/ # 用户管理
101
+ notification/ # 通知系统
102
+ tenant/ # 租户管理
103
+ sharedevents/ # 跨模块事件契约
104
+ pkg/
105
+ apierror/ # 可导出的 API 错误定义
106
+ migrations/ # SQL 迁移文件 (golang-migrate)
107
+ configs/ # 配置文件 (YAML)
108
+ deployments/ # Docker Compose / K8s
109
+ frontend/ # 前端应用 (planned)
110
+ admin/ # 管理后台 (planned)
111
+ ```
112
+
113
+ 产品业务代码、产品 BFF 和产品专属数据模型位于独立产品仓库,不属于 OneX `backend/internal/`。
114
+
115
+ ---
116
+
117
+ ## Import Path
118
+
119
+ ```
120
+ module: {{module}}
121
+
122
+ {{module}}/internal/core/config
123
+ {{module}}/internal/core/database
124
+ github.com/onex-platform/backend/internal/platform/identity
125
+ {{module}}/pkg/apierror
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Key Patterns
131
+
132
+ - **APISIX Gateway**: 外部网关处理路由/限流/认证插件,Go 服务不自建网关
133
+ - **EventBus**: 进程内事件总线,跨模块通信解耦业务逻辑
134
+ - **Google Wire**: 编译时依赖注入,显式依赖图
135
+ - **Zap**: 结构化日志,高性能
136
+ - **GORM**: ORM,Entity 与 Response VO 严格分离
137
+
138
+ ---
139
+
140
+ ## Upstream Platform Environment Variables
141
+
142
+ ```bash
143
+ DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USERNAME, DATABASE_PASSWORD
144
+ REDIS_HOST, REDIS_PORT, REDIS_PASSWORD
145
+ IDENTITY_ACCESS_TOKEN_ISSUER, IDENTITY_ACCESS_TOKEN_SIGNING_KEY_ID
146
+ IDENTITY_ACCESS_TOKEN_PRIVATE_KEY_PATH, IDENTITY_ACCESS_TOKEN_PUBLIC_KEY_DIRECTORY
147
+ IDENTITY_OAUTH_STATE_SIGNING_SECRET, IDENTITY_PHONE_HASH_KEY
148
+ OPENAI_API_KEY, OPENAI_BASE_URL
149
+ ANTHROPIC_API_KEY
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Code Rules Reference
155
+
156
+ 规范模板在 `backend/.claude/docs/` 目录中。
157
+
158
+ ---
159
+ ---
160
+
161
+ # AI Execution Standard & Coding Rules
162
+
163
+ > Part 1: AI Execution Flow (Phase 1–5) — mandatory workflow for every task
164
+ > Part 2: Coding Rules — project standards and forbidden patterns
165
+
166
+ ---
167
+
168
+ ## Phase 1: Understand
169
+
170
+ Before touching any code, fully understand the task and its context.
171
+
172
+ ### 1.1 Read project documentation
173
+
174
+ 1. Read this file (execution flow + coding rules)
175
+ 2. Read `backend/.claude/docs/` specifications relevant to the task (api-design, module-standards, database, error-handling, etc.)
176
+ 3. Read existing architecture docs in `docs/platform/` for affected modules
177
+ 4. Read the CLAUDE.md of each affected cmd/ app if applicable
178
+
179
+ **Read the specs BEFORE designing. Do not rely on memory or assumptions about project conventions.**
180
+
181
+ ### 1.2 Scope the impact
182
+
183
+ For each task, answer:
184
+
185
+ - Which modules are affected?
186
+ - Which database tables are affected?
187
+ - Which API endpoints are affected?
188
+ - Does data cross a module boundary?
189
+ - Does this affect Wire dependency graph? Which cmd/ apps need regeneration?
190
+
191
+ ### 1.3 Read all affected source files
192
+
193
+ Read every file that will be modified. Understand:
194
+
195
+ - Current function signatures and parameter types
196
+ - Current data structures and their behavior
197
+ - Current data flow: request → handler → service → repository → response
198
+ - Existing patterns and conventions in the file
199
+
200
+ **DO NOT modify any file you have not read in this session. DO NOT assume what code looks like from memory.**
201
+
202
+ ---
203
+
204
+ ## Phase 2: Design
205
+
206
+ Design the solution BEFORE writing any code. This is the most important phase.
207
+
208
+ ### 2.1 Research industry standards (MANDATORY)
209
+
210
+ **Before proposing ANY design, MUST first research industry best practices. This is NOT optional, NOT skippable.**
211
+
212
+ For every design decision, search and answer: "How does {industry leader} solve this exact problem?"
213
+
214
+ - Domain modeling → How do Stripe/Shopify/AWS model this entity?
215
+ - API design → How do Stripe API, GitHub API, Slack API handle this?
216
+ - Architecture pattern → How do large-scale Go projects structure this?
217
+ - State management → How do mature platforms handle this lifecycle?
218
+
219
+ **Research output MUST appear as a concrete table in the design document:**
220
+
221
+ ```markdown
222
+ | Decision Point | Industry Pattern | Used By | Our Choice | Rationale |
223
+ |---------------|-----------------|---------|------------|-----------|
224
+ ```
225
+
226
+ Missing this table = design is incomplete = FORBIDDEN to implement.
227
+
228
+ **Refactoring / rewriting rule**: Do NOT propose removing, replacing, or rewriting existing architecture until you have analyzed what the current design was trying to do and how industry leaders solve the same problem. "This code looks wrong" is not sufficient justification — you must prove the alternative is the industry-accepted approach.
229
+
230
+ ### 2.2 Define the target state
231
+
232
+ For each area the task touches, write out the exact desired end state. The design must include concrete code architecture, not just a list of changes.
233
+
234
+ Required for any design that touches code structure:
235
+
236
+ - **Entity / Model**: struct fields, behavior methods (signature + purpose), state machine transitions
237
+ - **Interface**: method signatures, which package defines it, which package implements it
238
+ - **API contract**: endpoint, method, request DTO fields, response VO fields, status codes
239
+ - **Database**: column name, type, nullable, default, comment — for every new/changed column
240
+ - **Data flow**: for every new field, trace: Source → DTO → Service → Repository → Entity → VO → Response
241
+ - **Directory structure**: which files go where, why this tier (Full DDD / Simplified / Flat)
242
+
243
+ **Be concrete, not vague.** "Add a status field" is insufficient. "Add `status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '订单状态'`, with transition map in `enum.go`, behavior methods `IsCancellable()` and `TransitionTo()` on model" is correct.
244
+
245
+ **Design the code architecture in the plan, not during implementation.** Implementation should be filling in a decided design, not making architecture decisions on the fly.
246
+
247
+ ### 2.3 Validate the design
248
+
249
+ **Patch vs Design check**: Before proposing any fix, ask: "Am I fixing this in the ONE place that owns this responsibility, or am I adding a workaround somewhere else?" If the answer is workaround, find the right place first.
250
+
251
+ Check every design decision against the FORBIDDEN Patterns table and coding rules in this file. If any check fails, revise the design before proceeding.
252
+
253
+ For refactoring or major changes, validate each decision:
254
+
255
+ ```
256
+ Decision: {what you propose}
257
+ Principle: {which rule says the current state is wrong}
258
+ Evidence: {measurable proof — line count, grep count, constructor count}
259
+ Risk: {what could go wrong}
260
+ Mitigation: {how to handle the risk}
261
+ Verdict: PROCEED / REJECT / REVISE
262
+ ```
263
+
264
+ ### 2.4 Determine design document level
265
+
266
+ Classify the task and produce the corresponding design document. See `.claude/docs/architecture-template.md` for full skeleton.
267
+
268
+ ```
269
+ New module or major architecture change?
270
+ → Level A: full architecture document (all mandatory sections)
271
+
272
+ Touch 3+ files, or change schema/API?
273
+ → Level B: focused design document
274
+
275
+ Otherwise?
276
+ → Level C: fix design
277
+ ```
278
+
279
+ | Level | What to produce | Destination |
280
+ |-------|----------------|-------------|
281
+ | **A** | Complete architecture document following `.claude/docs/architecture-template.md` | Plan file → archive to `docs/platform/` |
282
+ | **B** | Impact scope, industry reference, schema/model/API changes, data flow, implementation waves | Plan file |
283
+ | **C** | Root cause analysis, fix design, affected files, verification plan | Plan file |
284
+
285
+ **Every section must be concrete.** Column/Type/Nullable/Default/Comment for every DB field. Method signature, parameters, return type, business rule for every method.
286
+
287
+ ### 2.5 Decision Autonomy
288
+
289
+ **Inherited from `CLAUDE.md` Phase 2.2.** AI MUST make standard technical decisions autonomously when industry consensus exists. NEVER ask the user to choose between options that have a clear industry-standard answer.
290
+
291
+ Go-specific autonomous decisions (NEVER ask):
292
+
293
+ - Repository pattern vs direct DB → Repository (Go DDD standard)
294
+ - Table-driven tests vs individual → Table-driven (Go standard)
295
+ - `context.Context` as first param → Yes (Go standard)
296
+ - Error wrapping style → `fmt.Errorf("operation: %w", err)` (Go 1.13+ standard)
297
+ - Struct validation → `binding` tags on DTO, behavior methods on model (project convention)
298
+ - Module tier selection → Apply the tier decision flow in this file, do NOT ask user
299
+
300
+ ### 2.6 Self-Review Gate (MANDATORY)
301
+
302
+ **Inherited from `CLAUDE.md` Phase 2.6.** After completing ANY design or implementation, MUST self-review BEFORE presenting to user.
303
+
304
+ Go-specific self-review additions:
305
+
306
+ 1. Does every new/changed struct field trace through the full data flow? (DTO → Service → Entity → VO)
307
+ 2. Does Wire dependency graph remain acyclic?
308
+ 3. Are all new exported types documented with GoDoc (Chinese)?
309
+ 4. Does every handler call only Service methods (A1/A2 compliance)?
310
+ 5. Does every write Service method carry DomainEvent audit fields or call `audit.Enrich()` when no event is published (AU1 compliance)?
311
+
312
+ ### 2.7 Present design for approval
313
+
314
+ **Approval gate applies ONLY to Level A designs (new modules, major architecture changes).**
315
+
316
+ Level B/C: present design summary, proceed to implementation immediately.
317
+
318
+ ---
319
+
320
+ ## Phase 3: Plan
321
+
322
+ After design passes self-review (and user approval for Level A), create the implementation plan.
323
+
324
+ ### 3.1 List all file modifications
325
+
326
+ For each file: exact path, what function/section to change, what the change is.
327
+
328
+ ### 3.2 Map dependencies
329
+
330
+ Determine which changes depend on which others. A change depends on another if it imports, references, or extends something defined in the other.
331
+
332
+ ### 3.3 Group into dependency waves
333
+
334
+ Group changes so that each wave only depends on previous waves being complete. Within each wave, independent changes can be executed in parallel.
335
+
336
+ ---
337
+
338
+ ## Phase 4: Implement
339
+
340
+ ### 4.1 Execute wave by wave
341
+
342
+ For each wave:
343
+
344
+ 1. Implement all changes in the wave (parallel if independent)
345
+ 2. After the wave completes, verify types are consistent with previous waves
346
+ 3. Proceed to next wave only when current wave is clean
347
+
348
+ ### 4.2 Read before write (always)
349
+
350
+ Before modifying each file:
351
+
352
+ 1. Read its current content
353
+ 2. Confirm your change is compatible with what is actually there
354
+ 3. Then make the modification
355
+
356
+ ### 4.3 Follow existing patterns
357
+
358
+ When adding code to an existing file, match:
359
+
360
+ - Naming conventions already used in that file
361
+ - Code style and formatting patterns
362
+ - Comment language and level of detail
363
+ - Import organization
364
+
365
+ ---
366
+
367
+ ## Phase 5: Verify
368
+
369
+ ### 5.1 Build
370
+
371
+ ```bash
372
+ go build ./...
373
+ go vet ./...
374
+ make wire # regenerate all affected cmd/
375
+ ```
376
+
377
+ All MUST pass. If any fails, fix and rebuild.
378
+
379
+ ### 5.2 Design conformance check
380
+
381
+ After build passes, verify implementation matches the approved design. Every item in the design document must be implemented. No silent omissions.
382
+
383
+ ### 5.3 Quantitative verification
384
+
385
+ Grep for expected outcomes with concrete numbers. "It compiles" is necessary but not sufficient. Count the things that should exist.
386
+
387
+ ### 5.4 Rule conformance check
388
+
389
+ Re-validate against the FORBIDDEN Patterns table below with the actual implemented code. If any rule is violated, fix before marking complete.
390
+
391
+ ### 5.5 Automated review loop (Level A/B)
392
+
393
+ **Inherited from `CLAUDE.md` Phase 5.5.** For Level A/B deliveries, dispatch review agents and iterate until zero findings BEFORE presenting to user.
394
+
395
+ Go-specific review dimensions:
396
+
397
+ - FORBIDDEN pattern scan (S/A/T/C/H/D/AU/E rules)
398
+ - Wire dependency graph validity
399
+ - Handler → Service → Repository layering compliance
400
+ - Audit enrichment coverage (every write op)
401
+ - Industry standard alignment (compare against cited references)
402
+
403
+ **The user should receive a clean, reviewed deliverable. If the user has to point out "this doesn't follow the Stripe pattern you cited", that is a Phase 5.5 failure.**
404
+
405
+ ---
406
+ ---
407
+
408
+ # Part 2: Coding Rules
409
+
410
+ ---
411
+
412
+ ## Code Separation (CRITICAL)
413
+
414
+ BEFORE writing ANY code, check: does it contain constants, types, enums, request/response structs, or error definitions?
415
+ If YES, place them in the correct file. NEVER inline complex type definitions in handler/service files.
416
+
417
+ | Content | NEVER In | ALWAYS In |
418
+ |---------|----------|-----------|
419
+ | constant / magic number (shared) | service, handler | `{package}/constants.go` 或模块级 `const` 块 |
420
+ | constant (single consumer) | — | co-locate in consumer file as unexported `const` |
421
+ | interface (contract) | infrastructure, handler | 消费方所在 package(Go 惯例:接口由使用者定义) |
422
+ | enum (iota / string const) | service, handler | `{package}/enum.go` |
423
+ | type alias | service, handler | `{package}/types.go` |
424
+ | Request struct (user) | handler | `{package}/dto.go` |
425
+ | Request struct (admin) | handler | `{package}/dto_admin.go` |
426
+ | Response VO (user) | anywhere mixed | `{package}/vo.go` (struct + `ToXxxResponse()`) |
427
+ | Response VO (admin) | anywhere mixed | `{package}/vo_admin.go` (struct + `ToAdminXxxResponse()`) |
428
+ | Error sentinel/type | service | `{package}/errors.go` 或 `pkg/apierror/` |
429
+ | Event payload | service | `internal/sharedevents/events.go` |
430
+ | Pagination params | DTO (inline) | Embed `types.PageParams`, `types.AdminPageParams`, or explicitly justified `types.BulkPageParams` from `common/types` |
431
+
432
+ Go 惯例:相关类型可以按领域分组在同一文件中。例如 `domain/model.go` 可包含同一聚合根的多个 struct。
433
+
434
+ ---
435
+
436
+ ## File Naming
437
+
438
+ MUST use snake_case (Go 标准)。Go 中不使用类型后缀命名文件,而是按职责命名。
439
+
440
+ | 职责 | File Pattern | Type Pattern |
441
+ |------|-------------|--------------|
442
+ | HTTP Handler (user) | `handler.go` | `XxxHandler` struct |
443
+ | HTTP Handler (admin) | `handler_admin.go` | `XxxAdminHandler` struct |
444
+ | Service | `service.go` 或 `{name}_service.go` | `XxxService` struct |
445
+ | Repository 接口 | `repository.go` (in domain/) | `XxxRepository` interface |
446
+ | Repository 实现 | `persistence.go` (in infrastructure/) | `xxxRepository` struct (unexported) |
447
+ | Request DTO (user) | `dto.go` | `CreateXxxRequest`, `UpdateXxxRequest` |
448
+ | Request DTO (admin) | `dto_admin.go` | `AdminCreateXxxRequest`, `AdminListXxxRequest` |
449
+ | Response VO (user) | `vo.go` | `XxxResponse` struct + `ToXxxResponse()` |
450
+ | Response VO (admin) | `vo_admin.go` | `AdminXxxResponse` struct + `ToAdminXxxResponse()` |
451
+ | Domain Model | `model.go` | `Xxx` struct (PascalCase, NO suffix) |
452
+ | Enum | `enum.go` | `XxxStatus` type + `const` iota 或 string |
453
+ | Constants | `constants.go` | `const` 块 |
454
+ | Error | `errors.go` | `ErrXxxNotFound` sentinel 或 `XxxError` type |
455
+ | Event | `events.go` (in sharedevents/) | `XxxEvent` struct |
456
+ | Listener | `listener.go` | `XxxListener` struct |
457
+ | Middleware | `{name}.go` (in middleware/) | `XxxMiddleware()` func |
458
+ | Wire Provider | `wire.go` | `InitializeXxx()` injector |
459
+ | Wire Provider Set | `provider.go` | `ProviderSet = wire.NewSet(...)` |
460
+ | Test | `{name}_test.go` | `TestXxx`, `BenchmarkXxx` |
461
+
462
+ ---
463
+
464
+ ## FORBIDDEN Patterns (CRITICAL)
465
+
466
+ Violation of ANY rule blocks commit. No exceptions.
467
+
468
+ | ID | Cat | Pattern | Fix |
469
+ |----|-----|---------|-----|
470
+ | S1 | Security | Hardcoded secrets in source | Move to config/env, access via `Config` struct |
471
+ | S2 | Security | Dynamic code execution (`reflect` for dispatch) | Use static mapping (map / switch) |
472
+ | S3 | Security | Sensitive data in logs | Log IDs only, NEVER passwords/tokens/PII |
473
+ | S4 | Security | `os.Getenv()` in business code | Use `Config` struct, load once at startup |
474
+ | A1 | Arch | Business logic in handler | Move ALL logic to Service |
475
+ | A2 | Arch | Repository/DB ops in handler | Call Service methods only |
476
+ | A3 | Arch | Direct cross-package type import bypassing interface | Define interface in consumer package |
477
+ | A4 | Arch | Circular package import | Extract shared types to third package |
478
+ | A5 | Arch | Flat directory (all files in `cmd/*/`) | Organize into `internal/` subpackages |
479
+ | A6 | Arch | Silent init failure (swallowed error) | MUST return error, caller decides |
480
+ | A7 | Arch | `init()` with side effects | Explicit initialization in `main()` or Wire |
481
+ | A8 | Arch | Direct `http.ResponseWriter` manipulation in handler | Use Gin context helpers (`c.JSON()`, `c.Status()`) |
482
+ | A11 | Arch | Gateway plugin callback (`forward-auth` / internal auth bridge / similar) directly targeting a single backend node (`http://service:port/...`) | Route through APISIX internal route or shared upstream policy. Gateway-side callbacks MUST NOT bypass upstream health checks, retries, and load-balancing |
483
+ | A12 | Arch | Production public API exposed behind APISIX with single-node upstream or without APISIX health checks | Use multi-node upstreams with active + passive health checks, explicit timeout/retry policy, and keepalive pool. Single-node upstream is allowed only in local dev hot-reload compose |
484
+ | T1 | Type | `interface{}` / `any` without comment | Add concrete type or justification comment |
485
+ | T2 | Type | Type definitions in service file | Move to `model.go`, `dto.go`, `vo.go`, `enum.go` |
486
+ | T3 | Type | Numeric enum without string method | Use `String()` method 或 string const |
487
+ | T4 | Type | Manual singleton (`sync.Once` + global) | Use Wire DI, single instance by construction |
488
+ | T5 | Type | Exported unexported-type method | Keep type/method export level consistent |
489
+ | C1 | Contract | `return entity` from service to handler | Use `return ToXxxResponse(entity)` |
490
+ | C2 | Contract | `{ "code": 200, "data": ... }` wrapper | Return data directly, use HTTP status codes |
491
+ | C3 | Contract | Response struct as request input | Separate Request (dto.go) and Response (vo.go) |
492
+ | C4 | Contract | Chinese in error messages | English ONLY for all error messages |
493
+ | C5 | Contract | Hardcoded numeric error codes | Use string `ErrorCode` const |
494
+ | H1 | Hygiene | `fmt.Println` / `log.Println` | Use `zap.Logger` |
495
+ | H2 | Hygiene | Non-snake_case filename | Rename to `snake_case.go` |
496
+ | H3 | Hygiene | Panic in handler/service | Return error, middleware handles recovery |
497
+ | H4 | Hygiene | Commented-out code | Delete; git has history |
498
+ | H5 | Hygiene | Unused/speculative code (YAGNI) | Delete; write only what is needed NOW |
499
+ | H6 | Hygiene | Exported type from `internal/` that should be unexported | Unexport; only export what other internal packages need |
500
+ | H7 | Hygiene | Naked return in named return function > 5 lines | Use explicit return |
501
+ | H8 | Hygiene | Underscore import `_` without comment | Add `// for side-effect: xxx` comment |
502
+ | A9 | Arch | ANY re-export in `provider.go` (`var NewFoo = sub.NewFoo` or `type X = sub.X`) | `provider.go` ONLY contains `wire.NewSet(...)` and Wire helper functions. ZERO re-exports of any kind. Callers MUST import the actual sub-package directly |
503
+ | A10 | Arch | Handler/Service/Model in module root directory | Business code MUST go into domain/ application/ infrastructure/ subdirectories |
504
+ | D1 | Deferred | `// TODO:` / `// 待后续` / `// 暂跳过` / `// 暂设` / `// 后续实现` in committed code | Either implement completely OR return explicit error. NEVER defer implementation with comments |
505
+ | D2 | Deferred | Fallback branch for "backward compatibility" / "兼容历史数据" | Single code path only. If format changed, migrate data. NEVER add fallback parsing |
506
+ | D3 | Deferred | `// 迁移完成后应移除` / "should be removed after migration" | Remove NOW. Code that "should be removed later" will never be removed |
507
+ | D4 | Deferred | Try-decrypt, if fail try-plaintext pattern | Decrypt or fail. NEVER silently fall back to unencrypted path |
508
+ | D5 | Deferred | Silent skip of unimplemented feature (`// 暂跳过`, empty handler, log-and-return-nil) | Return typed error (`apierror.BadRequest` / `fmt.Errorf`) for unsupported operations. Caller decides |
509
+ | D6 | Deferred | Noop/stub implementation returning `nil, nil` or hardcoded values for production interfaces | Implement fully OR define proper error: `fmt.Errorf("{operation} is not implemented")` |
510
+ | D7 | Deferred | `placeholder` / `stub` / `dummy` / `mock` in non-test production code | Only in `_test.go` files. Production code must be complete |
511
+ | AU1 | Audit | Service write operation missing audit evidence | Set DomainEvent `AuditChanges`, or call `audit.Enrich(ctx, changes, metadata)` after successful write when no event is published; never both |
512
+ | AU2 | Audit | `audit.Enrich()` called on error path (before write succeeds) | Call ONLY after operation **succeeds**, NEVER before error return |
513
+ | AU3 | Audit | `audit.Enrich()` called in Handler | Audit enrichment is business logic, MUST be called in Service layer |
514
+ | E1 | Enforce | Discovered violation deferred with "先不折腾" / "后续再改" / "合理轻量 pattern" | Fix NOW. Rules have zero exceptions. No "thin CRUD exemption" |
515
+ | E2 | Enforce | Code delivered with known violations and a plan to "fix later" | ALL violations MUST be fixed BEFORE delivery. No partial compliance |
516
+ | E3 | Enforce | Fix applied as patch/workaround without proper design thinking | Every fix must be architecturally sound. No band-aids |
517
+ | E4 | Enforce | Discovered bug/violation excluded with "不在本次范围" / "是新功能" | If the scan found it, fix it. Scope is defined by what's broken, not by what you planned to do |
518
+ | E5 | Enforce | Runtime conversion/adapter to "兼容已存数据" when no production data exists | Change the source format directly. Compatibility layers are only for live production data |
519
+ | IS1 | Identity | Backend handler reads business decision state from `c.GetHeader("X-User-Content-*")` / `c.GetHeader("X-User-Tier-*")` / similar plaintext business header injected by gateway | 通过 `principal.MustGet(c)` / `principal.Get(c)` 读取 backend 自己 resolve 的状态。Identity header(X-User-Public-ID/X-Identity-ID/X-Session-ID)仍由 middleware 解析进 ctx,不直接被业务读 |
520
+ | IS2 | Identity | 同一权益 / 决策 concept 暴露 2+ resolve 路径(service / header / wrapper / sidecar)让 handler 自由选择 | One owner per concept:内容访问唯一调 `accessPolicySvc.ResolveContentAccess`;entitlement limit 唯一调 `EntitlementService.GetLimit`。新增功能必须复用现有 service,不得新建并行 reader |
521
+ | IS3 | Reliability | EventBus listener 关键 side-effect(cache invalidate / projection update / outbox dispatch)失败仅 `Warn` 不 `return err` | `return fmt.Errorf("...: %w", err)` — 让 outbox 自动 retry 直至最终一致。模板:`handleSubscriptionEvent` (`listener.go:85-108`) |
522
+ | IS4 | Cache | `cache.Delete(...)` followed by `cache.Set(...)` (race-prone two-step invalidation) | 单次 `cache.Set(...)` 覆盖即可;写入失败 fail-fast。无 Delete 步骤 |
523
+ | IS5 | Gateway | APISIX / 网关注入"非 identity"业务决策 header 给 backend 信任(违反 Stripe / GitHub / AWS 共识) | 网关只注入 identity(X-User-Public-ID/X-Identity-ID/X-Session-ID),并 strip 客户端伪造的同名 header;业务决策(content access / permissions / tier)由 backend middleware 自己 resolve |
524
+ | DB1 | Database | `FOREIGN KEY` constraint in migration | FORBIDDEN. Application layer ensures integrity. FK causes cascade locks, DDL blocking, sharding incompatibility |
525
+ | DB2 | Database | `SELECT *` in queries | ALWAYS specify columns: `Select("id", "name", "email")` |
526
+ | DB3 | Database | Unbounded list query without pagination | ALWAYS paginate. NEVER return all rows |
527
+ | DB4 | Database | Production/DMS SQL uses unverified dialect-sensitive constructs such as `BEGIN`/`COMMIT`, `CROSS JOIN LATERAL (VALUES ...) AS alias(...)`, positional anonymous row output, or multi-statement repair scripts | Use a single PostgreSQL statement compatible with the production SQL runner; validate syntax locally against PostgreSQL before handing it to operators |
528
+ | R1 | Reuse | `gin.H{}` for API list/paginated response | Use `response.NewPaginated()` or `response.NewList()`. Custom structures use VO struct, NEVER build JSON with `gin.H` |
529
+ | R2 | Reuse | `string` type for sort order field | Use `types.SortOrder` from `common/types`. DTO field type + service comparisons MUST use `types.SortOrderASC` / `types.SortOrderDESC` |
530
+ | R3 | Reuse | Inline pagination normalization `if page < 1 { page = 1 }` duplicated | Extract shared helper or use `types.PaginationQuery.Normalize()`. Same logic MUST NOT appear 2+ times in one module |
531
+ | R4 | Reuse | Manual error construction `c.JSON(400, gin.H{"error": ...})` | Use `response.Error(c, apierror.BadRequest(...))` and other `pkg/apierror` constructors |
532
+ | R5 | Reuse | Custom pagination metadata struct (e.g. `PaginationInfo`) | Use `response.PaginationMeta` from `common/response/pagination.go`. NEVER redefine pagination structs |
533
+ | R6 | Reuse | Handler manually parsing `c.Query()` when DTO already defined | Use `c.ShouldBindQuery(&req)` / `c.ShouldBindUri(&req)` to bind existing DTO struct |
534
+ | R7 | Reuse | Handler returning raw `[]T` slice for list endpoint | ALL list endpoints MUST return `response.NewPaginated()` or `response.NewList()`. Service signature: `(items, total, error)`. DTO MUST embed `types.PageParams`, `types.AdminPageParams`, or explicitly justified `types.BulkPageParams` |
535
+ | R8 | Reuse | Repeating in-memory "keyword filter + page slice" helpers inside a module | Reuse `internal/common/utils.FilterAndPaginate()`; the module provides only the matcher. `common/response/pagination.go` owns HTTP response shape only and MUST NOT contain query/filter logic |
536
+ | L1 | Lint | `ALL_CAPS` constant name (e.g. `QUOTA_INSUFFICIENT`) | Use Go CamelCase with `ErrCode` prefix: `ErrCodeQuotaInsufficient`. String VALUE stays ALL_CAPS |
537
+ | L2 | Lint | `err == gorm.ErrRecordNotFound` direct comparison | Use `errors.Is(err, gorm.ErrRecordNotFound)` — supports wrapped errors |
538
+ | L3 | Lint | `for _, item := range largeStructSlice` (copies struct each iteration) | Use `for i := range slice` + `slice[i]` or `item := &slice[i]` |
539
+ | L4 | Lint | `sb.WriteString(fmt.Sprintf(...))` | Use `fmt.Fprintf(sb, ...)` directly |
540
+ | L5 | Lint | Variable name shadows Go builtin (`copy`, `new`, `len`, `max`, `min`) | Rename: `copy` → `taskCopy`, `new` → `current`, `max` → `maxLimit` |
541
+ | L6 | Lint | `http.NewRequest(...)` without context | Use `http.NewRequestWithContext(ctx, ...)` |
542
+ | L7 | Lint | `math/rand` for non-security purposes without `//nolint:gosec` | Add `//nolint:gosec // {reason}` comment explaining why crypto/rand is not needed |
543
+ | I1 | Infra | Inline `Page int` + `PageSize int` in DTO | Embed `types.PageParams` (user), `types.AdminPageParams` (admin max=200), or `types.BulkPageParams` (explicit high-volume read max=1000). NEVER define pagination fields manually |
544
+ | I2 | Infra | Inline `(page-1)*pageSize` offset calculation | Use `.Offset()` from embedded PageParams/AdminPageParams/BulkPageParams/PaginationQuery |
545
+ | I3 | Infra | `gin.H{}` in handler response body | Use VO struct (vo.go) or anonymous struct. gin.H FORBIDDEN in handlers (R1 also covers list responses) |
546
+ | I4 | Infra | `response.ValidationError(c, fmt.Errorf(...))` for missing required params | Use `response.Error(c, apierror.BadRequest(apierror.CodeValidationFailed, "..."))` or add `middleware.RequireProductCode()` at route level |
547
+ | I5 | Infra | `c.Get("key")` to read context values in handler | Use middleware helpers: `middleware.GetUserID(c)`, `middleware.GetProductCode(c)`, etc. |
548
+ | I6 | Infra | DTO-local custom `Normalize()`/`PageOrDefault()` for pagination | DELETE custom methods. Delegate to the shared `PageParams.Normalize()`, `AdminPageParams.Normalize()`, or `BulkPageParams.Normalize()` implementation |
549
+ | I7 | Infra | External list/search HTTP DTO exposes a generic `limit` parameter | Standard pagination MUST use `types.PageParams` / `types.AdminPageParams` / explicitly justified `types.BulkPageParams`; external contracts allow only `page` + `page_size`. `limit` is allowed only as an explicit domain config field (for example `default_limit`, `max_items`), never as a list-query pagination parameter |
550
+ | TX1 | Transaction | `r.db.WithContext(ctx)` in Repository/Persistence | Use `database.GetDB(ctx, r.db)` — ensures transaction participation |
551
+ | TX2 | Transaction | `middleware.WithTransaction` / `middleware.DBOrTx` | Use `database.TransactionManager.WithTransaction` — single mechanism |
552
+ | TX3 | Transaction | Multiple transaction context keys | Single `database.ctxTxKey{}` — one mechanism, one key |
553
+ | N1 | Enum | 管理端展示或选择使用的枚举值、标签、颜色在 registry 外重复维护 | 在 `internal/common/enums/register_xxx.go` 引用 owner 常量注册,并测试实际消费的值集合。私有实现类型和机器协议值不要求注册为管理端选项 |
554
+ | N2 | Reference | `ReferenceID` / `reference_id` 字段用 `fmt.Sprintf` / 字符串拼接 ad-hoc 构造 | 在 owner domain 的 `reference.go` 定义 helper `XxxReferenceID(xxxID int64) string`,调用方 MUST 通过 helper 生成。See `backend/.claude/docs/identifier-contract.md` §3.2 |
555
+ | N3 | Reference | `ReferenceType` 字段使用字符串字面量(e.g. `"order"` / `"subscription"`) | 在 domain 的 `reference.go` 定义 `ReferenceTypeXxx` 常量,所有写入路径 MUST 引用常量 |
556
+ | N4 | Validator | 写入 `p_credit_transactions` / `p_member_point_ledger` / `p_quota_transactions` 时绕过模块的 `ValidateTransactionFields` 直接调用 `db.Create` / `db.Save` | MUST 通过 repo 的 `Create` / `BatchCreate` 方法,repo 内部强制调用 `credit.ValidateTransactionFields`(或对应模块 validator)。禁止 Service/Handler 直接操作 `*gorm.DB` 写入凭证类表 |
557
+ | LC1 | Locale | Domain model, DTO write path, persisted JSON map, or admin API accepts/stores region locale tags such as `zh-CN` / `en-US` as business locale keys | Internal business locale values MUST use OneX short codes validated by `internal/common/locale.IsShortCode`. External headers/imports may call `NormalizeCode` only at boundary adapters before entering domain/service writes |
558
+ | LC2 | Locale | Duplicated supported-locale lists, locale enum metadata, or fallback locale arrays outside `internal/common/locale` / enum registry helpers | Use `commonlocale.SupportedCodes()`, `commonlocale.DefaultCode`, `commonlocale.AdminDefaultCode`, and shared enum helpers. Migrations may list historical external aliases only to repair old data |
559
+ | LC3 | Locale | Localized text/channel JSON validation implemented with ad-hoc key checks or `map[string]string` loops that do not call the common locale validator | Route all localized-map write validation through `commonlocale.IsShortCode` or a module helper that delegates to it. Invalid locale keys fail fast with validation errors |
560
+
561
+ `make lint-enums` / `backend/scripts/check-forbidden-patterns.sh` 运行管理端枚举合同测试及标识符、凭证写入静态检查。详细标识符契约见 `backend/.claude/docs/identifier-contract.md`。
562
+
563
+ ---
564
+
565
+ ## Delivery Discipline (CRITICAL)
566
+
567
+ Every delivery MUST achieve **zero violations** against this spec. There are NO exceptions, NO exemptions, NO deferrals.
568
+
569
+ | Principle | Detail |
570
+ |-----------|--------|
571
+ | **发现即修正** | Found a violation → fix it NOW in the same delivery. Never defer to "next time" |
572
+ | **无豁免条款** | No pattern is "too simple" or "too thin" to follow the rules. CRUD handler still needs Service layer if rules say so |
573
+ | **设计先行** | Every fix must be properly designed, not patched. If a bug fix requires architectural change, do the architectural change |
574
+ | **不存在后续** | "后续如果需要可以提取" = 现在就提取。"后续处理" = 现在处理 |
575
+ | **交付 = 零违规** | Delivery with known violations is a failed delivery, regardless of how "minor" the violation seems |
576
+
577
+ ### Pre-Delivery Checklist
578
+
579
+ BEFORE declaring any task complete, run this mental checklist:
580
+
581
+ 1. All files pass FORBIDDEN patterns table (S/A/T/C/H/D/AU/E rules)
582
+ 2. Handler layer contains ZERO business logic (A1), ZERO repo calls (A2), ZERO audit calls (AU3)
583
+ 3. All write operations in Service carry audit evidence through DomainEvent fields or `audit.Enrich()` (AU1)
584
+ 4. No deferred code markers (D1-D7)
585
+ 5. `go build ./...` passes
586
+ 6. `wire ./cmd/*/` regenerated for all affected cmd directories
587
+ 7. No residual imports from refactored/deleted packages
588
+ 8. All list/search contracts pass pagination validation: DTOs expose no generic `limit`, Handlers return no raw slices, application layer has no duplicated `filter + slice` helpers, and the `response` package contains no filtering/query logic
589
+
590
+ Skipping ANY item = failed delivery.
591
+
592
+ ### Pagination Validation
593
+
594
+ Whenever you modify a list/search endpoint, an options dropdown endpoint, or in-memory application-layer pagination, you MUST validate the pagination contract before delivery:
595
+
596
+ 1. **Parameter layer**
597
+ - DTOs MUST embed `types.PageParams`, `types.AdminPageParams`, or an explicitly justified `types.BulkPageParams`
598
+ - Generic pagination MUST NOT define `limit`
599
+ 2. **Application layer**
600
+ - In-memory filtering + slicing MUST reuse `internal/common/utils.FilterAndPaginate()`
601
+ - The module keeps only the matcher and MUST NOT duplicate a `keyword -> filter -> slice` shell
602
+ 3. **Response layer**
603
+ - List endpoints MUST return `response.NewPaginated()` or `response.NewList()`
604
+ - `internal/common/response/pagination.go` owns response shape only and MUST NOT contain filtering/query logic
605
+
606
+ Recommended pre-delivery checks:
607
+
608
+ ```bash
609
+ rg -n 'form:"limit"|json:"limit"' internal
610
+ rg -n 'response\\.OK\\(c,\\s*items\\)|response\\.OK\\(c,\\s*result\\)' internal
611
+ rg -n 'if .*page < 1|\\(page-1\\)\\*pageSize|slice\\(start, start \\+ pageSize\\)' internal
612
+ ```
613
+
614
+ ---
615
+
616
+ ## Deferred Code Policy (CRITICAL)
617
+
618
+ Every line of committed code MUST be production-ready. There are ZERO exceptions.
619
+
620
+ | Scenario | WRONG | CORRECT |
621
+ |----------|-------|---------|
622
+ | Feature not ready | `// TODO: implement later` | Return `apierror.BadRequest("Feature X is not supported")` |
623
+ | Data format changed | `if newFormat(err) { fallback(oldFormat) }` | Migrate data. Single code path |
624
+ | Encryption bypass | `if decrypt(err) { tryPlaintext() }` | `if decrypt(err) { return err }` |
625
+ | Module not integrated | `// 暂跳过` / empty block | Reject input that requires the module: `return apierror.BadRequest(...)` |
626
+ | Interface not implemented | `return nil, nil` (noop) | `return nil, fmt.Errorf("X is not implemented")` |
627
+ | Partial implementation | Handle case A, `// case B 待后续` | Handle case A, `default: return fmt.Errorf("unsupported: %s", caseType)` |
628
+
629
+ The principle: **fail loudly, never silently skip**. A production system that returns an error is safer than one that silently does nothing.
630
+
631
+ ---
632
+
633
+ ## API Versioning
634
+
635
+ - Full URL pattern: `/api/v{N}/{resource}` (e.g. `/api/v1/users`)
636
+ - Version prefix set in router group: `router.Group("/api/v1")`
637
+ - Handler ONLY registers resource path: `v1.GET("/users", h.List)`, NEVER full path
638
+ - Breaking changes: create v2 route group, keep v1 compatible until clients migrate
639
+
640
+ ---
641
+
642
+ ## API Response Rules
643
+
644
+ | Operation | Status | Body |
645
+ |-----------|--------|------|
646
+ | GET single | 200 | `{ "id": ..., ...fields }` |
647
+ | GET list | 200 | `{ "data": [...], "pagination": {...} }` |
648
+ | POST create | **201** | `{ "id": ..., ...fields }` |
649
+ | PUT/PATCH update | 200 | `{ "id": ..., ...fields }` |
650
+ | DELETE | **204** | Empty body |
651
+ | Error | 4xx/5xx | `{ "error": { "type": "...", "code": "...", "message": "..." } }` |
652
+
653
+ - Request input: struct + `binding` / `validate` tag, 定义在 `dto.go`
654
+ - Response output: struct + `ToXxxResponse()` 转换函数, 定义在 `vo.go`
655
+ - NEVER return Model/Entity directly. ALWAYS transform via `ToXxxResponse()`
656
+ - NEVER use wrapper format `{ "code": 0, "data": ..., "message": "ok" }`
657
+
658
+ ---
659
+
660
+ ## Error Handling
661
+
662
+ ### Flow
663
+
664
+ ```
665
+ Request → Middleware(Auth/Logging/Recovery) → Handler → Service → Repository
666
+ │ (return error)
667
+ Response ← Error Middleware ← ─────────────────── error
668
+ ```
669
+
670
+ - Handler: receives error from service, calls `response.Error(c, err)`. NEVER constructs error response manually
671
+ - Service: returns typed errors (`apierror.NotFound(...)`, `apierror.Business(...)`)
672
+ - Middleware: `Recovery` catches panic, `Auth` returns 401/403
673
+ - Messages: English ONLY. Format: `"{Resource} with {field} {value} not found"`
674
+
675
+ ### Error Decision Table
676
+
677
+ | Scenario | Error Constructor | Status | ErrorCode |
678
+ |----------|------------------|--------|-----------|
679
+ | Resource not found | `apierror.NotFound(...)` | 404 | `resource_not_found` |
680
+ | Duplicate resource | `apierror.Conflict(...)` | 409 | `resource_conflict` |
681
+ | Invalid input | `apierror.BadRequest(...)` / validator | 400 | `invalid_parameters` |
682
+ | No auth / expired token | `apierror.Unauthorized(...)` | 401 | `unauthorized` |
683
+ | No permission | `apierror.Forbidden(...)` | 403 | `forbidden` |
684
+ | Business rule violated | `apierror.Business(code, msg)` | 422 | (domain-specific) |
685
+ | Rate limited | `apierror.TooManyRequests()` | 429 | `rate_limited` |
686
+ | External service failure | `apierror.Internal(...)` | 500 | `internal_error` |
687
+
688
+ ---
689
+
690
+ ## Database Rules
691
+
692
+ - Embed `BaseModel` from `internal/core/database`
693
+ - Column name: `snake_case` (GORM 默认)。Struct field: `PascalCase`
694
+ - ALL columns MUST have `comment` tag (Chinese)
695
+ - Boolean columns: `is_xxx` 命名 + `bool` type
696
+ - Status columns: `varchar(20)` + string const
697
+ - Timestamps: `timestamptz(3)` (毫秒精度)
698
+ - PK: `bigserial`. FK: `bigint`
699
+ - Money: `decimal(19,4)`, 代码中用 `string`
700
+ - JSON: `jsonb` type, Go 中用 `datatypes.JSON` 或自定义 struct
701
+ - ALWAYS specify fields in queries: `Select("id", "name", "email")`. NEVER `SELECT *`
702
+ - ALWAYS paginate list queries. NEVER unbounded results
703
+ - Use `Preload` or `Joins` to avoid N+1 queries
704
+
705
+ ### Production SQL / DMS Execution Rules
706
+
707
+ - Production repair SQL MUST be a single statement when the execution tool does not support explicit transactions. Use writable CTEs for atomic multi-table updates.
708
+ - Validate every production SQL statement against PostgreSQL before handing it to operators. Do not rely on visual inspection for CTE, `RETURNING`, JSON, or `LATERAL` syntax.
709
+ - Avoid dialect-sensitive or tool-sensitive constructs in operator-facing SQL: explicit `BEGIN`/`COMMIT`, `CROSS JOIN LATERAL (VALUES ...) AS alias(...)`, anonymous composite row output, and client-specific batch separators.
710
+ - `RETURNING` output MUST use named scalar columns or named JSON object keys. Avoid `RETURNING row(...)` or unnamed `VALUES` outputs that produce `f1`, `f2`, `f3` fields.
711
+ - Destructive or state-changing production SQL MUST include an exact target guard (`id`, business reference, current status, version or timestamp where available) and return `target_count` plus changed row summaries.
712
+
713
+ ---
714
+
715
+ ## Transaction Infrastructure
716
+
717
+ - **单一机制**: `database.TransactionManager`(位于 `core/database/transaction.go`)
718
+ - **REQUIRED propagation**: `txManager.WithTransaction(ctx, fn)` — 加入已有事务,或新建事务
719
+ - **REQUIRES_NEW**: `txManager.WithNewTransaction(ctx, fn)` — 始终创建独立新事务(用于审计日志、幂等 key 等)
720
+ - **Repository 获取 DB**: `database.GetDB(ctx, r.db)` — Repository 内获取 DB 的**唯一**方式,从 context 提取事务,或回退到普通 DB
721
+ - **Service 不感知 `*gorm.DB`**: 回调签名为 `func(ctx context.Context) error`,Service 层看不到 GORM 类型
722
+ - **Savepoint**: GORM 对嵌套 `Transaction()` 调用自动使用 savepoint,无需额外封装
723
+ - **Options**: `WithNewTransaction` 接受 `...*sql.TxOptions`(来自 stdlib),用于设置隔离级别和只读模式
724
+
725
+ ---
726
+
727
+ ## Logging Rules
728
+
729
+ - Use `*zap.Logger` field in struct,通过构造函数/Wire 注入
730
+ - NEVER `fmt.Println` / `log.Println` / `log.Fatal`
731
+ - Structured fields first: `logger.Info("order created", zap.Int64("userId", uid), zap.Int64("orderId", oid))`
732
+ - Error logging: `logger.Error("operation failed", zap.Error(err), zap.Int64("contextId", id))`
733
+ - NEVER log passwords, tokens, API keys, PII, card numbers
734
+ - Message: short, past tense (`"order created"`, NOT `"creating order..."`)
735
+
736
+ ---
737
+
738
+ ## Audit Architecture (CloudTrail Envelope Pattern)
739
+
740
+ Three-layer audit architecture. Audit change data is carried on **DomainEvent envelope fields** (AWS CloudTrail pattern), NOT inside the business Payload.
741
+
742
+ ### Three-Table Architecture
743
+
744
+ | Table | Source | Retention | Purpose |
745
+ |-------|--------|-----------|---------|
746
+ | `sys_access_logs` | L1 middleware captures all HTTP requests | 30 days | Ops monitoring / operation logs |
747
+ | `sys_audit_logs` | L2 event envelope `AuditChanges` field (business change snapshots) | 7 years | Compliance audit |
748
+ | `sys_login_logs` | L2 events (auth events dual-written, with device/geo info) | 1 year | Security analysis |
749
+
750
+ ### Three Layers
751
+
752
+ | Layer | Mechanism | Developer Work |
753
+ |-------|-----------|---------------|
754
+ | L1 Middleware | `AuditMiddleware` → `sys_access_logs` | Zero — automatic |
755
+ | L2 Listener | `AuditListener` reads `AuditChanges` / `AuditMeta` from event envelope → `sys_audit_logs` / `sys_login_logs` | Set event envelope fields |
756
+ | L3 Enrichment | `audit.Enrich()` → middleware writes to `sys_audit_logs` | **Only for write ops WITHOUT events** |
757
+
758
+ ### Audit Data Rules (CRITICAL)
759
+
760
+ **Write operations WITH event publishing**: Set audit data on DomainEvent envelope fields. **FORBIDDEN to also call `audit.Enrich()`** (otherwise L2 + L3 = duplicate records).
761
+
762
+ ```go
763
+ import "{{module}}/internal/core/eventbus"
764
+
765
+ evt := eventbus.NewDomainEventFromContext(ctx, sharedevents.EventOrderPaid, orderID)
766
+ evt.Payload = &sharedevents.OrderPaidEvent{OrderID: order.ID, Amount: amount} // typed struct pointer (EP1)
767
+ evt.AuditChanges = &eventbus.AuditChangesPayload{
768
+ Before: map[string]any{"status": "pending"},
769
+ After: map[string]any{"status": "paid", "paid_at": time.Now()},
770
+ }
771
+ evt.AuditMeta = &eventbus.AuditMetadataPayload{Reason: "payment confirmed"} // optional
772
+ s.eventBus.PublishAsync(ctx, evt)
773
+ // FORBIDDEN: do NOT call audit.Enrich() here
774
+ ```
775
+
776
+ **Write operations WITHOUT event publishing** (pure L3 path): Use `audit.Enrich()`
777
+
778
+ ```go
779
+ import "{{module}}/internal/core/audit"
780
+
781
+ // Admin ops without events (e.g., AdminResetPassword, UpsertConfig)
782
+ audit.Enrich(ctx, &audit.ChangesPayload{
783
+ After: map[string]any{"password_reset": true},
784
+ }, nil)
785
+ ```
786
+
787
+ ### Decision Flow
788
+
789
+ ```
790
+ After write operation completes →
791
+ Does this operation publish a domain event?
792
+ YES → Set audit data on event.AuditChanges (L2 envelope path)
793
+ NO → Call audit.Enrich(ctx, changes, metadata) (L3 context path)
794
+ FORBIDDEN: using both simultaneously
795
+ ```
796
+
797
+ ### Exempt Scenarios
798
+
799
+ | Scenario | Reason |
800
+ |----------|--------|
801
+ | Read-only operations (GET / List / Query) | L1 already captures the request |
802
+ | Worker / Cron background tasks | Covered by L2 event envelope (no HTTP context) |
803
+ | EventBus Listener internals | L2 already captures the event |
804
+ | Technical operations (token rotation, cache refresh) | Not a business state change |
805
+
806
+ ### FORBIDDEN Patterns
807
+
808
+ | Pattern | Fix |
809
+ |---------|-----|
810
+ | `audit.Enrich()` + `PublishAsync()` in same method | Use envelope fields only, remove Enrich |
811
+ | `_audit_changes` key in `event.Payload` | Deprecated — use `event.AuditChanges` envelope field |
812
+ | `map[string]any` as event Payload | Use typed struct from `sharedevents` |
813
+
814
+ ---
815
+
816
+ ## Comments
817
+
818
+ - Language: Chinese ONLY. NEVER English comments
819
+ - Style: explain WHY, not WHAT. Skip self-explanatory code
820
+ - GoDoc on ALL exported types, functions, methods
821
+ - NEVER: ticket numbers in comments, commented-out code
822
+ - Struct fields: use `//` comment above field (Chinese description)
823
+
824
+ ---
825
+
826
+ ## OpenAPI Contract
827
+
828
+ - `api/openapi/services/<service>/openapi.yaml` 是 HTTP 契约唯一事实源,Go handler 不保存契约注释或文档专用 struct tag。
829
+ - 每个 operation 必须声明稳定的 `operationId`、显式 `security`、`summary`、`tags`、`responses`、owner、audience 与 stability。
830
+ - Canonical API 文档语言为 `zh-CN`;人类可见文案、顶层 Tag Object 和 `x-tagGroups` 必须使用中文语义,机器标识禁止本地化改名。
831
+ - 每个 operation 必须且只能使用一个已声明标签;每个顶层标签必须在 `x-tagGroups` 中出现且只出现一次,并保持业务阅读顺序。
832
+ - 修改路由、请求、响应、认证或状态码时,同一变更内更新 owner path/component、Arazzo workflow 和生成制品。
833
+ - registry 中全部 HTTP 服务启动时必须通过 Gin route 与内嵌 internal bundle 的精确集合校验。
834
+ - partner/public 只能由 internal canonical source 投影生成,禁止直接编辑 `dist/`。
835
+ - 详细规则和模板见 `.claude/docs/openapi-contract.md`。
836
+
837
+ ---
838
+
839
+ ## Import Order
840
+
841
+ Go 标准 goimports 分组:
842
+
843
+ 1. Standard library (`fmt`, `context`, `net/http`)
844
+ 2. External packages (`github.com/gin-gonic/gin`, `gorm.io/gorm`)
845
+ 3. Internal packages (`github.com/onex-platform/backend/internal/...`)
846
+
847
+ - NEVER import `internal/` package's unexported types from outside
848
+ - NEVER circular imports between packages
849
+ - Run `goimports` to auto-format
850
+
851
+ ---
852
+
853
+ ## Cross-Module Communication
854
+
855
+ | Need | Method |
856
+ |------|--------|
857
+ | Data from another module | 定义 interface in consumer package,implementation 通过 Wire 注入 |
858
+ | Notify without coupling | `EventBus.Publish(ctx, event)` |
859
+
860
+ - Import interface, NEVER concrete implementation across module boundaries
861
+ - Export only what other packages need (最小化导出)
862
+ - Listener 通过 `EventBus.Subscribe()` 注册
863
+
864
+ ### Event Payload Standard (CRITICAL — EP1–EP5)
865
+
866
+ All `DomainEvent.Payload` MUST be a **typed struct pointer**. Aligned with CloudEvents, Stripe Go SDK, Watermill CQRS. Violations WILL be rejected in review.
867
+
868
+ | ID | Rule | Correct | Forbidden |
869
+ | --- | --- | --- | --- |
870
+ | EP1 | Publisher sends pointer | `evt.Payload = &sharedevents.XxxEvent{...}` | `evt.Payload = sharedevents.XxxEvent{...}` (value) |
871
+ | EP2 | Registry factory returns pointer | `EventXxx: func() any { return &XxxEvent{} }` | `return XxxEvent{}` |
872
+ | EP3 | Listener asserts pointer only | `switch p := event.Payload.(type) { case *sharedevents.XxxEvent: ...; default: return err }` | Additional `case sharedevents.XxxEvent:` or `case map[string]any:` branches |
873
+ | EP4 | No map[string]any fallback | Registry + Outbox relay both produce pointers; map fallback is dead code (H5 NO PHANTOM CODE) | Retaining legacy `case map[string]any:` for "defensive" reasons |
874
+ | EP5 | Payload immutable after publish | Constructor fills fields; never mutate after `PublishAsync` | Mutating payload inside handler or later code |
875
+
876
+ **Why pointer?**
877
+ - `json.Unmarshal(&x)` requires a pointer → cross-process Outbox relay ALWAYS produces pointers. Pointer publisher + pointer listener = one uniform type assertion path.
878
+ - `interface{}` boxing escapes value types to heap anyway → no heap-cost benefit to values.
879
+ - Watermill CQRS `Handle(ctx, event *MyEvent) error` signature is industry standard; future bus swap is zero-refactor.
880
+
881
+ **Standard publisher pattern**:
882
+ ```go
883
+ evt := eventbus.NewDomainEventFromContext(ctx, sharedevents.EventUserCheckin, fmt.Sprintf("%d", record.ID))
884
+ evt.Payload = &sharedevents.UserCheckinEvent{
885
+ UserID: userID,
886
+ ProductCode: productCode,
887
+ CheckinDate: today.Format("2006-01-02"),
888
+ StreakDays: streakDays,
889
+ }
890
+ s.eventBus.PublishAsync(ctx, evt)
891
+ ```
892
+
893
+ **Standard listener pattern**:
894
+ ```go
895
+ func (l *Listener) handleXxx(ctx context.Context, event eventbus.DomainEvent) error {
896
+ payload, ok := event.Payload.(*sharedevents.XxxEvent)
897
+ if !ok {
898
+ l.logger.Warn("unexpected payload type",
899
+ zap.String("eventName", event.EventName),
900
+ zap.String("payloadType", fmt.Sprintf("%T", event.Payload)),
901
+ )
902
+ return fmt.Errorf("unexpected payload type %T for event %s", event.Payload, event.EventName)
903
+ }
904
+ // ... process payload.UserID / payload.ProductCode / ...
905
+ return nil
906
+ }
907
+ ```
908
+
909
+ ### Platform vs External Product Boundary (CRITICAL — PB1–PB4)
910
+
911
+ OneX owns reusable platform capabilities under `internal/platform/`. Product-specific workflows, presentation composition, and public BFF contracts belong to external product repositories; `internal/products/` is not an allowed OneX ownership boundary.
912
+
913
+ | ID | Rule | Correct | Forbidden |
914
+ | --- | --- | --- | --- |
915
+ | PB1 | Platform feature → `internal/platform/` | Checkin, points, member tier, order, and payment remain product-neutral engines | Adding an `internal/products/` implementation or product-specific branch inside a platform module |
916
+ | PB2 | `product_code` is a first-class parameter | Every cross-product entity has `product_code VARCHAR(50)` column + index; every DTO / domain struct threads it through | Hardcoding `"product_beta"` in service logic, SQL, or config keys |
917
+ | PB3 | Product-varying platform rules → DB config, not Go code | Rewards per product live in `p_credit_activity_reward_configs`; new product = INSERT row, zero code change | `if productCode == "sample_product" { amount = 100 }` |
918
+ | PB4 | Client must NOT hardcode platform contract values | Reward amounts, tier thresholds, etc. fetched from API (e.g., `/member/checkin/status` returns `next_reward_amount`) | Frontend `const REWARD = 100` that silently breaks when backend config changes per product |
919
+
920
+ Checkin reference implementation (as of this writing):
921
+ - Module location: `internal/platform/member/` ✓ PB1
922
+ - `UserCheckinEvent.ProductCode` field + `UserProductScoped` interface ✓ PB2
923
+ - Reward config in `p_credit_activity_reward_configs (product_code, activity_type, base_amount)` ✓ PB3
924
+ - API `/member/checkin/status` returns the upcoming reward amount so clients do not hardcode product-varying policy ✓ PB4
925
+
926
+ ---
927
+
928
+ ## Architecture Decisions
929
+
930
+ ### Module Complexity Tiers
931
+
932
+ BEFORE creating a new module, determine its complexity tier. Use ONLY the matching structure.
933
+
934
+ | Tier | Criteria | Structure | Modules |
935
+ |------|----------|-----------|---------|
936
+ | Full DDD | State machine / Saga / CQRS / multi-aggregate | `domain/` + `application/` + `infrastructure/` | identity, notification, order, payment |
937
+ | Simplified DDD | Domain logic without state machine / 2-3 related entities | `domain/` + `application/` + `infrastructure/` | user, tenant |
938
+ | Flat | Pure CRUD / simple queries | `model.go` + `service.go` + `handler.go` + `dto.go` + `vo.go` | audit |
939
+
940
+ Decision flow: Need state machine/Saga? → Full DDD. Complex domain logic? → Simplified. Otherwise → Flat.
941
+
942
+ Upgrade path: Flat → Simplified → Full DDD (one-way only, never downgrade).
943
+
944
+ ### Directory Subdivision Rules
945
+
946
+ After determining the module complexity tier, decide whether each layer needs sub-packages using the rules below.
947
+
948
+ #### domain/ — Almost Always Flat
949
+
950
+ | Condition | Structure |
951
+ |-----------|-----------|
952
+ | Default | Single package: model.go, enum.go, repository.go, interfaces.go, events.go |
953
+ | Subdivision trigger | 2+ completely independent aggregate roots (no shared entities) AND files > 12 |
954
+ | Subdivision pattern | `domain/{aggregate}/` |
955
+
956
+ Identity has 10 entities but all revolve around the Identity aggregate root → stays flat.
957
+
958
+ #### application/ — Subdivide by Subdomain
959
+
960
+ | Condition | Structure |
961
+ |-----------|-----------|
962
+ | Service files ≤ 6 AND total files ≤ 15 | Flat: `{name}_service.go` + `handler_{name}.go` |
963
+ | Service files > 6 AND 3+ isolated service groups | Subdivide: `application/{subdomain}/` |
964
+
965
+ Subdivision decision flow:
966
+ 1. Draw service dependency graph
967
+ 2. Identify "isolated groups" (may have intra-group coupling, but no inter-group service dependencies)
968
+ 3. Isolated groups ≥ 3 AND service files > 6 → MUST subdivide
969
+
970
+ Standard structure inside each sub-package: service.go, handler.go, dto.go, vo.go (optional).
971
+ Cross-subdomain orchestration (admin handler, listener) stays at application/ root.
972
+
973
+ #### infrastructure/ — Subdivide by Integration Type
974
+
975
+ | Condition | Structure |
976
+ |-----------|-----------|
977
+ | GORM repositories only | Flat: persistence.go |
978
+ | 3+ external integrations | Subdirectories by type: channels/, webhooks/, etc. |
979
+ | persistence.go > 1500 lines | Split into persistence_{aggregate}.go |
980
+
981
+ #### Module Root
982
+
983
+ {module}/ root ONLY contains assembly files:
984
+ - `module.go` — Module facade (manual assembly)
985
+ - `provider.go` — Wire ProviderSet (only `wire.NewSet`, NEVER constructor re-exports)
986
+ - FORBIDDEN: handler, service, model, or any business code
987
+
988
+ ### VO Naming (CRITICAL)
989
+
990
+ Two types of "VO" exist in this project. NEVER confuse them.
991
+
992
+ | Concept | File | Directory | Implementation |
993
+ |---------|------|-----------|---------------|
994
+ | API Response View Object | `vo.go` | `application/` 或 package root | struct + `ToXxxResponse()` func |
995
+ | DDD Value Object | `valueobject.go` | `domain/` | struct with `Equals()` method |
996
+
997
+ Value Object decision: Use `valueobject.go` ONLY when the value has composite structure (multiple fields that change together) AND invariant constraints (e.g., Money = amount + currency + non-negative check). Simple IDs → primitive type. Status → string const.
998
+
999
+ ### Product vs Tenant
1000
+
1001
+ Each brand is a **product**, NOT a tenant.
1002
+
1003
+ - Use `ProductContext`, NEVER `TenantContext`
1004
+ - OneX 产品数据隔离:`product_code` + IAM + owner-scoped query
1005
+ - 产品业务代码隔离:独立产品仓库与独立 BFF 进程
1006
+ - Tenant isolation:组织/客户级运行时数据范围,不是 Product 的别名
1007
+
1008
+ ### Multi-Product Configuration (三层模型)
1009
+
1010
+ Platform uses a **three-tier configuration model** with a central product registry.
1011
+
1012
+ #### Product Registry
1013
+
1014
+ `p_products` is the **single source of truth** for all platform products. Every module that needs per-product configuration references `p_products.code`.
1015
+
1016
+ | Rule | Detail |
1017
+ |------|--------|
1018
+ | **Field name** | `product_code` — ALL modules, NO exceptions (`product_id`, `app_id` FORBIDDEN) |
1019
+ | **Column type** | `VARCHAR(50)` — ALL modules, unified width |
1020
+ | **Value format** | `snake_case` — regex: `^[a-z][a-z0-9_]{1,49}$` |
1021
+ | **Enum source** | `common/types.Product` — single definition, ALL modules reference it |
1022
+
1023
+ #### Three Tiers
1024
+
1025
+ | Tier | Storage | Content | Example |
1026
+ |------|---------|---------|---------|
1027
+ | Tier 1: Infrastructure | YAML + env var | DB/Redis/JWT/API keys | `configs/config.yaml` |
1028
+ | Tier 2: Platform Module | `p_products` + per-module config tables | Commerce/Notification/OAuth/Tenant | `p_config_product_configs` |
1029
+ | Tier 3: Product-Specific | External product repository | Product workflow, presentation, and product-owned data | `<product-repository>/backend/` |
1030
+
1031
+ #### Per-Module Config Tables (Tier 2)
1032
+
1033
+ Each platform module owns its per-product configuration table. Tables are NOT redundant — each covers a distinct domain:
1034
+
1035
+ | Config Table | Module | Responsibility |
1036
+ |-------------|--------|---------------|
1037
+ | `p_products` | product | Product identity (name, logo, status) |
1038
+ | `p_config_product_configs` | commerce/config | Commerce settings (currency, trial, tax) |
1039
+ | `p_config_payment_configs` | commerce/config | Payment gateways (provider, secrets) |
1040
+ | `p_notification_products` | notification | Channel config (sender, branding, quotas) |
1041
+ | `p_identity_oauth_configs` | identity | OAuth providers (client_id, redirect_uri) |
1042
+ | `p_tenant_apps` | tenant | Tenant features (feature flags, rate limits) |
1043
+
1044
+ All tables use `product_code VARCHAR(50)` to reference `p_products.code`.
1045
+
1046
+ See the upstream OneX `backend/.claude/docs/product-registry-design.md` for the platform-owned registry design; its source revision is recorded in `docs/standards-provenance.json`.
1047
+
1048
+ ### Service Topology
1049
+
1050
+ Modular Monolith 架构(Stripe/Shopify 标准)。统一平台 API 服务所有产品,管理后台独立进程。
1051
+
1052
+ | App | Port | Purpose |
1053
+ |-----|------|---------|
1054
+ | `cmd/platform-api/` | 3002 | 统一平台服务(Identity + Commerce + Credit + Quota) |
1055
+ | `cmd/admin-api/` | 3003 | 管理后台 BFF(admin dashboard) |
1056
+ | `cmd/worker/` | — | 后台任务(Asynq consumer) |
1057
+
1058
+ **Per-product domain routing**:APISIX 按 Host + Path 将产品公开合同路由到外部 Product BFF,将平台公开/内部合同路由到对应 OneX 服务。产品前端只配置一个公开产品 origin,不直接选择基础设施服务。
1059
+
1060
+ **路由选择性注册**:所有模块实现 nil-safe `RegisterRoutes(public, authenticated, admin *gin.RouterGroup)`。通过传 nil 跳过不需要的路由组:
1061
+ - admin-api: `RegisterRoutes(nil, nil, admin)` — 仅注册 admin 路由
1062
+
1063
+ **平台适配器**:OneX 进程内跨模块适配器统一在 `internal/common/bffadapter/`;外部 Product BFF 只能通过 OpenAPI HTTP 合同、事件或工作流调用平台能力。
1064
+
1065
+ **Outbox Relay**:platform-api 运行统一 Relay,处理所有域的 outbox 事件。admin-api 不调用 `relay.Start()`,admin 写入的 outbox 记录由 platform-api 的 Relay 投递。
1066
+
1067
+ **Event runtime boundary**:源聚合投影监听器必须留在拥有该状态机的运行时;`worker` 只消费 durable public events 做下游副作用。`user.deleted` 这类部分公开的事件族必须使用精确白名单,禁止 `user.*` 这类宽泛通配。See `backend/.claude/docs/event-runtime-boundary.md`.
1068
+
1069
+ **E2E contract tests**:凡是跨运行时、依赖 relay/worker、会改变最终用户可见真相的工作流,必须同时具备一个全链路 E2E 和一个 `ProvideRelayConfig()` 白名单回归测试。See `backend/.claude/docs/e2e-standards.md`.
1070
+
1071
+ **内部服务间调用**:`/internal/v1/` 路由组,通过 IAM 服务账号凭证认证、已认证主体校验、路由资源策略授权保护。
1072
+
1073
+ **Gateway upstream policy**:所有挂在 APISIX 后的生产 public API upstream 必须使用多节点 + 主被动健康检查 + 显式 timeout/retries/keepalive。任何 gateway plugin 回调(如 `forward-auth`)必须复用 APISIX 内部路由或共享 upstream,禁止直连单个 backend 实例。
1074
+
1075
+ Gateway (APISIX) runs separately, not in Go codebase. Routes: `/api/v1/admin/*` → admin-api (priority 10).
1076
+
1077
+ ### Event Contracts
1078
+
1079
+ Cross-module events MUST be defined in `internal/sharedevents/`, NEVER in the publishing module.
1080
+
1081
+ - Event struct: `{Resource}{Action}Event` (e.g., `IdentityCreatedEvent`)
1082
+ - Event name const: `Event{Resource}{Action}` = `"{resource}.{action}"` (e.g., `"identity.created"`)
1083
+ - Import: `import "{{module}}/internal/sharedevents"`
1084
+
1085
+ ### Table Naming
1086
+
1087
+ | Scope | Prefix | Example |
1088
+ |-------|--------|---------|
1089
+ | Platform base entity | `p_` | `p_products`, `p_tenants` |
1090
+ | Platform module | `p_{module}_` | `p_user_users`, `p_identity_identities` |
1091
+ | System | `sys_` | `sys_migrations`, `sys_access_logs`, `sys_audit_logs`, `sys_login_logs`, `sys_outbox_events` |
1092
+
1093
+ Product-related columns: ALL tables that reference a product MUST use `product_code VARCHAR(50)` as the column name. NEVER use `product_id`, `app_id`, or other variants.
1094
+
1095
+ Product-specific tables are owned by external product repositories and must not be added to the OneX schema.
1096
+
1097
+ ---
1098
+
1099
+ ## Dependency Injection (Wire)
1100
+
1101
+ - 每个模块提供 `provider.go`,定义 `wire.NewSet(...)`
1102
+ - 每个 `cmd/` 提供 `wire.go`,定义 injector function
1103
+ - 运行 `make wire` 生成 `wire_gen.go`
1104
+ - NEVER 手动编辑 `wire_gen.go`
1105
+ - NEVER 在 `main.go` 中手动构造依赖
1106
+
1107
+ ---
1108
+
1109
+ ## Commit Discipline
1110
+
1111
+ - ONE module, ONE feature per commit
1112
+ - Pre-commit: validate against `backend/.claude/docs/` specs
1113
+ - MUST NOT commit with any CRITICAL/MUST violation
1114
+
1115
+ ---
1116
+
1117
+ ## Scaffold Skills
1118
+
1119
+ 创建新模块或新管理页时,优先使用脚手架生成骨架代码,再填充业务逻辑:
1120
+
1121
+ | Skill | Usage | Purpose |
1122
+ |-------|-------|---------|
1123
+ | `/scaffold` | `/scaffold {module} --tier={full-ddd\|simplified\|flat}` | 生成 Go 模块骨架(domain + application + infrastructure) |
1124
+ | `/scaffold-admin` | `/scaffold-admin {module}/{resource}` | 生成 Admin CRUD 页面(VxeGrid + Modal + Form + API) |
1125
+
1126
+ ---
1127
+
1128
+ ## Reference
1129
+
1130
+ | Doc | Content |
1131
+ |-----|---------|
1132
+ | `.claude/docs/architecture-template.md` | Plan mode mandatory skeleton (Level A/B/C) |
1133
+ | `backend/.claude/docs/api-design.md` | Handler/Service/DTO/VO templates, pagination |
1134
+ | `backend/.claude/docs/module-standards.md` | Tier decision, directory subdivision, VO naming |
1135
+ | `backend/.claude/docs/error-handling.md` | Error types, codes, decision table |
1136
+ | `backend/.claude/docs/database.md` | Model template, column types, migrations |
1137
+ | Upstream OneX `.claude/docs/decisions.md` | Platform Architecture Decision Records; source revision in `docs/standards-provenance.json` |
1138
+ | `internal/platform/trade/order/` | Reference: Full DDD module |
1139
+ | `internal/platform/trade/module.go` | Reference: Module self-registration |