@nakedev/go-scaffold 0.4.0 → 0.5.0

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 (192) hide show
  1. package/README.md +598 -306
  2. package/dist/commands/auth.js +65 -23
  3. package/dist/commands/check.js +281 -0
  4. package/dist/commands/config.js +50 -0
  5. package/dist/commands/create.js +33 -2
  6. package/dist/commands/generate.js +29 -3
  7. package/dist/commands/method.js +74 -63
  8. package/dist/commands/migration.js +2 -2
  9. package/dist/commands/observability.js +4 -53
  10. package/dist/commands/rbac.js +21 -10
  11. package/dist/commands/undo.js +11 -3
  12. package/dist/commands/worker.js +15 -5
  13. package/dist/index.js +198 -59
  14. package/dist/prompts/auth-wizard.js +40 -6
  15. package/dist/prompts/create-wizard.js +42 -1
  16. package/dist/prompts/generate-wizard.js +89 -9
  17. package/dist/templates/auth-manifest.js +50 -19
  18. package/dist/templates/create-manifest.js +8 -0
  19. package/dist/templates/module-manifest.js +84 -26
  20. package/dist/templates/rbac-manifest.js +16 -11
  21. package/dist/templates/worker-manifest.js +4 -1
  22. package/dist/types.js +8 -0
  23. package/dist/utils/auth-patcher.js +124 -33
  24. package/dist/utils/config.js +167 -4
  25. package/dist/utils/docs-patcher.js +68 -0
  26. package/dist/utils/hexagonal-method-patcher.js +334 -0
  27. package/dist/utils/main-patcher.js +32 -30
  28. package/dist/utils/marker-patch.js +7 -1
  29. package/dist/utils/module-location.js +17 -11
  30. package/dist/utils/module-profile.js +32 -0
  31. package/dist/utils/platform-patcher.js +56 -7
  32. package/dist/utils/rbac-patcher.js +89 -210
  33. package/package.json +7 -2
  34. package/templates/add/auth/cmd/seed/main.go.hbs +15 -3
  35. package/templates/add/auth/docs/login.yaml.hbs +11 -1
  36. package/templates/add/auth/docs/mfa-verify.yaml.hbs +19 -0
  37. package/templates/add/auth/docs/provider-exchange.yaml.hbs +40 -0
  38. package/templates/add/auth/docs/provider-login.yaml.hbs +31 -0
  39. package/templates/add/auth/docs/refresh.yaml.hbs +7 -0
  40. package/templates/add/auth/docs/register.yaml.hbs +7 -0
  41. package/templates/add/auth/docs/reset-password.yaml.hbs +1 -1
  42. package/templates/add/auth/docs/schemas.yaml.hbs +59 -1
  43. package/templates/add/auth/docs/users-me-mfa-confirm.yaml.hbs +19 -0
  44. package/templates/add/auth/docs/users-me-mfa-disable.yaml.hbs +15 -0
  45. package/templates/add/auth/docs/users-me-mfa-setup.yaml.hbs +14 -0
  46. package/templates/add/auth/docs/users-me-mfa.yaml.hbs +12 -0
  47. package/templates/add/auth/internal/app/user/adapters/inbound/http/browser_policy.go.hbs +98 -0
  48. package/templates/add/auth/internal/app/user/adapters/inbound/http/dto.go.hbs +159 -0
  49. package/templates/add/auth/internal/app/user/adapters/inbound/http/handler.go.hbs +228 -0
  50. package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_local.go.hbs +76 -0
  51. package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_mfa.go.hbs +83 -0
  52. package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_oauth.go.hbs +70 -0
  53. package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_recovery.go.hbs +49 -0
  54. package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_test.go.hbs +311 -0
  55. package/templates/add/auth/internal/app/user/adapters/inbound/http/handler_user.go.hbs +41 -0
  56. package/templates/add/auth/internal/app/user/adapters/inbound/http/session_cookie.go.hbs +35 -0
  57. package/templates/add/auth/internal/app/user/adapters/outbound/password/bcrypt.go.hbs +35 -0
  58. package/templates/add/auth/internal/app/user/adapters/outbound/password/bcrypt_test.go.hbs +20 -0
  59. package/templates/add/auth/internal/app/user/adapters/outbound/postgres/mfa_store.go.hbs +129 -0
  60. package/templates/add/auth/internal/app/user/adapters/outbound/postgres/mfa_store_test.go.hbs +174 -0
  61. package/templates/add/auth/internal/app/user/adapters/outbound/postgres/model.go.hbs +84 -0
  62. package/templates/add/auth/internal/app/user/adapters/outbound/postgres/repository.go.hbs +211 -0
  63. package/templates/add/auth/internal/app/user/{repository_test.go.hbs → adapters/outbound/postgres/repository_test.go.hbs} +18 -19
  64. package/templates/add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_pg.go.hbs +213 -0
  65. package/templates/add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_pg_test.go.hbs +103 -0
  66. package/templates/add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_recovery.go.hbs +84 -0
  67. package/templates/add/auth/internal/app/user/adapters/outbound/redis/tokenstore.go.hbs +228 -0
  68. package/templates/add/auth/internal/app/user/adapters/outbound/redis/tokenstore_test.go.hbs +196 -0
  69. package/templates/add/auth/internal/app/user/application/contracts.go.hbs +52 -0
  70. package/templates/add/auth/internal/app/user/application/dto.go.hbs +75 -0
  71. package/templates/add/auth/internal/app/user/application/errors.go.hbs +62 -0
  72. package/templates/add/auth/internal/app/user/application/external_login.go.hbs +198 -0
  73. package/templates/add/auth/internal/app/user/application/jwt.go.hbs +58 -0
  74. package/templates/add/auth/internal/app/user/application/local_auth.go.hbs +96 -0
  75. package/templates/add/auth/internal/app/user/application/mfa_service.go.hbs +449 -0
  76. package/templates/add/auth/internal/app/user/application/mfa_service_test.go.hbs +200 -0
  77. package/templates/add/auth/internal/app/user/application/oauth.go.hbs +132 -0
  78. package/templates/add/auth/internal/app/user/application/provider_test.go.hbs +285 -0
  79. package/templates/add/auth/internal/app/user/application/recovery.go.hbs +82 -0
  80. package/templates/add/auth/internal/app/user/application/recovery_service.go.hbs +112 -0
  81. package/templates/add/auth/internal/app/user/application/service.go.hbs +145 -0
  82. package/templates/add/auth/internal/app/user/application/service_test.go.hbs +891 -0
  83. package/templates/add/auth/internal/app/user/application/sessions.go.hbs +99 -0
  84. package/templates/add/auth/internal/app/user/application/tokenstore_ports.go.hbs +14 -0
  85. package/templates/add/auth/internal/app/user/application/user_query.go.hbs +65 -0
  86. package/templates/add/auth/internal/app/user/composition.go.hbs +168 -0
  87. package/templates/add/auth/internal/app/user/domain/entity.go.hbs +41 -0
  88. package/templates/add/auth/internal/app/user/domain/errors.go.hbs +32 -0
  89. package/templates/add/auth/internal/app/user/ports/password.go.hbs +9 -0
  90. package/templates/add/auth/internal/app/user/ports/repository.go.hbs +90 -0
  91. package/templates/add/auth/internal/platform/authprovider/google/google.go.hbs +389 -0
  92. package/templates/add/auth/internal/platform/authprovider/google/google_test.go.hbs +312 -0
  93. package/templates/add/auth/migrations/create_auth_tokens.up.sql.hbs +10 -5
  94. package/templates/add/auth/migrations/create_identities.up.sql.hbs +1 -1
  95. package/templates/add/auth/migrations/create_login_throttle.up.sql.hbs +1 -1
  96. package/templates/add/auth/migrations/create_mfa.down.sql.hbs +3 -0
  97. package/templates/add/auth/migrations/create_mfa.up.sql.hbs +29 -0
  98. package/templates/add/auth/migrations/create_users.up.sql.hbs +4 -3
  99. package/templates/add/rbac/internal/app/role/adapters/inbound/http/handler.go.hbs +142 -0
  100. package/templates/add/rbac/internal/app/role/adapters/inbound/http/handler_test.go.hbs +19 -0
  101. package/templates/add/rbac/internal/app/role/adapters/outbound/postgres/model.go.hbs +48 -0
  102. package/templates/add/rbac/internal/app/role/adapters/outbound/postgres/repository.go.hbs +127 -0
  103. package/templates/add/rbac/internal/app/role/{repository_test.go.hbs → adapters/outbound/postgres/repository_test.go.hbs} +8 -8
  104. package/templates/add/rbac/internal/app/role/application/dto.go.hbs +47 -0
  105. package/templates/add/rbac/internal/app/role/application/errors.go.hbs +19 -0
  106. package/templates/add/rbac/internal/app/role/application/service.go.hbs +157 -0
  107. package/templates/add/rbac/internal/app/role/{service_test.go.hbs → application/service_test.go.hbs} +26 -19
  108. package/templates/add/rbac/internal/app/role/composition.go.hbs +48 -0
  109. package/templates/add/rbac/internal/app/role/domain/entity.go.hbs +23 -0
  110. package/templates/add/rbac/internal/app/role/domain/errors.go.hbs +26 -0
  111. package/templates/add/rbac/internal/app/role/ports/repository.go.hbs +25 -0
  112. package/templates/add/rbac/migrations/add_roles.down.sql.hbs +3 -11
  113. package/templates/add/rbac/migrations/add_roles.up.sql.hbs +17 -6
  114. package/templates/add/worker/internal/platform/queue/river_test.go.hbs +84 -0
  115. package/templates/create/base/.claude/skills/go-scaffold/SKILL.md.hbs +358 -121
  116. package/templates/create/base/.env.example.hbs +0 -1
  117. package/templates/create/base/.golangci.yml.hbs +2 -2
  118. package/templates/create/base/AGENTS.md.hbs +279 -67
  119. package/templates/create/base/Makefile.hbs +2 -1
  120. package/templates/create/base/README.md.hbs +115 -32
  121. package/templates/create/base/cmd/api/wiring.go.hbs +13 -9
  122. package/templates/create/base/internal/composition/doc.go.hbs +7 -0
  123. package/templates/create/base/internal/platform/database/database.go.hbs +3 -3
  124. package/templates/create/base/internal/shared/apperror/apperror.go.hbs +15 -2
  125. package/templates/create/base/internal/shared/config/config.go.hbs +0 -8
  126. package/templates/create/base/internal/shared/middleware/cors_test.go.hbs +40 -0
  127. package/templates/create/base/internal/shared/middleware/error.go.hbs +15 -5
  128. package/templates/create/features/docs/architecture.md.hbs +92 -32
  129. package/templates/create/features/docs/patterns.md.hbs +137 -91
  130. package/templates/create/features/docs/techstack.md.hbs +18 -3
  131. package/templates/generate/module/hexagonal/adapters/inbound/http/dto.go.hbs +45 -0
  132. package/templates/generate/module/hexagonal/adapters/inbound/http/dto.minimal.go.hbs +28 -0
  133. package/templates/generate/module/hexagonal/adapters/inbound/http/handler.go.hbs +182 -0
  134. package/templates/generate/module/hexagonal/adapters/inbound/http/handler.minimal.go.hbs +83 -0
  135. package/templates/generate/module/hexagonal/adapters/inbound/http/handler_crud_test.go.hbs +18 -0
  136. package/templates/generate/module/hexagonal/adapters/inbound/http/handler_test.go.hbs +30 -0
  137. package/templates/generate/module/hexagonal/adapters/outbound/postgres/model.go.hbs +37 -0
  138. package/templates/generate/module/hexagonal/adapters/outbound/postgres/repository.go.hbs +95 -0
  139. package/templates/generate/module/{repository_test.go.hbs → hexagonal/adapters/outbound/postgres/repository_test.go.hbs} +8 -8
  140. package/templates/generate/module/hexagonal/application/commands.crud.go.hbs +54 -0
  141. package/templates/generate/module/hexagonal/application/commands.go.hbs +25 -0
  142. package/templates/generate/module/hexagonal/application/cqrs_test.go.hbs +66 -0
  143. package/templates/generate/module/hexagonal/application/dto.go.hbs +35 -0
  144. package/templates/generate/module/hexagonal/application/dto.minimal.go.hbs +25 -0
  145. package/templates/generate/module/hexagonal/application/queries.crud.go.hbs +33 -0
  146. package/templates/generate/module/hexagonal/application/queries.go.hbs +25 -0
  147. package/templates/generate/module/hexagonal/application/service.crud.go.hbs +73 -0
  148. package/templates/generate/module/hexagonal/application/service.go.hbs +29 -0
  149. package/templates/generate/module/hexagonal/application/service_test.go.hbs +62 -0
  150. package/templates/generate/module/hexagonal/composition.go.hbs +27 -0
  151. package/templates/generate/module/hexagonal/domain/entity.go.hbs +20 -0
  152. package/templates/generate/module/hexagonal/domain/errors.go.hbs +11 -0
  153. package/templates/generate/module/hexagonal/ports/repository.go.hbs +38 -0
  154. package/templates/generate/module/migration.up.sql.hbs +1 -1
  155. package/dist/utils/method-patcher.js +0 -357
  156. package/templates/add/auth/docs/google-callback.yaml.hbs +0 -22
  157. package/templates/add/auth/docs/google-login.yaml.hbs +0 -7
  158. package/templates/add/auth/internal/app/user/dto.go.hbs +0 -77
  159. package/templates/add/auth/internal/app/user/errors.go.hbs +0 -43
  160. package/templates/add/auth/internal/app/user/handler.go.hbs +0 -276
  161. package/templates/add/auth/internal/app/user/jwt.go.hbs +0 -108
  162. package/templates/add/auth/internal/app/user/model/authtoken.go.hbs +0 -39
  163. package/templates/add/auth/internal/app/user/model/identity.go.hbs +0 -31
  164. package/templates/add/auth/internal/app/user/model/loginthrottle.go.hbs +0 -26
  165. package/templates/add/auth/internal/app/user/model/user.go.hbs +0 -30
  166. package/templates/add/auth/internal/app/user/repository.go.hbs +0 -137
  167. package/templates/add/auth/internal/app/user/service.go.hbs +0 -531
  168. package/templates/add/auth/internal/app/user/service_test.go.hbs +0 -316
  169. package/templates/add/auth/internal/app/user/tokenstore.go.hbs +0 -30
  170. package/templates/add/auth/internal/app/user/tokenstore_pg.go.hbs +0 -144
  171. package/templates/add/auth/internal/app/user/tokenstore_redis.go.hbs +0 -147
  172. package/templates/add/rbac/internal/app/role/dto.go.hbs +0 -45
  173. package/templates/add/rbac/internal/app/role/errors.go.hbs +0 -39
  174. package/templates/add/rbac/internal/app/role/handler.go.hbs +0 -104
  175. package/templates/add/rbac/internal/app/role/model/permission.go.hbs +0 -12
  176. package/templates/add/rbac/internal/app/role/model/role.go.hbs +0 -22
  177. package/templates/add/rbac/internal/app/role/model/role_permission.go.hbs +0 -11
  178. package/templates/add/rbac/internal/app/role/repository.go.hbs +0 -97
  179. package/templates/add/rbac/internal/app/role/service.go.hbs +0 -217
  180. package/templates/generate/module/dto.go.hbs +0 -36
  181. package/templates/generate/module/errors.go.hbs +0 -33
  182. package/templates/generate/module/handler.go.hbs +0 -134
  183. package/templates/generate/module/handler_test.go.hbs +0 -174
  184. package/templates/generate/module/minimal/dto.go.hbs +0 -28
  185. package/templates/generate/module/minimal/handler.go.hbs +0 -48
  186. package/templates/generate/module/minimal/handler_test.go.hbs +0 -10
  187. package/templates/generate/module/minimal/service.go.hbs +0 -45
  188. package/templates/generate/module/minimal/service_test.go.hbs +0 -77
  189. package/templates/generate/module/model/model.go.hbs +0 -36
  190. package/templates/generate/module/repository.go.hbs +0 -103
  191. package/templates/generate/module/service.go.hbs +0 -108
  192. package/templates/generate/module/service_test.go.hbs +0 -161
