go-duck-cli 1.2.25 → 1.3.2

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 (217) hide show
  1. package/README.md +6 -0
  2. package/generators/ai_docs.js +6 -0
  3. package/generators/config.js +3 -1
  4. package/generators/devops.js +68 -20
  5. package/generators/security.js +2 -2
  6. package/go-duck-planner/css/bootstrap.min.css +6 -0
  7. package/go-duck-planner/css/main.css +1 -0
  8. package/go-duck-planner/favicon.ico +0 -0
  9. package/go-duck-planner/fonts/icomoonf33b-2.html +0 -0
  10. package/go-duck-planner/fonts/icomoonf33b-3.html +0 -0
  11. package/go-duck-planner/fonts/icomoonf33b-4.html +0 -0
  12. package/go-duck-planner/fonts/icomoonf33b.html +0 -0
  13. package/go-duck-planner/fonts/open-sans/OpenSans-Bold.html +0 -0
  14. package/go-duck-planner/fonts/open-sans/OpenSans-ExtraBold.html +0 -0
  15. package/go-duck-planner/fonts/open-sans/OpenSans-Light.html +0 -0
  16. package/go-duck-planner/fonts/open-sans/OpenSans-Regular.html +0 -0
  17. package/go-duck-planner/fonts/open-sans/OpenSans-SemiBold.html +0 -0
  18. package/go-duck-planner/fonts/rubik-mono/RubikMonoOne-Regular.html +0 -0
  19. package/go-duck-planner/fonts/style.css +2735 -0
  20. package/go-duck-planner/img/cancel.html +0 -0
  21. package/go-duck-planner/img/consulting.html +0 -0
  22. package/go-duck-planner/img/consulting2.html +0 -0
  23. package/go-duck-planner/img/dashed-circles-dark.html +0 -0
  24. package/go-duck-planner/img/docs/doc.html +0 -0
  25. package/go-duck-planner/img/docs/pdf.html +0 -0
  26. package/go-duck-planner/img/docs/ppt.html +0 -0
  27. package/go-duck-planner/img/docs/xls.html +0 -0
  28. package/go-duck-planner/img/docs/zip.html +0 -0
  29. package/go-duck-planner/img/empty-chat-display.html +0 -0
  30. package/go-duck-planner/img/error-screen/stars.html +0 -0
  31. package/go-duck-planner/img/fav.png +0 -0
  32. package/go-duck-planner/img/flags/1x1/au.html +0 -0
  33. package/go-duck-planner/img/flags/1x1/br.html +0 -0
  34. package/go-duck-planner/img/flags/1x1/bv.html +131 -0
  35. package/go-duck-planner/img/flags/1x1/ca.html +0 -0
  36. package/go-duck-planner/img/flags/1x1/cw.html +131 -0
  37. package/go-duck-planner/img/flags/1x1/eu.html +131 -0
  38. package/go-duck-planner/img/flags/1x1/hn.html +131 -0
  39. package/go-duck-planner/img/flags/1x1/in.html +0 -0
  40. package/go-duck-planner/img/flags/1x1/ni.html +131 -0
  41. package/go-duck-planner/img/flags/1x1/se.html +131 -0
  42. package/go-duck-planner/img/flags/1x1/za.html +131 -0
  43. package/go-duck-planner/img/folder.html +0 -0
  44. package/go-duck-planner/img/followers.html +0 -0
  45. package/go-duck-planner/img/food/biscuit.html +0 -0
  46. package/go-duck-planner/img/food/cupcake.html +0 -0
  47. package/go-duck-planner/img/food/donut.html +0 -0
  48. package/go-duck-planner/img/food/ice-cream.html +0 -0
  49. package/go-duck-planner/img/food/pizza.html +0 -0
  50. package/go-duck-planner/img/food/tea-cup.html +0 -0
  51. package/go-duck-planner/img/hover-on-tabs.html +0 -0
  52. package/go-duck-planner/img/icon-search.html +0 -0
  53. package/go-duck-planner/img/lines-bg.html +0 -0
  54. package/go-duck-planner/img/lines-bg2.html +0 -0
  55. package/go-duck-planner/img/login-bg.html +0 -0
  56. package/go-duck-planner/img/logo-compact.html +0 -0
  57. package/go-duck-planner/img/logo-large.html +0 -0
  58. package/go-duck-planner/img/logo.png +0 -0
  59. package/go-duck-planner/img/logo.svg +19 -0
  60. package/go-duck-planner/img/pattern.html +0 -0
  61. package/go-duck-planner/img/products/bag.html +0 -0
  62. package/go-duck-planner/img/products/camera.html +0 -0
  63. package/go-duck-planner/img/products/clock.html +0 -0
  64. package/go-duck-planner/img/products/drone.html +0 -0
  65. package/go-duck-planner/img/products/pencils.html +0 -0
  66. package/go-duck-planner/img/products/ring.html +0 -0
  67. package/go-duck-planner/img/products/shirt.html +0 -0
  68. package/go-duck-planner/img/products/shoes.html +0 -0
  69. package/go-duck-planner/img/products/toy.html +0 -0
  70. package/go-duck-planner/img/realestate/img1.html +0 -0
  71. package/go-duck-planner/img/realestate/img10.html +0 -0
  72. package/go-duck-planner/img/realestate/img11.html +0 -0
  73. package/go-duck-planner/img/realestate/img12.html +0 -0
  74. package/go-duck-planner/img/realestate/img2.html +0 -0
  75. package/go-duck-planner/img/realestate/img3.html +0 -0
  76. package/go-duck-planner/img/realestate/img4.html +0 -0
  77. package/go-duck-planner/img/realestate/img5.html +0 -0
  78. package/go-duck-planner/img/realestate/img6.html +0 -0
  79. package/go-duck-planner/img/realestate/img7.html +0 -0
  80. package/go-duck-planner/img/realestate/img8.html +0 -0
  81. package/go-duck-planner/img/realestate/img9.html +0 -0
  82. package/go-duck-planner/img/shade.html +0 -0
  83. package/go-duck-planner/img/stock/img1.html +0 -0
  84. package/go-duck-planner/img/stock/img10.html +0 -0
  85. package/go-duck-planner/img/stock/img11.html +0 -0
  86. package/go-duck-planner/img/stock/img12.html +0 -0
  87. package/go-duck-planner/img/stock/img13.html +0 -0
  88. package/go-duck-planner/img/stock/img14.html +0 -0
  89. package/go-duck-planner/img/stock/img2.html +0 -0
  90. package/go-duck-planner/img/stock/img3.html +0 -0
  91. package/go-duck-planner/img/stock/img4.html +0 -0
  92. package/go-duck-planner/img/stock/img5.html +0 -0
  93. package/go-duck-planner/img/stock/img6.html +0 -0
  94. package/go-duck-planner/img/stock/img7.html +0 -0
  95. package/go-duck-planner/img/stock/img8.html +0 -0
  96. package/go-duck-planner/img/stock/img9.html +0 -0
  97. package/go-duck-planner/img/svg/box.html +0 -0
  98. package/go-duck-planner/img/svg/commisions.html +0 -0
  99. package/go-duck-planner/img/svg/customer.html +0 -0
  100. package/go-duck-planner/img/svg/income.html +0 -0
  101. package/go-duck-planner/img/trophy.html +0 -0
  102. package/go-duck-planner/img/user-2.html +0 -0
  103. package/go-duck-planner/img/user.html +0 -0
  104. package/go-duck-planner/img/user1.html +0 -0
  105. package/go-duck-planner/img/user10.html +0 -0
  106. package/go-duck-planner/img/user12.html +0 -0
  107. package/go-duck-planner/img/user13.html +0 -0
  108. package/go-duck-planner/img/user14.html +0 -0
  109. package/go-duck-planner/img/user15.html +0 -0
  110. package/go-duck-planner/img/user16.html +0 -0
  111. package/go-duck-planner/img/user17.html +0 -0
  112. package/go-duck-planner/img/user18.html +0 -0
  113. package/go-duck-planner/img/user19.html +0 -0
  114. package/go-duck-planner/img/user2.html +0 -0
  115. package/go-duck-planner/img/user20.html +0 -0
  116. package/go-duck-planner/img/user21.html +0 -0
  117. package/go-duck-planner/img/user22.html +0 -0
  118. package/go-duck-planner/img/user23.html +0 -0
  119. package/go-duck-planner/img/user24.html +0 -0
  120. package/go-duck-planner/img/user3.html +0 -0
  121. package/go-duck-planner/img/user4.html +0 -0
  122. package/go-duck-planner/img/user5.html +0 -0
  123. package/go-duck-planner/img/user6.html +0 -0
  124. package/go-duck-planner/img/user7.html +0 -0
  125. package/go-duck-planner/img/user8.html +0 -0
  126. package/go-duck-planner/img/user9.html +0 -0
  127. package/go-duck-planner/index.html +30 -0
  128. package/go-duck-planner/js/bootstrap.bundle.min.html +0 -0
  129. package/go-duck-planner/js/jquery.min.html +0 -0
  130. package/go-duck-planner/js/main.html +0 -0
  131. package/go-duck-planner/js/modernizr.html +0 -0
  132. package/go-duck-planner/js/moment.html +0 -0
  133. package/go-duck-planner/main-HHOZYGRI.js +47 -0
  134. package/go-duck-planner/styles-3LK4NBNX.css +1 -0
  135. package/go-duck-planner/vendor/apex/apexcharts.min.html +0 -0
  136. package/go-duck-planner/vendor/apex/custom/analytics/byChannelGraph.html +0 -0
  137. package/go-duck-planner/vendor/apex/custom/analytics/byCountryGraph.html +0 -0
  138. package/go-duck-planner/vendor/apex/custom/analytics/byDeviceGraph.html +0 -0
  139. package/go-duck-planner/vendor/apex/custom/analytics/ordersGraph.html +0 -0
  140. package/go-duck-planner/vendor/apex/custom/analytics/targets.html +0 -0
  141. package/go-duck-planner/vendor/apex/custom/crm/sales.html +0 -0
  142. package/go-duck-planner/vendor/apex/custom/crm/sparkline-graphs.html +0 -0
  143. package/go-duck-planner/vendor/apex/custom/home/customersGraph.html +0 -0
  144. package/go-duck-planner/vendor/apex/custom/home/earningsGraph.html +0 -0
  145. package/go-duck-planner/vendor/apex/custom/home/ordersGraph.html +0 -0
  146. package/go-duck-planner/vendor/apex/custom/home/salesGraph.html +0 -0
  147. package/go-duck-planner/vendor/apex/custom/home/sparkline.html +0 -0
  148. package/go-duck-planner/vendor/apex/custom/home/visitorsGraph.html +0 -0
  149. package/go-duck-planner/vendor/apex/custom/profile/revenue.html +0 -0
  150. package/go-duck-planner/vendor/apex/custom/reports/orders.html +0 -0
  151. package/go-duck-planner/vendor/apex/custom/reports/revenue.html +0 -0
  152. package/go-duck-planner/vendor/apex/custom/reports/sales.html +0 -0
  153. package/go-duck-planner/vendor/apex/custom/reports/sales2.html +0 -0
  154. package/go-duck-planner/vendor/apex/custom/reports/sparkline.html +0 -0
  155. package/go-duck-planner/vendor/apex/custom/saas/revenue.html +0 -0
  156. package/go-duck-planner/vendor/apex/custom/saas/sales.html +0 -0
  157. package/go-duck-planner/vendor/apex/custom/sales/revenue.html +0 -0
  158. package/go-duck-planner/vendor/apex/custom/sales/tickets.html +0 -0
  159. package/go-duck-planner/vendor/bs-select/bs-select-custom.html +0 -0
  160. package/go-duck-planner/vendor/bs-select/bs-select.html +0 -0
  161. package/go-duck-planner/vendor/bs-select/bs-select.min.html +0 -0
  162. package/go-duck-planner/vendor/calendar/css/custom.html +0 -0
  163. package/go-duck-planner/vendor/calendar/css/main.min.html +0 -0
  164. package/go-duck-planner/vendor/calendar/custom/custom-schedule-calendar.html +0 -0
  165. package/go-duck-planner/vendor/calendar/custom/daygrid-calendar.html +0 -0
  166. package/go-duck-planner/vendor/calendar/custom/draggable-calendar.html +0 -0
  167. package/go-duck-planner/vendor/calendar/custom/google-view-calendar.html +0 -0
  168. package/go-duck-planner/vendor/calendar/custom/list-view-calendar.html +0 -0
  169. package/go-duck-planner/vendor/calendar/custom/selectable-calendar.html +0 -0
  170. package/go-duck-planner/vendor/calendar/js/main.min.html +0 -0
  171. package/go-duck-planner/vendor/circliful/circliful.custom.html +0 -0
  172. package/go-duck-planner/vendor/circliful/circliful.min.html +0 -0
  173. package/go-duck-planner/vendor/datatables/buttons.bs.html +0 -0
  174. package/go-duck-planner/vendor/datatables/buttons.min.html +0 -0
  175. package/go-duck-planner/vendor/datatables/buttons.print.min.html +0 -0
  176. package/go-duck-planner/vendor/datatables/custom/custom-datatables.html +0 -0
  177. package/go-duck-planner/vendor/datatables/dataTables.bootstrap.min.html +0 -0
  178. package/go-duck-planner/vendor/datatables/dataTables.bs4-custom.html +0 -0
  179. package/go-duck-planner/vendor/datatables/dataTables.bs4.html +0 -0
  180. package/go-duck-planner/vendor/datatables/dataTables.min.html +0 -0
  181. package/go-duck-planner/vendor/datatables/html5.min.html +0 -0
  182. package/go-duck-planner/vendor/datatables/jszip.min.html +0 -0
  183. package/go-duck-planner/vendor/datatables/pdfmake.min.html +0 -0
  184. package/go-duck-planner/vendor/datatables/vfs_fonts.html +0 -0
  185. package/go-duck-planner/vendor/daterange/custom-daterange.html +0 -0
  186. package/go-duck-planner/vendor/daterange/daterange-2.html +0 -0
  187. package/go-duck-planner/vendor/daterange/daterange.html +0 -0
  188. package/go-duck-planner/vendor/dropzone/dropzone.min-2.html +0 -0
  189. package/go-duck-planner/vendor/dropzone/dropzone.min.html +0 -0
  190. package/go-duck-planner/vendor/gallery/baguetteBox.html +0 -0
  191. package/go-duck-planner/vendor/gallery/custom-gallery.html +0 -0
  192. package/go-duck-planner/vendor/gallery/gallery.html +0 -0
  193. package/go-duck-planner/vendor/gallery/plugins.html +0 -0
  194. package/go-duck-planner/vendor/input-tags/tagsinput-custom.html +0 -0
  195. package/go-duck-planner/vendor/input-tags/tagsinput.html +0 -0
  196. package/go-duck-planner/vendor/input-tags/tagsinput.min.html +0 -0
  197. package/go-duck-planner/vendor/input-tags/typeahead.html +0 -0
  198. package/go-duck-planner/vendor/megamenu/css/megamenu.css +591 -0
  199. package/go-duck-planner/vendor/megamenu/js/custom.html +0 -0
  200. package/go-duck-planner/vendor/megamenu/js/megamenu.html +0 -0
  201. package/go-duck-planner/vendor/rating/raty-custom.html +0 -0
  202. package/go-duck-planner/vendor/rating/raty.html +0 -0
  203. package/go-duck-planner/vendor/search-filter/custom-search-filter.css +122 -0
  204. package/go-duck-planner/vendor/search-filter/custom-search-filter.html +0 -0
  205. package/go-duck-planner/vendor/search-filter/search-filter.css +497 -0
  206. package/go-duck-planner/vendor/search-filter/search-filter.html +0 -0
  207. package/go-duck-planner/vendor/slimscroll/custom-scrollbar.html +0 -0
  208. package/go-duck-planner/vendor/slimscroll/slimscroll.min.html +0 -0
  209. package/go-duck-planner/vendor/summernote/summernote-bs4-2.html +0 -0
  210. package/go-duck-planner/vendor/summernote/summernote-bs4.html +0 -0
  211. package/go-duck-planner/vendor/wizard/jquery.steps.custom.html +0 -0
  212. package/go-duck-planner/vendor/wizard/jquery.steps.html +0 -0
  213. package/go-duck-planner/vendor/wizard/jquery.steps.min.html +0 -0
  214. package/index.js +37 -3
  215. package/package.json +1 -1
  216. package/templates/docs/pages/index.hbs +10 -0
  217. package/templates/go/router.go.hbs +8 -3
