@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,790 @@
1
+ package middleware
2
+
3
+ import (
4
+ "bytes"
5
+ "context"
6
+ "encoding/json"
7
+ "errors"
8
+ "fmt"
9
+ "io"
10
+ "sort"
11
+ "strconv"
12
+ "strings"
13
+
14
+ "github.com/gin-gonic/gin"
15
+
16
+ "{{module}}/internal/common/iamscope"
17
+ "{{module}}/internal/common/ruleexpression"
18
+ "{{module}}/internal/common/types"
19
+ iamdomain "{{module}}/internal/integrations/onex/iam"
20
+ "{{module}}/pkg/apierror"
21
+ )
22
+
23
+ // scopeConstraintKey 在 gin.Context 传递数据范围约束的私有 key。
24
+ //
25
+ // 采用本 package 既有的 "__xxx" 命名(见 apikey_auth.go),避免与业务键冲突;
26
+ // 仅通过 SetScopeConstraint / GetScopeConstraint 读写,不直接暴露字符串。
27
+ const scopeConstraintKey = "__iamScopeConstraint"
28
+
29
+ // scopePrincipalIDKey 在 gin.Context 传递已解析 IAM 主体主键的私有 key。
30
+ //
31
+ // 数据范围的 self 维度(assigned_to_self 等)需用主体主键填充列谓词;该主键由
32
+ // RequireResourcePermission 在请求期解析(主键 != identity_id,SH-I1),故由中间件
33
+ // 与 scope 约束一并注入,供查询层透传给 applier。仅通过 SetScopePrincipalID /
34
+ // GetScopePrincipalID 读写。
35
+ const scopePrincipalIDKey = "__iamScopePrincipalID"
36
+
37
+ // resourcePermissionDecisionKey 在 gin.Context 传递本次资源授权裁决证据的私有 key。
38
+ const resourcePermissionDecisionKey = "__iamResourcePermissionDecision"
39
+
40
+ const (
41
+ requiredCapabilityMissingReason = "required_capability_missing"
42
+ requiredProductRequirementNotSatisfiedReason = "required_product_requirement_not_satisfied"
43
+ requiredProductRequirementIndeterminateReason = "required_product_requirement_indeterminate"
44
+ )
45
+
46
+ type adminAccessContextKey struct{}
47
+
48
+ type resourcePermissionConfig struct {
49
+ decisionRisk iamdomain.RiskLevel
50
+ productRequirements []productAdmissionRequirement
51
+ requirementErr error
52
+ }
53
+
54
+ // ProductRequirement 声明路由的版本化产品准入表达式。
55
+ type ProductRequirement struct {
56
+ // Expression 是 common/ruleexpression V1 信封。
57
+ Expression json.RawMessage
58
+ // ExpressionHash 是表达式 canonical JSON 的 SHA-256。
59
+ ExpressionHash string
60
+ }
61
+
62
+ type productAdmissionRequirement struct {
63
+ expression ruleexpression.ExpressionV1
64
+ deniedReason string
65
+ explanation string
66
+ }
67
+
68
+ type productAdmissionDecision struct {
69
+ Allowed bool
70
+ ReasonCode string
71
+ Explanation string
72
+ Failure *apierror.APIError
73
+ }
74
+
75
+ // ResourcePermissionDecision 记录一次资源授权裁决的审计证据。
76
+ type ResourcePermissionDecision struct {
77
+ // 被求值动作
78
+ Action string
79
+ // 被求值资源
80
+ Resource string
81
+ // 是否允许
82
+ Allowed bool
83
+ // 决策原因码
84
+ ReasonCode string
85
+ // 决策原因类别
86
+ ReasonKind string
87
+ // IAM 主体主键
88
+ PrincipalID int64
89
+ // 数据范围摘要
90
+ ScopeConstraintSummary string
91
+ }
92
+
93
+ // ResourcePermissionOption 配置资源动作级授权中间件的可选行为。
94
+ type ResourcePermissionOption func(*resourcePermissionConfig)
95
+
96
+ // WithDecisionLogRisk 声明当前路由求值需要按指定风险等级写访问决策日志。
97
+ func WithDecisionLogRisk(risk iamdomain.RiskLevel) ResourcePermissionOption {
98
+ return func(cfg *resourcePermissionConfig) {
99
+ cfg.decisionRisk = risk
100
+ }
101
+ }
102
+
103
+ // WithRequiredCapability 声明路由只在当前产品能力生效时进入 IAM 求值。
104
+ func WithRequiredCapability(capabilityCode string) ResourcePermissionOption {
105
+ requirement, err := capabilityAdmissionRequirement(capabilityCode)
106
+ return func(cfg *resourcePermissionConfig) {
107
+ appendProductAdmissionRequirement(cfg, requirement, err)
108
+ }
109
+ }
110
+
111
+ // WithRequiredProductRequirement 声明路由的产品上下文与能力组合需求。
112
+ func WithRequiredProductRequirement(requirement ProductRequirement) ResourcePermissionOption {
113
+ normalized, err := normalizeProductAdmissionRequirement(requirement)
114
+ return func(cfg *resourcePermissionConfig) {
115
+ appendProductAdmissionRequirement(cfg, normalized, err)
116
+ }
117
+ }
118
+
119
+ func appendProductAdmissionRequirement(
120
+ cfg *resourcePermissionConfig,
121
+ requirement productAdmissionRequirement,
122
+ err error,
123
+ ) {
124
+ if cfg.requirementErr != nil {
125
+ return
126
+ }
127
+ if err != nil {
128
+ cfg.requirementErr = err
129
+ return
130
+ }
131
+ cfg.productRequirements = append(cfg.productRequirements, requirement)
132
+ }
133
+
134
+ func capabilityAdmissionRequirement(capabilityCode string) (productAdmissionRequirement, error) {
135
+ expression := ruleexpression.ExpressionV1{
136
+ SchemaVersion: ruleexpression.SchemaVersionV1,
137
+ Root: &ruleexpression.PredicateNode{
138
+ Subject: ruleexpression.SubjectCapability,
139
+ Key: strings.TrimSpace(capabilityCode),
140
+ Operator: ruleexpression.OperatorActive,
141
+ },
142
+ }
143
+ if _, err := ruleexpression.CanonicalJSON(expression); err != nil {
144
+ return productAdmissionRequirement{}, fmt.Errorf("required capability expression is invalid: %w", err)
145
+ }
146
+ return productAdmissionRequirement{
147
+ expression: expression,
148
+ deniedReason: requiredCapabilityMissingReason,
149
+ explanation: "required product capability is not active",
150
+ }, nil
151
+ }
152
+
153
+ func normalizeProductAdmissionRequirement(requirement ProductRequirement) (productAdmissionRequirement, error) {
154
+ expression, err := ruleexpression.Decode(bytes.TrimSpace(requirement.Expression))
155
+ if err != nil {
156
+ return productAdmissionRequirement{}, fmt.Errorf("decode product admission requirement: %w", err)
157
+ }
158
+ if err := validateProductAdmissionSubjects(expression.Root); err != nil {
159
+ return productAdmissionRequirement{}, err
160
+ }
161
+ hash, err := ruleexpression.CanonicalHash(expression)
162
+ if err != nil {
163
+ return productAdmissionRequirement{}, fmt.Errorf("hash product admission requirement: %w", err)
164
+ }
165
+ expectedHash := strings.TrimSpace(requirement.ExpressionHash)
166
+ if expectedHash == "" || expectedHash != hash {
167
+ return productAdmissionRequirement{}, fmt.Errorf("product admission requirement hash does not match canonical expression")
168
+ }
169
+ return productAdmissionRequirement{
170
+ expression: expression,
171
+ deniedReason: requiredProductRequirementNotSatisfiedReason,
172
+ explanation: "required product condition is not satisfied",
173
+ }, nil
174
+ }
175
+
176
+ func validateProductAdmissionSubjects(node ruleexpression.Node) error {
177
+ switch current := node.(type) {
178
+ case *ruleexpression.AllNode:
179
+ for i := range current.Children {
180
+ if err := validateProductAdmissionSubjects(current.Children[i]); err != nil {
181
+ return err
182
+ }
183
+ }
184
+ case *ruleexpression.AnyNode:
185
+ for i := range current.Children {
186
+ if err := validateProductAdmissionSubjects(current.Children[i]); err != nil {
187
+ return err
188
+ }
189
+ }
190
+ case *ruleexpression.NotNode:
191
+ return validateProductAdmissionSubjects(current.Child)
192
+ case *ruleexpression.PredicateNode:
193
+ switch current.Subject {
194
+ case ruleexpression.SubjectProduct, ruleexpression.SubjectAttribute, ruleexpression.SubjectCapability:
195
+ return nil
196
+ default:
197
+ return fmt.Errorf("subject %q is not allowed in a product admission requirement", current.Subject)
198
+ }
199
+ default:
200
+ return fmt.Errorf("product admission requirement contains unsupported node %T", node)
201
+ }
202
+ return nil
203
+ }
204
+
205
+ func evaluateProductAdmissionRequirements(
206
+ cfg resourcePermissionConfig,
207
+ product iamdomain.ProductContext,
208
+ ) (productAdmissionDecision, error) {
209
+ if cfg.requirementErr != nil {
210
+ return productAdmissionDecision{}, cfg.requirementErr
211
+ }
212
+ if len(cfg.productRequirements) == 0 {
213
+ return productAdmissionDecision{Allowed: true}, nil
214
+ }
215
+ if product.ProductCode == "" {
216
+ return productAdmissionDecision{Failure: apierror.BadRequest(
217
+ apierror.CodeInvalidOperation,
218
+ "X-Product-Code header is required. Select a product first",
219
+ )}, nil
220
+ }
221
+
222
+ for i := range cfg.productRequirements {
223
+ requirement := cfg.productRequirements[i]
224
+ result, err := ruleexpression.Evaluate(requirement.expression, productAdmissionPredicateResolver(product))
225
+ if err != nil {
226
+ return productAdmissionDecision{}, fmt.Errorf("evaluate product admission requirement: %w", err)
227
+ }
228
+ switch result {
229
+ case ruleexpression.ResultTrue:
230
+ continue
231
+ case ruleexpression.ResultFalse:
232
+ return productAdmissionDecision{
233
+ ReasonCode: requirement.deniedReason,
234
+ Explanation: requirement.explanation,
235
+ }, nil
236
+ default:
237
+ return productAdmissionDecision{
238
+ ReasonCode: requiredProductRequirementIndeterminateReason,
239
+ Explanation: "required product condition could not be evaluated",
240
+ }, nil
241
+ }
242
+ }
243
+ return productAdmissionDecision{Allowed: true}, nil
244
+ }
245
+
246
+ func productAdmissionPredicateResolver(product iamdomain.ProductContext) ruleexpression.PredicateResolver {
247
+ return func(predicate *ruleexpression.PredicateNode) (ruleexpression.Result, error) {
248
+ switch predicate.Subject {
249
+ case ruleexpression.SubjectProduct:
250
+ actual := ""
251
+ switch predicate.Key {
252
+ case "code":
253
+ actual = product.ProductCode
254
+ case "lifecycle_status":
255
+ actual = product.LifecycleStatus
256
+ default:
257
+ return ruleexpression.ResultIndeterminate, nil
258
+ }
259
+ return compareProductRequirementString(actual, predicate.Operator, predicate.Value), nil
260
+ case ruleexpression.SubjectAttribute:
261
+ actual, known, present := product.AttributeFact(predicate.Key)
262
+ if !known {
263
+ return ruleexpression.ResultIndeterminate, nil
264
+ }
265
+ if predicate.Operator == ruleexpression.OperatorExists {
266
+ return productRequirementBooleanResult(present), nil
267
+ }
268
+ if !present {
269
+ return ruleexpression.ResultIndeterminate, nil
270
+ }
271
+ return compareProductRequirementJSON(actual, predicate.Operator, predicate.Value), nil
272
+ case ruleexpression.SubjectCapability:
273
+ active, known := product.CapabilityState(predicate.Key)
274
+ if !known {
275
+ return ruleexpression.ResultIndeterminate, nil
276
+ }
277
+ switch predicate.Operator {
278
+ case ruleexpression.OperatorActive:
279
+ return productRequirementBooleanResult(active), nil
280
+ case ruleexpression.OperatorInactive:
281
+ return productRequirementBooleanResult(!active), nil
282
+ default:
283
+ return ruleexpression.ResultIndeterminate, nil
284
+ }
285
+ default:
286
+ return ruleexpression.ResultIndeterminate, nil
287
+ }
288
+ }
289
+ }
290
+
291
+ func compareProductRequirementString(
292
+ actual string,
293
+ operator ruleexpression.Operator,
294
+ expected ruleexpression.Value,
295
+ ) ruleexpression.Result {
296
+ switch operator {
297
+ case ruleexpression.OperatorEqual, ruleexpression.OperatorNotEqual:
298
+ value, ok := expected.(*ruleexpression.StringValue)
299
+ if !ok {
300
+ return ruleexpression.ResultIndeterminate
301
+ }
302
+ equal := actual == value.Value
303
+ if operator == ruleexpression.OperatorNotEqual {
304
+ equal = !equal
305
+ }
306
+ return productRequirementBooleanResult(equal)
307
+ case ruleexpression.OperatorIn, ruleexpression.OperatorNotIn:
308
+ value, ok := expected.(*ruleexpression.StringArrayValue)
309
+ if !ok {
310
+ return ruleexpression.ResultIndeterminate
311
+ }
312
+ contains := false
313
+ for i := range value.Values {
314
+ if value.Values[i] == actual {
315
+ contains = true
316
+ break
317
+ }
318
+ }
319
+ if operator == ruleexpression.OperatorNotIn {
320
+ contains = !contains
321
+ }
322
+ return productRequirementBooleanResult(contains)
323
+ default:
324
+ return ruleexpression.ResultIndeterminate
325
+ }
326
+ }
327
+
328
+ func compareProductRequirementJSON(
329
+ actual json.RawMessage,
330
+ operator ruleexpression.Operator,
331
+ expected ruleexpression.Value,
332
+ ) ruleexpression.Result {
333
+ decoder := json.NewDecoder(bytes.NewReader(actual))
334
+ decoder.UseNumber()
335
+ var decoded any
336
+ if err := decoder.Decode(&decoded); err != nil {
337
+ return ruleexpression.ResultIndeterminate
338
+ }
339
+ if err := ensureProductRequirementJSONEOF(decoder); err != nil {
340
+ return ruleexpression.ResultIndeterminate
341
+ }
342
+
343
+ switch operator {
344
+ case ruleexpression.OperatorEqual, ruleexpression.OperatorNotEqual:
345
+ equal, comparable := productRequirementValueEqualsJSON(expected, decoded)
346
+ if !comparable {
347
+ return ruleexpression.ResultIndeterminate
348
+ }
349
+ if operator == ruleexpression.OperatorNotEqual {
350
+ equal = !equal
351
+ }
352
+ return productRequirementBooleanResult(equal)
353
+ case ruleexpression.OperatorIn, ruleexpression.OperatorNotIn:
354
+ values, ok := expected.(*ruleexpression.StringArrayValue)
355
+ actualString, stringOK := decoded.(string)
356
+ if !ok || !stringOK {
357
+ return ruleexpression.ResultIndeterminate
358
+ }
359
+ contains := false
360
+ for i := range values.Values {
361
+ if values.Values[i] == actualString {
362
+ contains = true
363
+ break
364
+ }
365
+ }
366
+ if operator == ruleexpression.OperatorNotIn {
367
+ contains = !contains
368
+ }
369
+ return productRequirementBooleanResult(contains)
370
+ default:
371
+ return ruleexpression.ResultIndeterminate
372
+ }
373
+ }
374
+
375
+ func productRequirementValueEqualsJSON(expected ruleexpression.Value, actual any) (bool, bool) { //nolint:T1 // any 是 JSON decoder 的封闭输出。
376
+ switch value := expected.(type) {
377
+ case *ruleexpression.BooleanValue:
378
+ actualValue, ok := actual.(bool)
379
+ return ok && actualValue == value.Value, ok
380
+ case *ruleexpression.NumberValue:
381
+ actualValue, ok := actual.(json.Number)
382
+ if !ok {
383
+ return false, false
384
+ }
385
+ parsed, err := actualValue.Float64()
386
+ return err == nil && parsed == value.Value, err == nil
387
+ case *ruleexpression.StringValue:
388
+ actualValue, ok := actual.(string)
389
+ return ok && actualValue == value.Value, ok
390
+ default:
391
+ return false, false
392
+ }
393
+ }
394
+
395
+ func ensureProductRequirementJSONEOF(decoder *json.Decoder) error {
396
+ var extra json.RawMessage
397
+ err := decoder.Decode(&extra)
398
+ if err == io.EOF {
399
+ return nil
400
+ }
401
+ if err != nil {
402
+ return err
403
+ }
404
+ return fmt.Errorf("attribute value contains trailing JSON")
405
+ }
406
+
407
+ func productRequirementBooleanResult(value bool) ruleexpression.Result {
408
+ if value {
409
+ return ruleexpression.ResultTrue
410
+ }
411
+ return ruleexpression.ResultFalse
412
+ }
413
+
414
+ // ResourceAuthorizer IAM 授权能力(由 iam.Module 满足)。
415
+ //
416
+ // 接口由消费方(middleware)定义(Go 惯例 + 项目 A3:接口由使用者定义),
417
+ // middleware → iam/domain 为单向依赖(iam/domain 不反向 import middleware,无环)。
418
+ type ResourceAuthorizer interface {
419
+ // ResolvePrincipalByIdentity 按认证身份 ID 解析其活跃 IAM 主体(主键 != identity_id)。
420
+ ResolvePrincipalByIdentity(ctx context.Context, identityID int64) (*iamdomain.PrincipalRecord, error)
421
+ // AssembleAdminAccessContext 通过 IAM 唯一工厂装配请求授权上下文与产品事实。
422
+ AssembleAdminAccessContext(
423
+ ctx context.Context,
424
+ principal *iamdomain.PrincipalRecord,
425
+ input iamdomain.AdminAccessContextInput,
426
+ ) (iamdomain.AdminAccessContext, error)
427
+ // Evaluate 单资源动作级求值:principal 对 (action, resource 模式) 是否有 Allow。
428
+ Evaluate(ctx context.Context, req iamdomain.EvaluateRequest) (iamdomain.Decision, error)
429
+ // EvaluateMany 批量求值:按 principal 分组装配语句集,N 个请求仅装配 distinct principal 次。
430
+ //
431
+ // 供菜单 IAM 投影按 sys_menus.iam_action 对当前主体一次性求值全部节点(避免逐节点重复装配语句)。
432
+ // 返回顺序与入参一一对应(与单资源 Evaluate 同源裁决,保证菜单可见性与路由守卫一致)。
433
+ EvaluateMany(ctx context.Context, reqs []iamdomain.EvaluateRequest) ([]iamdomain.Decision, error)
434
+ // ResolveScope 解析主体在 action 上的数据范围约束,供查询层注入 WHERE 过滤。
435
+ ResolveScope(ctx context.Context, principalID int64, action string, workspace iamdomain.WorkspaceContext) (iamscope.ScopeConstraint, error)
436
+ // ResolveProductScopes 解析主体在指定 action 上可见的产品集合。
437
+ //
438
+ // 供 global 域 handler(如产品注册表 / mediagen 列表)按操作员产品范围过滤结果集:
439
+ // unbounded=true 表示全产品访问(不过滤);否则仅展示 products 集合内产品的数据。
440
+ // 该方法必须使用已解析 IAM 主体主键与动作名,避免认证身份 ID 或无关 global 授权扩大产品范围。
441
+ ResolveProductScopes(ctx context.Context, principalID int64, action string) (products []string, unbounded bool, err error)
442
+ }
443
+
444
+ // ResourceDecisionLogger 由授权模块实现,用于高风险动作写入访问决策日志。
445
+ type ResourceDecisionLogger interface {
446
+ LogDecision(ctx context.Context, req iamdomain.EvaluateRequest, decision iamdomain.Decision, risk iamdomain.RiskLevel)
447
+ }
448
+
449
+ // RequireResourcePermission 资源动作级授权中间件(两阶段授权第一阶段,设计 §6.4)。
450
+ //
451
+ // 职责边界:
452
+ // - 做「动作级」检查——principal 对 (action, resource 模式) 是否有 Allow(含 time/ip
453
+ // 等非资源条件)。不在请求期校验具体资源实例归属(业务对象此时尚未加载)。
454
+ // - 放行后将 ResolveScope 产出的 ScopeConstraint 注入 gin ctx,供下游查询层作为
455
+ // WHERE 过滤统一执行资源归属收敛(单资源 get 不属于自己 scope → 查询返回
456
+ // not-found,而非中间件 403)。
457
+ //
458
+ // resourceTemplate 为 ARN 形态模板,占位符在请求期替换:
459
+ // - {product_code} ← 中间件已 resolve 的产品上下文(GetProductCode)。
460
+ // - 其余 {name} ← 同名路径参数 c.Param("name")(如 {id}、{store_id})。
461
+ //
462
+ // list 端点模板无 {id} 时保留集合 / 通配模式(如以 ** 收尾),由 Evaluate 做模式匹配。
463
+ func RequireResourcePermission(authz ResourceAuthorizer, action string, resourceTemplate string, opts ...ResourcePermissionOption) gin.HandlerFunc {
464
+ cfg := resourcePermissionConfig{}
465
+ for _, opt := range opts {
466
+ opt(&cfg)
467
+ }
468
+ return func(c *gin.Context) {
469
+ principal, sourceIP, apiErr := resolveRequestPrincipal(c, authz)
470
+ if apiErr != nil {
471
+ abortWithAPIError(c, apiErr)
472
+ return
473
+ }
474
+
475
+ resourceARN := resolveResourceTemplate(c, resourceTemplate)
476
+ accessCtx, err := authz.AssembleAdminAccessContext(c.Request.Context(), principal, iamdomain.AdminAccessContextInput{
477
+ Principal: iamdomain.PrincipalContext{
478
+ SourceIP: sourceIP,
479
+ },
480
+ Workspace: iamdomain.WorkspaceContext{
481
+ ProductCode: string(GetProductCode(c)),
482
+ },
483
+ Request: iamdomain.RequestContext{
484
+ RequestID: GetRequestID(c),
485
+ IdempotencyKey: c.GetHeader(types.HeaderIdempotencyKey),
486
+ UserAgent: c.Request.UserAgent(),
487
+ Method: c.Request.Method,
488
+ Action: action,
489
+ SourceIP: sourceIP,
490
+ RouteName: c.FullPath(),
491
+ },
492
+ Resource: iamdomain.ResourceContext{
493
+ ARN: resourceARN,
494
+ },
495
+ })
496
+ if err != nil {
497
+ abortWithAPIError(c, productContextAPIError(string(GetProductCode(c)), err))
498
+ return
499
+ }
500
+ c.Request = c.Request.WithContext(withAdminAccessContext(c.Request.Context(), accessCtx))
501
+
502
+ evalReq := iamdomain.EvaluateRequest{
503
+ PrincipalID: principal.ID,
504
+ Action: action,
505
+ Resource: resourceARN,
506
+ Context: accessCtx,
507
+ }
508
+ admission, err := evaluateProductAdmissionRequirements(cfg, accessCtx.Product)
509
+ if err != nil {
510
+ abortWithAPIError(c, apierror.Internal("Product admission requirement is invalid"))
511
+ return
512
+ }
513
+ if admission.Failure != nil {
514
+ abortWithAPIError(c, admission.Failure)
515
+ return
516
+ }
517
+ if !admission.Allowed {
518
+ decision := iamdomain.NewDeniedDecision(
519
+ action,
520
+ resourceARN,
521
+ admission.ReasonCode,
522
+ nil,
523
+ admission.Explanation,
524
+ )
525
+ SetResourcePermissionDecision(c, ResourcePermissionDecision{
526
+ Action: action,
527
+ Resource: resourceARN,
528
+ Allowed: false,
529
+ ReasonCode: decision.ReasonCode,
530
+ ReasonKind: string(decision.ReasonKind),
531
+ PrincipalID: principal.ID,
532
+ })
533
+ logAccessDecision(c.Request.Context(), authz, evalReq, decision, cfg.decisionRisk)
534
+ abortWithAPIError(c, apierror.Forbidden("Forbidden: "+decision.ReasonCode))
535
+ return
536
+ }
537
+
538
+ decision, err := authz.Evaluate(c.Request.Context(), evalReq)
539
+ if err != nil {
540
+ abortWithAPIError(c, apierror.Internal("Authorization check failed"))
541
+ return
542
+ }
543
+ permissionDecision := ResourcePermissionDecision{
544
+ Action: evalReq.Action,
545
+ Resource: evalReq.Resource,
546
+ Allowed: decision.Allowed,
547
+ ReasonCode: decision.ReasonCode,
548
+ ReasonKind: string(decision.ReasonKind),
549
+ PrincipalID: principal.ID,
550
+ }
551
+ SetResourcePermissionDecision(c, permissionDecision)
552
+ logAccessDecision(c.Request.Context(), authz, evalReq, decision, cfg.decisionRisk)
553
+ if !decision.Allowed {
554
+ // 携带决策原因码,便于客户端与审计区分拒绝来源(仿 RequirePermission 的 403 写法)。
555
+ abortWithAPIError(c, apierror.Forbidden("Forbidden: "+decision.ReasonCode))
556
+ return
557
+ }
558
+
559
+ // 动作级放行 → 以主体主键解析数据范围约束注入 ctx,交给查询层做 WHERE 过滤。
560
+ scope, err := authz.ResolveScope(c.Request.Context(), principal.ID, action, accessCtx.Workspace)
561
+ if err != nil {
562
+ abortWithAPIError(c, apierror.Internal("Scope resolution failed"))
563
+ return
564
+ }
565
+ permissionDecision.ScopeConstraintSummary = summarizeScopeConstraint(scope)
566
+ SetResourcePermissionDecision(c, permissionDecision)
567
+ SetScopeConstraint(c, scope)
568
+ // 主体主键随约束一并注入:self 维度(assigned_to_self 等)下推时需用它填充列谓词。
569
+ SetScopePrincipalID(c, principal.ID)
570
+
571
+ c.Next()
572
+ }
573
+ }
574
+
575
+ // GetAdminAccessContext 读取路由授权阶段装配的完整 IAM 求值上下文。
576
+ func GetAdminAccessContext(ctx context.Context) (iamdomain.AdminAccessContext, bool) {
577
+ v := ctx.Value(adminAccessContextKey{})
578
+ accessCtx, ok := v.(iamdomain.AdminAccessContext)
579
+ return accessCtx, ok
580
+ }
581
+
582
+ func withAdminAccessContext(ctx context.Context, accessCtx iamdomain.AdminAccessContext) context.Context {
583
+ return context.WithValue(ctx, adminAccessContextKey{}, accessCtx)
584
+ }
585
+
586
+ func logAccessDecision(
587
+ ctx context.Context,
588
+ authz ResourceAuthorizer,
589
+ req iamdomain.EvaluateRequest,
590
+ decision iamdomain.Decision,
591
+ risk iamdomain.RiskLevel,
592
+ ) {
593
+ if !risk.RequiresDecisionLog() {
594
+ return
595
+ }
596
+ logger, ok := authz.(ResourceDecisionLogger)
597
+ if !ok {
598
+ return
599
+ }
600
+ logger.LogDecision(ctx, req, decision, risk)
601
+ }
602
+
603
+ func resolveRequestPrincipal(
604
+ c *gin.Context,
605
+ authz ResourceAuthorizer,
606
+ ) (*iamdomain.PrincipalRecord, string, *apierror.APIError) {
607
+ sourceIP := ResolveTrustedClientIP(c)
608
+ if iamPrincipal := GetAuthenticatedIAMPrincipal(c); iamPrincipal != nil {
609
+ if iamPrincipal.SourceIP != "" {
610
+ sourceIP = iamPrincipal.SourceIP
611
+ }
612
+ return &iamdomain.PrincipalRecord{
613
+ ID: iamPrincipal.PrincipalID,
614
+ PrincipalNo: iamPrincipal.PrincipalNo,
615
+ PrincipalType: iamPrincipal.PrincipalType,
616
+ IdentityID: iamPrincipal.IdentityID,
617
+ IsActive: true,
618
+ Version: iamPrincipal.PrincipalVersion,
619
+ }, sourceIP, nil
620
+ }
621
+
622
+ identity := GetUserIdentity(c)
623
+ if identity == nil {
624
+ return nil, sourceIP, apierror.Unauthorized()
625
+ }
626
+
627
+ // 把认证身份 ID 解析为真实 IAM 主体:主体主键(binding 的 principal_id 指向它)
628
+ // 与 identity_id 是两个语义不同的标识(SH-I1),不可混用。授权全程以主体主键展开。
629
+ principal, err := authz.ResolvePrincipalByIdentity(c.Request.Context(), identity.IdentityID.Int64())
630
+ if err != nil {
631
+ // 身份未映射到活跃主体 → 无任何授权可言,拒绝(403);其余为查询故障(500)。
632
+ if errors.Is(err, iamdomain.ErrPrincipalNotFound) {
633
+ return nil, sourceIP, apierror.Forbidden("Forbidden: no active principal")
634
+ }
635
+ return nil, sourceIP, apierror.Internal("Principal resolution failed")
636
+ }
637
+ return principal, sourceIP, nil
638
+ }
639
+
640
+ // ResolveRequestPrincipal 解析当前请求中的 IAM 授权主体与来源 IP。
641
+ //
642
+ // 非守卫型 handler 需要做产品范围过滤时复用该入口,保证人类身份和服务账号凭证都解析为同一种
643
+ // IAM 主体主键,避免自行读取 identity_id 后误用为 principal_id。
644
+ func ResolveRequestPrincipal(
645
+ c *gin.Context,
646
+ authz ResourceAuthorizer,
647
+ ) (*iamdomain.PrincipalRecord, string, *apierror.APIError) {
648
+ return resolveRequestPrincipal(c, authz)
649
+ }
650
+
651
+ // resolveResourceTemplate 把 ARN 模板的占位符替换为请求期实际值。
652
+ //
653
+ // {product_code} ← GetProductCode(c);其余 {name} ← c.Param("name")。
654
+ // 无对应来源的占位符替换为空串(让模板段缺值,由 Evaluate 的 ARN 模式匹配兜底)。
655
+ func resolveResourceTemplate(c *gin.Context, template string) string {
656
+ if !strings.ContainsRune(template, '{') {
657
+ return template
658
+ }
659
+ var b strings.Builder
660
+ b.Grow(len(template))
661
+ rest := template
662
+ for {
663
+ open := strings.IndexByte(rest, '{')
664
+ if open < 0 {
665
+ b.WriteString(rest)
666
+ break
667
+ }
668
+ closeIdx := strings.IndexByte(rest[open:], '}')
669
+ if closeIdx < 0 {
670
+ // 无闭合括号 → 原样输出剩余串(不臆造截断)。
671
+ b.WriteString(rest)
672
+ break
673
+ }
674
+ closeIdx += open
675
+ b.WriteString(rest[:open])
676
+ name := rest[open+1 : closeIdx]
677
+ b.WriteString(resolveTemplateToken(c, name))
678
+ rest = rest[closeIdx+1:]
679
+ }
680
+ return b.String()
681
+ }
682
+
683
+ // resolveTemplateToken 解析单个占位符 token 的实际值。
684
+ func resolveTemplateToken(c *gin.Context, name string) string {
685
+ if name == "product_code" {
686
+ return string(GetProductCode(c))
687
+ }
688
+ if name == "organization_ref" {
689
+ if access := GetIAMDelegatedAccessContext(c); access != nil {
690
+ return access.OrganizationRef
691
+ }
692
+ }
693
+ return c.Param(name)
694
+ }
695
+
696
+ // SetScopeConstraint 在 gin.Context 写入数据范围约束,供下游查询层注入 WHERE。
697
+ func SetScopeConstraint(c *gin.Context, sc iamscope.ScopeConstraint) {
698
+ c.Set(scopeConstraintKey, sc)
699
+ }
700
+
701
+ // GetScopeConstraint 读取由 RequireResourcePermission 注入的数据范围约束。
702
+ //
703
+ // 返回 ok=false 表示当前路由未经过资源授权中间件(下游查询层应据此 fail-safe 处理)。
704
+ func GetScopeConstraint(c *gin.Context) (iamscope.ScopeConstraint, bool) {
705
+ v, ok := c.Get(scopeConstraintKey)
706
+ if !ok {
707
+ return iamscope.ScopeConstraint{}, false
708
+ }
709
+ sc, ok := v.(iamscope.ScopeConstraint)
710
+ if !ok {
711
+ return iamscope.ScopeConstraint{}, false
712
+ }
713
+ return sc, true
714
+ }
715
+
716
+ // SetScopePrincipalID 在 gin.Context 写入已解析的 IAM 主体主键,供查询层填充 self 维度谓词。
717
+ func SetScopePrincipalID(c *gin.Context, principalID int64) {
718
+ c.Set(scopePrincipalIDKey, principalID)
719
+ }
720
+
721
+ // GetScopePrincipalID 读取由 RequireResourcePermission 注入的 IAM 主体主键。
722
+ //
723
+ // 返回 ok=false 表示当前路由未经过资源授权中间件(查询层应据此 fail-safe 处理,
724
+ // 与 GetScopeConstraint 的 ok 语义一致)。
725
+ func GetScopePrincipalID(c *gin.Context) (int64, bool) {
726
+ v, ok := c.Get(scopePrincipalIDKey)
727
+ if !ok {
728
+ return 0, false
729
+ }
730
+ principalID, ok := v.(int64)
731
+ if !ok {
732
+ return 0, false
733
+ }
734
+ return principalID, true
735
+ }
736
+
737
+ // SetResourcePermissionDecision 在 gin.Context 写入资源授权裁决证据,供操作日志读取。
738
+ func SetResourcePermissionDecision(c *gin.Context, decision ResourcePermissionDecision) {
739
+ c.Set(resourcePermissionDecisionKey, decision)
740
+ }
741
+
742
+ // GetResourcePermissionDecision 读取由 RequireResourcePermission 写入的资源授权裁决证据。
743
+ func GetResourcePermissionDecision(c *gin.Context) (ResourcePermissionDecision, bool) {
744
+ v, ok := c.Get(resourcePermissionDecisionKey)
745
+ if !ok {
746
+ return ResourcePermissionDecision{}, false
747
+ }
748
+ decision, ok := v.(ResourcePermissionDecision)
749
+ if !ok {
750
+ return ResourcePermissionDecision{}, false
751
+ }
752
+ return decision, true
753
+ }
754
+
755
+ func summarizeScopeConstraint(scope iamscope.ScopeConstraint) string {
756
+ switch {
757
+ case scope.IsUnbounded():
758
+ return "unbounded"
759
+ case scope.IsEmpty():
760
+ return "empty"
761
+ default:
762
+ dimensions := scopeConstraintDimensions(scope)
763
+ if len(dimensions) == 0 {
764
+ return "bounded"
765
+ }
766
+ return "allow_groups=" + strconv.Itoa(len(scope.AllowGroups)) +
767
+ ";deny_groups=" + strconv.Itoa(len(scope.DenyGroups)) +
768
+ ";dimensions=" + strings.Join(dimensions, ",")
769
+ }
770
+ }
771
+
772
+ func scopeConstraintDimensions(scope iamscope.ScopeConstraint) []string {
773
+ seen := make(map[string]struct{})
774
+ for _, group := range scope.AllowGroups {
775
+ for _, predicate := range group {
776
+ seen[string(predicate.Dimension)] = struct{}{}
777
+ }
778
+ }
779
+ for _, group := range scope.DenyGroups {
780
+ for _, predicate := range group {
781
+ seen[string(predicate.Dimension)] = struct{}{}
782
+ }
783
+ }
784
+ dimensions := make([]string, 0, len(seen))
785
+ for dimension := range seen {
786
+ dimensions = append(dimensions, dimension)
787
+ }
788
+ sort.Strings(dimensions)
789
+ return dimensions
790
+ }