@@ -6,12 +6,20 @@ exports.promptMethodType = promptMethodType;
6
6
  exports.promptGetMode = promptGetMode;
7
7
  exports.promptMigrationName = promptMigrationName;
8
8
  exports.promptLookupField = promptLookupField;
9
+ exports.promptModuleSurface = promptModuleSurface;
10
+ exports.promptApplicationStyle = promptApplicationStyle;
11
+ exports.promptModuleProfile = promptModuleProfile;
12
+ exports.promptAdvancedModuleArchitecture = promptAdvancedModuleArchitecture;
13
+ exports.moduleArchitectureForProfile = moduleArchitectureForProfile;
14
+ exports.moduleProfileDescription = moduleProfileDescription;
9
15
  exports.promptModuleShape = promptModuleShape;
16
+ exports.promptModuleCqrs = promptModuleCqrs;
10
17
  exports.promptModuleAuth = promptModuleAuth;
11
18
  exports.promptModulePermission = promptModulePermission;
12
19
  exports.promptExistingModule = promptExistingModule;
13
20
  const interactive_1 = require("./interactive");
14
21
  const naming_1 = require("../utils/naming");
22
+ const module_profile_1 = require("../utils/module-profile");
15
23
  // wraps an assert-style validator into inquirer's true|string contract so a