package/README.md CHANGED
@@ -120,6 +120,12 @@ Follow these four steps to get a generated microservice running locally and in K
120
120
 
121
121
  Follow these steps to create and run a new microservice with GO-DUCK:
122
122
 
123
+ ```bash
124
+ # 0. Design your schema visually (Optional)
125
+ go-duck gdl-planner -p 8000
126
+ ```
127
+ This launches a browser-based drag-and-drop canvas at `http://localhost:8000` where you can visually design your entities, relationships, nested BSON objects, and Enums, and then export it directly into a `.gdl` file!
128
+
123
129
  ```bash
124
130
  # 1. Create a new microservice
125
131
  go-duck create -o ./my-app -c config.yaml
@@ -43,6 +43,12 @@ export const generateAIDocs = async (config, entities, outputDir, enums, openEnt
43
43
  archContent += `- **Elasticsearch Sync**: ${config.search?.elasticsearch?.enabled ? 'Enabled (via @Searchable)' : 'Disabled'}\n`;
44
44
  archContent += `- **OpenTelemetry**: ${config.telemetry?.otel?.enabled ? 'Enabled' : 'Disabled'}\n`;
45
45
 
46
+ archContent += `\n## Deployment (Kubernetes)\n`;
47
+ archContent += `- **Network Isolation**: Strict per-service isolated namespaces (e.g., \`[shortName]-[service]-k8s\`).\n`;
48
+ archContent += `- **Internal Routing**: Services communicate via explicit Fully Qualified Domain Names (FQDN).\n`;
49
+ archContent += `- **External Exposure**: Infrastructure services are exposed via explicit NodePort mappings (Range: 30000+).\n`;
50
+ archContent += `- **Self-Contained Manifests**: All manifests inject their own \`kind: Namespace\` block for auto-provisioning.\n`;
51
+
46
52
  await fs.writeFile(path.join(aiDocsDir, 'ARCHITECTURE.md'), archContent);
47
53
 
48
54
  // 2. ENDPOINTS.md
@@ -2,7 +2,7 @@ import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import chalk from 'chalk';
4
4
 
5
- export const generateConfigLoader = async (outputDir) => {
5
+ export const generateConfigLoader = async (outputDir, configObj) => {
6
6
  const configDir = path.join(outputDir, 'config');
7
7
  await fs.ensureDir(configDir);
8
8
 
@@ -28,6 +28,7 @@ type Config struct {
28
28
  REST struct {
29
29
  Port int \`mapstructure:"port"\`
30
30
  Protocol string \`mapstructure:"protocol"\`
31
+ ApiPathPrefix string \`mapstructure:"api-path-prefix"\`
31
32
  } \`mapstructure:"rest"\`
32
33
  GRPC struct {
33
34
  Addr string \`mapstructure:"addr"\`
@@ -242,6 +243,7 @@ func LoadConfig() (*Config, error) {
242
243
  // Default values
243
244
  v.SetDefault("go-duck.server.rest.port", 8080)
244
245
  v.SetDefault("go-duck.server.rest.protocol", "json")
246
+ v.SetDefault("go-duck.server.rest.api-path-prefix", "/${configObj.name || 'api'}/api")
245
247
  v.SetDefault("go-duck.security.rate-limit.rps", 100.0)
246
248
  v.SetDefault("go-duck.security.rate-limit.burst", 200)
247
249
  v.SetDefault("go-duck.logging.datadog.enabled", false)
@@ -14,6 +14,8 @@ export const generateDeploymentArtifacts = async (config, projectRootDir) => {
14
14
  await fs.ensureDir(githubDir);
15
15
 
16
16
  const appName = config.name || 'go-duck';
17
+ const parts = appName.split(/[-_]/);
18
+ const shortName = (parts.length > 1 ? parts.map(w => w[0]).join('') : appName).substring(0, 10).toLowerCase() || 'goduck';
17
19
  const appPort = config.server?.port || 8080;
18
20
  const keycloakHost = config.security?.['keycloak-host'] || 'http://localhost:8180';
19
21
  const keycloakPort = keycloakHost.includes(':') ? keycloakHost.split(':').pop() : '8080';
@@ -117,6 +119,7 @@ services:
117
119
  mosquitto:
118
120
  image: eclipse-mosquitto:2.0.18
119
121
  container_name: ${appName}-mqtt
122
+ command: ["sh", "-c", "mosquitto_passwd -c -b /tmp/mosquitto_passwd ${config.messaging?.mqtt?.username || 'dev_user'} ${config.messaging?.mqtt?.password || 'dev_password'} && chown 1883:1883 /tmp/mosquitto_passwd && exec /usr/sbin/mosquitto -c /mosquitto/config/mosquitto.conf"]
120
123
  ports:
121
124
  - "${mqttPort}:1883"
122
125
  - "9001:9001"
@@ -269,7 +272,8 @@ networks:
269
272
  listener 1883
270
273
  listener 9001
271
274
  protocol websockets
272
- allow_anonymous true
275
+ allow_anonymous false
276
+ password_file /tmp/mosquitto_passwd
273
277
  `;
274
278
 
275
279
  // --- 6. GitHub Actions CI/CD ---
@@ -454,7 +458,7 @@ spec:
454
458
  - name: GO_DUCK_SERVER_REST_PORT
455
459
  value: "${appPort}"
456
460
  - name: GO_DUCK_DATASOURCE_HOST
457
- value: postgres
461
+ value: postgres.${shortName}-postgres-k8s.svc.cluster.local
458
462
  - name: GO_DUCK_DATASOURCE_USERNAME
459
463
  value: "${config.datasource?.username || 'postgres'}"
460
464
  - name: GO_DUCK_DATASOURCE_PASSWORD
@@ -464,17 +468,17 @@ spec:
464
468
  - name: GO_DUCK_DATASOURCE_PORT
465
469
  value: "5432"
466
470
  - name: GO_DUCK_CACHE_REDIS_HOST
467
- value: redis:6379
471
+ value: redis.${shortName}-redis-k8s.svc.cluster.local:6379
468
472
  - name: GO_DUCK_MESSAGING_MQTT_BROKER
469
- value: tcp://mosquitto:1883
473
+ value: tcp://mosquitto.${shortName}-mosquitto-k8s.svc.cluster.local:1883
470
474
  - name: GO_DUCK_MESSAGING_NATS_URL
471
- value: nats://nats:4222
475
+ value: nats://nats.${shortName}-nats-k8s.svc.cluster.local:4222
472
476
  - name: GO_DUCK_TELEMETRY_OTEL_ENDPOINT
473
- value: otel-collector:4317
477
+ value: otel-collector.${shortName}-otel-collector-k8s.svc.cluster.local:4317
474
478
  - name: GO_DUCK_ELASTICSEARCH_ADDRESSES
475
- value: http://elasticsearch:9200
479
+ value: http://elasticsearch.${shortName}-elasticsearch-k8s.svc.cluster.local:9200
476
480
  - name: GO_DUCK_SECURITY_KEYCLOAK_HOST
477
- value: http://keycloak:8080
481
+ value: http://keycloak.${shortName}-keycloak-k8s.svc.cluster.local:8080
478
482
  ports:
479
483
  - name: http
480
484
  containerPort: ${appPort}
@@ -486,13 +490,16 @@ kind: Service
486
490
  metadata:
487
491
  name: ${appName}
488
492
  spec:
493
+ type: NodePort
489
494
  ports:
490
495
  - name: http
491
496
  port: ${appPort}
492
497
  targetPort: http
498
+ nodePort: 30080
493
499
  - name: grpc
494
500
  port: 9000
495
501
  targetPort: grpc
502
+ nodePort: 30090
496
503
  selector:
497
504
  app: ${appName}
498
505
  `;
@@ -549,8 +556,10 @@ kind: Service
549
556
  metadata:
550
557
  name: postgres
551
558
  spec:
559
+ type: NodePort
552
560
  ports:
553
561
  - port: 5432
562
+ nodePort: 30432
554
563
  selector:
555
564
  app: postgres
556
565
  `;
@@ -582,8 +591,10 @@ kind: Service
582
591
  metadata:
583
592
  name: redis
584
593
  spec:
594
+ type: NodePort
585
595
  ports:
586
596
  - port: 6379
597
+ nodePort: 30379
587
598
  selector:
588
599
  app: redis
589
600
  `;
@@ -615,8 +626,10 @@ kind: Service
615
626
  metadata:
616
627
  name: nats
617
628
  spec:
629
+ type: NodePort
618
630
  ports:
619
631
  - port: 4222
632
+ nodePort: 30222
620
633
  selector:
621
634
  app: nats
622
635
  `;
@@ -630,7 +643,8 @@ data:
630
643
  listener 1883
631
644
  listener 9001
632
645
  protocol websockets
633
- allow_anonymous true
646
+ allow_anonymous false
647
+ password_file /tmp/mosquitto_passwd
634
648
  ---
635
649
  apiVersion: apps/v1
636
650
  kind: Deployment
@@ -651,6 +665,7 @@ spec:
651
665
  containers:
652
666
  - name: mosquitto
653
667
  image: eclipse-mosquitto:2.0.18
668
+ command: ["sh", "-c", "mosquitto_passwd -c -b /tmp/mosquitto_passwd ${config.messaging?.mqtt?.username || 'dev_user'} ${config.messaging?.mqtt?.password || 'dev_password'} && chown 1883:1883 /tmp/mosquitto_passwd && exec /usr/sbin/mosquitto -c /mosquitto/config/mosquitto.conf"]
654
669
  ports:
655
670
  - containerPort: 1883
656
671
  - containerPort: 9001
@@ -668,11 +683,14 @@ kind: Service
668
683
  metadata:
669
684
  name: mosquitto
670
685
  spec:
686
+ type: NodePort
671
687
  ports:
672
688
  - name: mqtt
673
689
  port: 1883
690
+ nodePort: 31883
674
691
  - name: ws
675
692
  port: 9001
693
+ nodePort: 30001
676
694
  selector:
677
695
  app: mosquitto
678
696
  `;
@@ -711,8 +729,10 @@ kind: Service
711
729
  metadata:
712
730
  name: elasticsearch
713
731
  spec:
732
+ type: NodePort
714
733
  ports:
715
734
  - port: 9200
735
+ nodePort: 30200
716
736
  selector:
717
737
  app: elasticsearch
718
738
  `;
@@ -748,11 +768,14 @@ kind: Service
748
768
  metadata:
749
769
  name: jaeger
750
770
  spec:
771
+ type: NodePort
751
772
  ports:
752
773
  - name: ui
753
774
  port: 16686
775
+ nodePort: 30686
754
776
  - name: otlp-grpc
755
777
  port: 4317
778
+ nodePort: 30317
756
779
  selector:
757
780
  app: jaeger
758
781
  `;
@@ -824,11 +847,14 @@ kind: Service
824
847
  metadata:
825
848
  name: otel-collector
826
849
  spec:
850
+ type: NodePort
827
851
  ports:
828
852
  - name: otlp-grpc
829
853
  port: 4317
854
+ nodePort: 30317
830
855
  - name: otlp-http
831
856
  port: 4318
857
+ nodePort: 30318
832
858
  selector:
833
859
  app: otel-collector
834
860
  `;
@@ -890,8 +916,10 @@ kind: Service
890
916
  metadata:
891
917
  name: keycloak
892
918
  spec:
919
+ type: NodePort
893
920
  ports:
894
921
  - port: 8080
922
+ nodePort: 30880
895
923
  selector:
896
924
  app: keycloak
897
925
  `;
@@ -909,17 +937,33 @@ spec:
909
937
  await fs.writeFile(path.join(devopsDir, 'app.yml'), appYaml);
910
938
  await fs.writeFile(path.join(devopsDir, 'docker-compose.yml'), dockerCompose);
911
939
  await fs.writeFile(path.join(k8sDir, 'mosquitto.conf'), mosquittoConf);
940
+ // Namespace calculation: unique namespace per service
941
+ const applyNs = (yamlString, serviceName) => {
942
+ const nsName = `${shortName}-${serviceName}-k8s`;
943
+ const nsBlock = `apiVersion: v1\nkind: Namespace\nmetadata:\n name: ${nsName}\n---\n`;
944
+ return nsBlock + yamlString.replace(/^metadata:$/gm, `metadata:\n namespace: ${nsName}`);
945
+ };
946
+
947
+ const servicesList = ['app', 'postgres', 'redis', 'nats', 'mosquitto', 'elasticsearch', 'jaeger', 'otel-collector', 'keycloak'];
948
+ if (config.datasource?.mongodb?.enabled) servicesList.push('mongodb');
912
949
 
950
+ // We conditionally add minio if storage is enabled (or any blob provider), but for safety we'll just generate its namespace always.
951
+ servicesList.push('minio');
952
+
953
+ const k8sNamespaceYaml = servicesList.map(svc => `apiVersion: v1\nkind: Namespace\nmetadata:\n name: ${shortName}-${svc}-k8s`).join('\n---\n');
954
+
955
+ await fs.writeFile(path.join(k8sDir, 'namespace.yaml'), k8sNamespaceYaml);
956
+
913
957
  // Write Kubernetes manifest assets
914
- await fs.writeFile(path.join(k8sDir, 'app.yaml'), k8sAppYaml);
915
- await fs.writeFile(path.join(k8sDir, 'postgres.yaml'), k8sPostgresYaml);
916
- await fs.writeFile(path.join(k8sDir, 'redis.yaml'), k8sRedisYaml);
917
- await fs.writeFile(path.join(k8sDir, 'nats.yaml'), k8sNatsYaml);
918
- await fs.writeFile(path.join(k8sDir, 'mosquitto.yaml'), k8sMosquittoYaml);
919
- await fs.writeFile(path.join(k8sDir, 'elasticsearch.yaml'), k8sElasticsearchYaml);
920
- await fs.writeFile(path.join(k8sDir, 'jaeger.yaml'), k8sJaegerYaml);
921
- await fs.writeFile(path.join(k8sDir, 'otel-collector-k8s.yaml'), k8sOtelCollectorYaml);
922
- await fs.writeFile(path.join(k8sDir, 'keycloak.yaml'), k8sKeycloakYaml);
958
+ await fs.writeFile(path.join(k8sDir, 'app.yaml'), applyNs(k8sAppYaml, 'app'));
959
+ await fs.writeFile(path.join(k8sDir, 'postgres.yaml'), applyNs(k8sPostgresYaml, 'postgres'));
960
+ await fs.writeFile(path.join(k8sDir, 'redis.yaml'), applyNs(k8sRedisYaml, 'redis'));
961
+ await fs.writeFile(path.join(k8sDir, 'nats.yaml'), applyNs(k8sNatsYaml, 'nats'));
962
+ await fs.writeFile(path.join(k8sDir, 'mosquitto.yaml'), applyNs(k8sMosquittoYaml, 'mosquitto'));
963
+ await fs.writeFile(path.join(k8sDir, 'elasticsearch.yaml'), applyNs(k8sElasticsearchYaml, 'elasticsearch'));
964
+ await fs.writeFile(path.join(k8sDir, 'jaeger.yaml'), applyNs(k8sJaegerYaml, 'jaeger'));
965
+ await fs.writeFile(path.join(k8sDir, 'otel-collector-k8s.yaml'), applyNs(k8sOtelCollectorYaml, 'otel-collector'));
966
+ await fs.writeFile(path.join(k8sDir, 'keycloak.yaml'), applyNs(k8sKeycloakYaml, 'keycloak'));
923
967
 
924
968
  // Additional optional services manifests
925
969
  const k8sMongoYaml = `apiVersion: apps/v1
@@ -949,8 +993,10 @@ kind: Service
949
993
  metadata:
950
994
  name: mongodb
951
995
  spec:
996
+ type: NodePort
952
997
  ports:
953
998
  - port: 27017
999
+ nodePort: 30017
954
1000
  selector:
955
1001
  app: mongodb`;
956
1002
  const k8sMinioYaml = `apiVersion: apps/v1
@@ -988,12 +1034,14 @@ kind: Service
988
1034
  metadata:
989
1035
  name: minio
990
1036
  spec:
1037
+ type: NodePort
991
1038
  ports:
992
1039
  - port: 9000
1040
+ nodePort: 30900
993
1041
  selector:
994
1042
  app: minio`;
995
- await fs.writeFile(path.join(k8sDir, 'mongodb.yaml'), k8sMongoYaml);
996
- await fs.writeFile(path.join(k8sDir, 'minio.yaml'), k8sMinioYaml);
1043
+ await fs.writeFile(path.join(k8sDir, 'mongodb.yaml'), applyNs(k8sMongoYaml, 'mongodb'));
1044
+ await fs.writeFile(path.join(k8sDir, 'minio.yaml'), applyNs(k8sMinioYaml, 'minio'));
997
1045
 
998
1046
  await fs.writeFile(path.join(githubDir, 'ci.yml'), ciWorkflow);
999
1047
  await fs.writeFile(path.join(githubDir, 'cd.yml'), cdWorkflow);
@@ -21,7 +21,7 @@ import (
21
21
  "time"
22
22
 
23
23
  "github.com/gin-gonic/gin"
24
- "github.com/golang-jwt/jwt/v4"
24
+ "github.com/golang-jwt/jwt/v5"
25
25
  "{{app_name}}/config"
26
26
  )
27
27
 
@@ -164,7 +164,7 @@ func JWTMiddleware() gin.HandlerFunc {
164
164
  return nil, fmt.Errorf("missing kid header")
165
165
  }
166
166
  return GetPublicKeyByKid(kid, config.GetConfig())
167
- })
167
+ }, jwt.WithLeeway(10*time.Second))
168
168
 
169
169
  if err != nil || !token.Valid {
170
170
  c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})