16
24
  // reserved word re-prompts inline instead of aborting the whole command.
17
25
  function notKeyword(value, role) {
@@ -78,29 +86,101 @@ async function promptLookupField() {
78
86
  });
79
87
  return field.trim();
80
88
  }
81
- // The three `generate module` decisions that exist as flags (--full, --auth,
82
- // --permission). They live here next to the other generate prompts so the
83
- // subcommand and the bare-menu path can ask them the same way a choice only
84
- // reachable by knowing the flag name isn't a choice for anyone driving this
85
- // from the menu.
86
- async function promptModuleShape() {
89
+ // The `generate module` choices live here next to the other generate prompts so
90
+ // the subcommand, bare menu, and project config wizard ask them consistently
91
+ // a choice only reachable by knowing a flag name is not a choice for someone
92
+ // driving the CLI interactively.
93
+ async function promptModuleSurface(defaultValue = "minimal") {
87
94
  return (0, interactive_1.select)({
88
95
  message: "What should the module contain?",
89
- default: false,
96
+ default: defaultValue,
90
97
  choices: [
91
98
  {
92
99
  name: "Minimal — model + wiring only",
93
- value: false,
100
+ value: "minimal",
94
101
  description: "the safe default; add endpoints one at a time with `generate method`",
95
102
  },
96
103
  {
97
104
  name: "CRUD skeleton — list/get/create/update/delete",
98
- value: true,
105
+ value: "crud",
99
106
  description: "all five endpoints wired up; DTO fields and business rules are left as TODO",
100
107
  },
101
108
  ],
102
109
  });
103
110
  }
111
+ async function promptApplicationStyle(defaultValue = "service") {
112
+ return (0, interactive_1.select)({
113
+ message: "How should the application boundary be organised?",
114
+ default: defaultValue,
115
+ choices: [
116
+ {
117
+ name: "Single service",
118
+ value: "service",
119
+ description: "the simpler path; use this unless reads and writes have different business needs",
120
+ },
121
+ {
122
+ name: "CQRS command/query handlers",
123
+ value: "cqrs",
124
+ description: "separate state-changing commands from read-only queries; storage remains shared by default",
125
+ },
126
+ ],
127
+ });
128
+ }
129
+ /**
130
+ * Ask for the useful decision first. The underlying surface/application
131
+ * choices remain available through Advanced and through the CLI flags, but a
132
+ * new user should not have to understand two architecture axes before making
133
+ * a sensible choice.
134
+ */
135
+ async function promptModuleProfile(defaultValue = "lean") {
136
+ return (0, interactive_1.select)({
137
+ message: "Choose a module profile:",
138
+ default: defaultValue,
139
+ choices: [
140
+ {
141
+ name: "Lean — minimal + single service",
142
+ value: "lean",
143
+ description: "model, repository, service and handler wiring; add only the endpoints this domain needs",
144
+ },
145
+ {
146
+ name: "CRUD — CRUD surface + single service",
147
+ value: "crud",
148
+ description: "list/get/create/update/delete skeletons; fields and business rules remain TODOs",
149
+ },
150
+ {
151
+ name: "CQRS — minimal surface + command/query handlers",
152
+ value: "cqrs",
153
+ description: "separate state-changing commands from read-only queries; no broker or second database is added",
154
+ },
155
+ {
156
+ name: "Advanced — choose surface and application boundary",
157
+ value: "advanced",
158
+ description: "for the uncommon CRUD + CQRS combination or a deliberately customised module",
159
+ },
160
+ ],
161
+ });
162
+ }
163
+ async function promptAdvancedModuleArchitecture(defaultSurface = "minimal", defaultApplicationStyle = "service") {
164
+ return {
165
+ moduleSurface: await promptModuleSurface(defaultSurface),
166
+ applicationStyle: await promptApplicationStyle(defaultApplicationStyle),
167
+ };
168
+ }
169
+ function moduleArchitectureForProfile(profile) {
170
+ return (0, module_profile_1.architectureForModuleProfile)(profile);
171
+ }
172
+ function moduleProfileDescription(moduleSurface, applicationStyle) {
173
+ return (0, module_profile_1.describeModuleProfile)((0, module_profile_1.moduleProfileFor)(moduleSurface, applicationStyle));
174
+ }
175
+ // Backward-compatible boolean helpers for the existing generate-module flow.
176
+ // The richer enum prompts are also used by the project config wizard so one
177
+ // set of choices describes both the default and the per-module override.
178
+ async function promptModuleShape(defaultValue = false) {
179
+ return (await promptModuleSurface(defaultValue ? "crud" : "minimal")) === "crud";
180
+ }
181
+ async function promptModuleCqrs(defaultValue = false) {
182
+ return (await promptApplicationStyle(defaultValue ? "cqrs" : "service")) === "cqrs";
183
+ }
104
184
  async function promptModuleAuth() {
105
185
  return (0, interactive_1.confirm)({
106
186
  message: "Require a valid access token for this module's routes?",
@@ -1,34 +1,65 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.authFiles = authFiles;
4
- // Everything that is the same whichever store backs the tokens.
4
+ // Auth is a complete hexagonal feature. The application package owns use
5
+ // cases and contracts, inbound owns Gin/HTTP translation, and outbound owns
6
+ // GORM/Redis details. The manifest is intentionally explicit: adding auth
7
+ // must create one canonical implementation tree.
5
8
  const SHARED = [
6
9
  { template: "add/auth/internal/shared/middleware/auth.go.hbs", output: "internal/shared/middleware/auth.go" },
7
10
  { template: "add/auth/internal/shared/middleware/ratelimit.go.hbs", output: "internal/shared/middleware/ratelimit.go" },
8
- { template: "add/auth/internal/app/user/model/user.go.hbs", output: "internal/app/user/model/user.go" },
9
- { template: "add/auth/internal/app/user/model/identity.go.hbs", output: "internal/app/user/model/identity.go" },
10
- { template: "add/auth/internal/app/user/model/loginthrottle.go.hbs", output: "internal/app/user/model/loginthrottle.go" },
11
- { template: "add/auth/internal/app/user/dto.go.hbs", output: "internal/app/user/dto.go" },
12
- { template: "add/auth/internal/app/user/errors.go.hbs", output: "internal/app/user/errors.go" },
13
- { template: "add/auth/internal/app/user/jwt.go.hbs", output: "internal/app/user/jwt.go" },
14
- { template: "add/auth/internal/app/user/tokenstore.go.hbs", output: "internal/app/user/tokenstore.go" },
15
- { template: "add/auth/internal/app/user/repository.go.hbs", output: "internal/app/user/repository.go" },
16
- { template: "add/auth/internal/app/user/service.go.hbs", output: "internal/app/user/service.go" },
17
- { template: "add/auth/internal/app/user/service_test.go.hbs", output: "internal/app/user/service_test.go" },
18
- { template: "add/auth/internal/app/user/repository_test.go.hbs", output: "internal/app/user/repository_test.go" },
19
- { template: "add/auth/internal/app/user/handler.go.hbs", output: "internal/app/user/handler.go" },
11
+ { template: "add/auth/internal/app/user/domain/entity.go.hbs", output: "internal/app/user/domain/entity.go" },
12
+ { template: "add/auth/internal/app/user/domain/errors.go.hbs", output: "internal/app/user/domain/errors.go" },
13
+ { template: "add/auth/internal/app/user/ports/repository.go.hbs", output: "internal/app/user/ports/repository.go" },
14
+ { template: "add/auth/internal/app/user/ports/password.go.hbs", output: "internal/app/user/ports/password.go" },
15
+ { template: "add/auth/internal/app/user/application/contracts.go.hbs", output: "internal/app/user/application/contracts.go" },
16
+ { template: "add/auth/internal/app/user/application/dto.go.hbs", output: "internal/app/user/application/dto.go" },
17
+ { template: "add/auth/internal/app/user/application/errors.go.hbs", output: "internal/app/user/application/errors.go" },
18
+ { template: "add/auth/internal/app/user/application/external_login.go.hbs", output: "internal/app/user/application/external_login.go" },
19
+ { template: "add/auth/internal/app/user/application/jwt.go.hbs", output: "internal/app/user/application/jwt.go" },
20
+ { template: "add/auth/internal/app/user/application/local_auth.go.hbs", output: "internal/app/user/application/local_auth.go" },
21
+ { template: "add/auth/internal/app/user/application/mfa_service.go.hbs", output: "internal/app/user/application/mfa_service.go" },
22
+ { template: "add/auth/internal/app/user/application/mfa_service_test.go.hbs", output: "internal/app/user/application/mfa_service_test.go" },
23
+ { template: "add/auth/internal/app/user/application/oauth.go.hbs", output: "internal/app/user/application/oauth.go" },
24
+ { template: "add/auth/internal/app/user/application/provider_test.go.hbs", output: "internal/app/user/application/provider_test.go" },
25
+ { template: "add/auth/internal/app/user/application/recovery.go.hbs", output: "internal/app/user/application/recovery.go" },
26
+ { template: "add/auth/internal/app/user/application/recovery_service.go.hbs", output: "internal/app/user/application/recovery_service.go" },
27
+ { template: "add/auth/internal/app/user/application/service.go.hbs", output: "internal/app/user/application/service.go" },
28
+ { template: "add/auth/internal/app/user/application/service_test.go.hbs", output: "internal/app/user/application/service_test.go" },
29
+ { template: "add/auth/internal/app/user/application/sessions.go.hbs", output: "internal/app/user/application/sessions.go" },
30
+ { template: "add/auth/internal/app/user/application/tokenstore_ports.go.hbs", output: "internal/app/user/application/tokenstore_ports.go" },
31
+ { template: "add/auth/internal/app/user/application/user_query.go.hbs", output: "internal/app/user/application/user_query.go" },
32
+ { template: "add/auth/internal/app/user/adapters/inbound/http/browser_policy.go.hbs", output: "internal/app/user/adapters/inbound/http/browser_policy.go" },
33
+ { template: "add/auth/internal/app/user/adapters/inbound/http/dto.go.hbs", output: "internal/app/user/adapters/inbound/http/dto.go" },
34
+ { template: "add/auth/internal/app/user/adapters/inbound/http/handler.go.hbs", output: "internal/app/user/adapters/inbound/http/handler.go" },
35
+ { template: "add/auth/internal/app/user/adapters/inbound/http/handler_local.go.hbs", output: "internal/app/user/adapters/inbound/http/handler_local.go" },
36
+ { template: "add/auth/internal/app/user/adapters/inbound/http/handler_mfa.go.hbs", output: "internal/app/user/adapters/inbound/http/handler_mfa.go" },
37
+ { template: "add/auth/internal/app/user/adapters/inbound/http/handler_oauth.go.hbs", output: "internal/app/user/adapters/inbound/http/handler_oauth.go" },
38
+ { template: "add/auth/internal/app/user/adapters/inbound/http/handler_recovery.go.hbs", output: "internal/app/user/adapters/inbound/http/handler_recovery.go" },
39
+ { template: "add/auth/internal/app/user/adapters/inbound/http/handler_test.go.hbs", output: "internal/app/user/adapters/inbound/http/handler_test.go" },
40
+ { template: "add/auth/internal/app/user/adapters/inbound/http/handler_user.go.hbs", output: "internal/app/user/adapters/inbound/http/handler_user.go" },
41
+ { template: "add/auth/internal/app/user/adapters/inbound/http/session_cookie.go.hbs", output: "internal/app/user/adapters/inbound/http/session_cookie.go" },
42
+ { template: "add/auth/internal/app/user/adapters/outbound/password/bcrypt.go.hbs", output: "internal/app/user/adapters/outbound/password/bcrypt.go" },
43
+ { template: "add/auth/internal/app/user/adapters/outbound/password/bcrypt_test.go.hbs", output: "internal/app/user/adapters/outbound/password/bcrypt_test.go" },
44
+ { template: "add/auth/internal/app/user/adapters/outbound/postgres/model.go.hbs", output: "internal/app/user/adapters/outbound/postgres/model.go" },
45
+ { template: "add/auth/internal/app/user/adapters/outbound/postgres/mfa_store.go.hbs", output: "internal/app/user/adapters/outbound/postgres/mfa_store.go" },
46
+ { template: "add/auth/internal/app/user/adapters/outbound/postgres/mfa_store_test.go.hbs", output: "internal/app/user/adapters/outbound/postgres/mfa_store_test.go" },
47
+ { template: "add/auth/internal/app/user/adapters/outbound/postgres/repository.go.hbs", output: "internal/app/user/adapters/outbound/postgres/repository.go" },
48
+ { template: "add/auth/internal/app/user/adapters/outbound/postgres/repository_test.go.hbs", output: "internal/app/user/adapters/outbound/postgres/repository_test.go" },
49
+ { template: "add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_recovery.go.hbs", output: "internal/app/user/adapters/outbound/postgres/tokenstore_recovery.go" },
50
+ { template: "add/auth/internal/app/user/composition.go.hbs", output: "internal/app/user/composition.go" },
51
+ { template: "add/auth/internal/platform/authprovider/google/google.go.hbs", output: "internal/platform/authprovider/google/google.go" },
52
+ { template: "add/auth/internal/platform/authprovider/google/google_test.go.hbs", output: "internal/platform/authprovider/google/google_test.go" },
20
53
  { template: "add/auth/cmd/seed/main.go.hbs", output: "cmd/seed/main.go" },
21
54
  ];
22
- // Only the chosen store's implementation is written. Shipping both would drag
23
- // go-redis into every project's go.mod for a file it never constructs — the
24
- // same reason `add worker` writes one queue adapter, not two.
25
55
  const POSTGRES = [
26
- { template: "add/auth/internal/app/user/model/authtoken.go.hbs", output: "internal/app/user/model/authtoken.go" },
27
- { template: "add/auth/internal/app/user/tokenstore_pg.go.hbs", output: "internal/app/user/tokenstore_pg.go" },
56
+ { template: "add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_pg.go.hbs", output: "internal/app/user/adapters/outbound/postgres/tokenstore_pg.go" },
57
+ { template: "add/auth/internal/app/user/adapters/outbound/postgres/tokenstore_pg_test.go.hbs", output: "internal/app/user/adapters/outbound/postgres/tokenstore_pg_test.go" },
28
58
  { template: "add/auth/internal/shared/middleware/ratelimit_memory.go.hbs", output: "internal/shared/middleware/ratelimit_memory.go" },
29
59
  ];
30
60
  const REDIS = [
31
- { template: "add/auth/internal/app/user/tokenstore_redis.go.hbs", output: "internal/app/user/tokenstore_redis.go" },
61
+ { template: "add/auth/internal/app/user/adapters/outbound/redis/tokenstore.go.hbs", output: "internal/app/user/adapters/outbound/redis/tokenstore.go" },
62
+ { template: "add/auth/internal/app/user/adapters/outbound/redis/tokenstore_test.go.hbs", output: "internal/app/user/adapters/outbound/redis/tokenstore_test.go" },
32
63
  { template: "add/auth/internal/shared/middleware/ratelimit_redis.go.hbs", output: "internal/shared/middleware/ratelimit_redis.go" },
33
64
  ];
34
65
  function authFiles(store) {
@@ -25,6 +25,10 @@ exports.CREATE_MANIFEST = [
25
25
  template: "create/base/internal/platform/database/database.go.hbs",
26
26
  output: "internal/platform/database/database.go",
27
27
  },
28
+ {
29
+ template: "create/base/internal/composition/doc.go.hbs",
30
+ output: "internal/composition/doc.go",
31
+ },
28
32
  {
29
33
  template: "create/base/internal/shared/config/config.go.hbs",
30
34
  output: "internal/shared/config/config.go",
@@ -57,6 +61,10 @@ exports.CREATE_MANIFEST = [
57
61
  template: "create/base/internal/shared/middleware/cors.go.hbs",
58
62
  output: "internal/shared/middleware/cors.go",
59
63
  },
64
+ {
65
+ template: "create/base/internal/shared/middleware/cors_test.go.hbs",
66
+ output: "internal/shared/middleware/cors_test.go",
67
+ },
60
68
  {
61
69
  template: "create/base/internal/shared/middleware/error.go.hbs",
62
70
  output: "internal/shared/middleware/error.go",
@@ -1,30 +1,88 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MODULE_FILES_MINIMAL = exports.MODULE_FILES = void 0;
4
- // output paths are relative to the module's own directory
5
- // (internal/app/<pkg> or internal/app/v<version>/<pkg>)
6
- exports.MODULE_FILES = [
7
- { template: "generate/module/model/model.go.hbs", output: "model/model.go" },
8
- { template: "generate/module/dto.go.hbs", output: "dto.go" },
9
- { template: "generate/module/errors.go.hbs", output: "errors.go" },
10
- { template: "generate/module/repository.go.hbs", output: "repository.go" },
11
- { template: "generate/module/service.go.hbs", output: "service.go" },
12
- { template: "generate/module/handler.go.hbs", output: "handler.go" },
13
- { template: "generate/module/service_test.go.hbs", output: "service_test.go" },
14
- { template: "generate/module/handler_test.go.hbs", output: "handler_test.go" },
15
- { template: "generate/module/repository_test.go.hbs", output: "repository_test.go" },
3
+ exports.MODULE_FILES_MINIMAL_CQRS = exports.MODULE_FILES_CQRS = exports.MODULE_FILES_MINIMAL = exports.MODULE_FILES = void 0;
4
+ // output paths are relative to the module's own directory.
5
+ //
6
+ // Every generated domain uses the same physical boundary. Surface and
7
+ // application style change the amount of code inside the boundary; they do
8
+ // not change where domain rules, ports, or adapters live.
9
+ const COMMON = [
10
+ { template: "generate/module/hexagonal/domain/entity.go.hbs", output: "domain/entity.go" },
11
+ { template: "generate/module/hexagonal/domain/errors.go.hbs", output: "domain/errors.go" },
12
+ { template: "generate/module/hexagonal/ports/repository.go.hbs", output: "ports/repository.go" },
13
+ {
14
+ template: "generate/module/hexagonal/adapters/outbound/postgres/model.go.hbs",
15
+ output: "adapters/outbound/postgres/model.go",
16
+ },
17
+ {
18
+ template: "generate/module/hexagonal/adapters/outbound/postgres/repository.go.hbs",
19
+ output: "adapters/outbound/postgres/repository.go",
20
+ },
21
+ {
22
+ template: "generate/module/hexagonal/adapters/inbound/http/handler_test.go.hbs",
23
+ output: "adapters/inbound/http/handler_test.go",
24
+ },
25
+ {
26
+ template: "generate/module/hexagonal/adapters/outbound/postgres/repository_test.go.hbs",
27
+ output: "adapters/outbound/postgres/repository_test.go",
28
+ },
29
+ { template: "generate/module/hexagonal/composition.go.hbs", output: "composition.go" },
16
30
  ];
17
- // minimal: same model/errors/repository (generate method's patches assume the
18
- // full data-access surface exists), but no default CRUD in dto/service/handler
19
- // — add endpoints one at a time with `generate method`.
20
- exports.MODULE_FILES_MINIMAL = [
21
- { template: "generate/module/model/model.go.hbs", output: "model/model.go" },
22
- { template: "generate/module/minimal/dto.go.hbs", output: "dto.go" },
23
- { template: "generate/module/errors.go.hbs", output: "errors.go" },
24
- { template: "generate/module/repository.go.hbs", output: "repository.go" },
25
- { template: "generate/module/minimal/service.go.hbs", output: "service.go" },
26
- { template: "generate/module/minimal/handler.go.hbs", output: "handler.go" },
27
- { template: "generate/module/minimal/service_test.go.hbs", output: "service_test.go" },
28
- { template: "generate/module/minimal/handler_test.go.hbs", output: "handler_test.go" },
29
- { template: "generate/module/repository_test.go.hbs", output: "repository_test.go" },
31
+ const SERVICE_MINIMAL = [
32
+ { template: "generate/module/hexagonal/application/dto.minimal.go.hbs", output: "application/dto.go" },
33
+ {
34
+ template: "generate/module/hexagonal/adapters/inbound/http/dto.minimal.go.hbs",
35
+ output: "adapters/inbound/http/dto.go",
36
+ },
37
+ { template: "generate/module/hexagonal/application/service.go.hbs", output: "application/service.go" },
38
+ { template: "generate/module/hexagonal/application/service_test.go.hbs", output: "application/service_test.go" },
39
+ {
40
+ template: "generate/module/hexagonal/adapters/inbound/http/handler.minimal.go.hbs",
41
+ output: "adapters/inbound/http/handler.go",
42
+ },
30
43
  ];
44
+ const SERVICE_CRUD = [
45
+ { template: "generate/module/hexagonal/application/dto.go.hbs", output: "application/dto.go" },
46
+ {
47
+ template: "generate/module/hexagonal/adapters/inbound/http/dto.go.hbs",
48
+ output: "adapters/inbound/http/dto.go",
49
+ },
50
+ { template: "generate/module/hexagonal/application/service.crud.go.hbs", output: "application/service.go" },
51
+ { template: "generate/module/hexagonal/application/service_test.go.hbs", output: "application/service_test.go" },
52
+ {
53
+ template: "generate/module/hexagonal/adapters/inbound/http/handler.go.hbs",
54
+ output: "adapters/inbound/http/handler.go",
55
+ },
56
+ ];
57
+ const CQRS_MINIMAL = [
58
+ { template: "generate/module/hexagonal/application/dto.minimal.go.hbs", output: "application/dto.go" },
59
+ {
60
+ template: "generate/module/hexagonal/adapters/inbound/http/dto.minimal.go.hbs",
61
+ output: "adapters/inbound/http/dto.go",
62
+ },
63
+ { template: "generate/module/hexagonal/application/commands.go.hbs", output: "application/commands.go" },
64
+ { template: "generate/module/hexagonal/application/queries.go.hbs", output: "application/queries.go" },
65
+ {
66
+ template: "generate/module/hexagonal/adapters/inbound/http/handler.minimal.go.hbs",
67
+ output: "adapters/inbound/http/handler.go",
68
+ },
69
+ { template: "generate/module/hexagonal/application/cqrs_test.go.hbs", output: "application/cqrs_test.go" },
70
+ ];
71
+ const CQRS_CRUD = [
72
+ { template: "generate/module/hexagonal/application/dto.go.hbs", output: "application/dto.go" },
73
+ {
74
+ template: "generate/module/hexagonal/adapters/inbound/http/dto.go.hbs",
75
+ output: "adapters/inbound/http/dto.go",
76
+ },
77
+ { template: "generate/module/hexagonal/application/commands.crud.go.hbs", output: "application/commands.go" },
78
+ { template: "generate/module/hexagonal/application/queries.crud.go.hbs", output: "application/queries.go" },
79
+ {
80
+ template: "generate/module/hexagonal/adapters/inbound/http/handler.go.hbs",
81
+ output: "adapters/inbound/http/handler.go",
82
+ },
83
+ { template: "generate/module/hexagonal/application/cqrs_test.go.hbs", output: "application/cqrs_test.go" },
84
+ ];
85
+ exports.MODULE_FILES = [...COMMON, ...SERVICE_CRUD];
86
+ exports.MODULE_FILES_MINIMAL = [...COMMON, ...SERVICE_MINIMAL];
87
+ exports.MODULE_FILES_CQRS = [...COMMON, ...CQRS_CRUD];
88
+ exports.MODULE_FILES_MINIMAL_CQRS = [...COMMON, ...CQRS_MINIMAL];
@@ -1,18 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RBAC_FILES = void 0;
4
- // output paths are relative to the project root
4
+ // output paths are relative to the project root. RBAC uses the same
5
+ // hexagonal split as every other generated module; there is one role
6
+ // implementation, not a public wrapper around duplicated code.
5
7
  exports.RBAC_FILES = [
6
8
  { template: "add/rbac/internal/shared/middleware/authz.go.hbs", output: "internal/shared/middleware/authz.go" },
7
9
  { template: "add/rbac/internal/shared/middleware/authz_test.go.hbs", output: "internal/shared/middleware/authz_test.go" },
8
- { template: "add/rbac/internal/app/role/model/role.go.hbs", output: "internal/app/role/model/role.go" },
9
- { template: "add/rbac/internal/app/role/model/permission.go.hbs", output: "internal/app/role/model/permission.go" },
10
- { template: "add/rbac/internal/app/role/model/role_permission.go.hbs", output: "internal/app/role/model/role_permission.go" },
11
- { template: "add/rbac/internal/app/role/repository.go.hbs", output: "internal/app/role/repository.go" },
12
- { template: "add/rbac/internal/app/role/service.go.hbs", output: "internal/app/role/service.go" },
13
- { template: "add/rbac/internal/app/role/service_test.go.hbs", output: "internal/app/role/service_test.go" },
14
- { template: "add/rbac/internal/app/role/repository_test.go.hbs", output: "internal/app/role/repository_test.go" },
15
- { template: "add/rbac/internal/app/role/handler.go.hbs", output: "internal/app/role/handler.go" },
16
- { template: "add/rbac/internal/app/role/dto.go.hbs", output: "internal/app/role/dto.go" },
17
- { template: "add/rbac/internal/app/role/errors.go.hbs", output: "internal/app/role/errors.go" },
10
+ { template: "add/rbac/internal/app/role/domain/entity.go.hbs", output: "internal/app/role/domain/entity.go" },
11
+ { template: "add/rbac/internal/app/role/domain/errors.go.hbs", output: "internal/app/role/domain/errors.go" },
12
+ { template: "add/rbac/internal/app/role/ports/repository.go.hbs", output: "internal/app/role/ports/repository.go" },
13
+ { template: "add/rbac/internal/app/role/application/dto.go.hbs", output: "internal/app/role/application/dto.go" },
14
+ { template: "add/rbac/internal/app/role/application/errors.go.hbs", output: "internal/app/role/application/errors.go" },
15
+ { template: "add/rbac/internal/app/role/application/service.go.hbs", output: "internal/app/role/application/service.go" },
16
+ { template: "add/rbac/internal/app/role/application/service_test.go.hbs", output: "internal/app/role/application/service_test.go" },
17
+ { template: "add/rbac/internal/app/role/adapters/inbound/http/handler.go.hbs", output: "internal/app/role/adapters/inbound/http/handler.go" },
18
+ { template: "add/rbac/internal/app/role/adapters/inbound/http/handler_test.go.hbs", output: "internal/app/role/adapters/inbound/http/handler_test.go" },
19
+ { template: "add/rbac/internal/app/role/adapters/outbound/postgres/model.go.hbs", output: "internal/app/role/adapters/outbound/postgres/model.go" },
20
+ { template: "add/rbac/internal/app/role/adapters/outbound/postgres/repository.go.hbs", output: "internal/app/role/adapters/outbound/postgres/repository.go" },
21
+ { template: "add/rbac/internal/app/role/adapters/outbound/postgres/repository_test.go.hbs", output: "internal/app/role/adapters/outbound/postgres/repository_test.go" },
22
+ { template: "add/rbac/internal/app/role/composition.go.hbs", output: "internal/app/role/composition.go" },
18
23
  ];
@@ -18,7 +18,10 @@ const SHARED = [
18
18
  // its whole dependency tree into go.mod for nothing. Swapping later means
19
19
  // re-running `add worker` with the other backend, or copying the adapter in
20
20
  // by hand — the queue.go contract it implements does not change.
21
- const RIVER = [{ template: "add/worker/internal/platform/queue/river.go.hbs", output: "internal/platform/queue/river.go" }];
21
+ const RIVER = [
22
+ { template: "add/worker/internal/platform/queue/river.go.hbs", output: "internal/platform/queue/river.go" },
23
+ { template: "add/worker/internal/platform/queue/river_test.go.hbs", output: "internal/platform/queue/river_test.go" },
24
+ ];
22
25
  const ASYNQ = [
23
26
  { template: "add/worker/internal/platform/queue/asynq.go.hbs", output: "internal/platform/queue/asynq.go" },
24
27
  // Redis only comes along when it is actually the queue's backing store.
package/dist/types.js CHANGED
@@ -1,2 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_ARCHITECTURE_CONFIG = void 0;
4
+ exports.DEFAULT_ARCHITECTURE_CONFIG = {
5
+ style: "modular-monolith",
6
+ boundary: "hexagonal",
7
+ packageLayout: "split",
8
+ defaultModuleSurface: "minimal",
9
+ defaultApplicationStyle: "service",
10
+ };