go-duck-cli 1.1.18 → 1.1.20

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.
@@ -96,6 +96,11 @@ services:
96
96
  - "${dbPort}:5432"
97
97
  volumes:
98
98
  - postgres_data:/var/lib/postgresql/data
99
+ healthcheck:
100
+ test: ["CMD-SHELL", "pg_isready -U ${config.datasource?.username || 'postgres'} -d ${config.datasource?.database || 'go_duck_master'}"]
101
+ interval: 5s
102
+ timeout: 5s
103
+ retries: 5
99
104
  networks:
100
105
  - go-duck-net
101
106
 
@@ -166,7 +171,8 @@ services:
166
171
  KC_DB_USERNAME: ${config.datasource?.username || 'postgres'}
167
172
  KC_DB_PASSWORD: ${config.datasource?.password || 'password'}
168
173
  depends_on:
169
- - postgres
174
+ postgres:
175
+ condition: service_healthy
170
176
  volumes:
171
177
  - ./keycloak/realm-config:/opt/keycloak/data/import
172
178
  ports:
@@ -240,7 +246,7 @@ services:
240
246
  - GO_DUCK_ELASTICSEARCH_ADDRESSES=http://elasticsearch:9200
241
247
  depends_on:
242
248
  postgres:
243
- condition: service_started
249
+ condition: service_healthy
244
250
  redis:
245
251
  condition: service_started
246
252
  mosquitto:
@@ -254,8 +260,7 @@ services:
254
260
 
255
261
  networks:
256
262
  go-duck-net:
257
- external: true
258
- name: devops_go-duck-net
263
+ driver: bridge
259
264
  `;
260
265
 
261
266
  // --- 5. MQTT Broker Config ---
@@ -179,12 +179,22 @@ func TenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
179
179
  }
180
180
 
181
181
  if len(mappings) == 0 {
182
- conn, _ := mgr.GetDB(fallbackDB)
182
+ conn, err := mgr.GetDB(fallbackDB)
183
+ if err != nil || conn == nil {
184
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to resolve tenant fallback database connection"})
185
+ c.Abort()
186
+ return
187
+ }
183
188
  siloConnections["fallback"] = conn
184
189
  c.Set("tenantDBConn", conn)
185
190
 
186
191
  if cfg.GoDuck.Datasource.MongoDB.Enabled {
187
- mClient, _ := mgr.GetMongoClient(fallbackDB)
192
+ mClient, err := mgr.GetMongoClient(fallbackDB)
193
+ if err != nil || mClient == nil {
194
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to resolve tenant fallback MongoDB connection"})
195
+ c.Abort()
196
+ return
197
+ }
188
198
  mDB := mClient.Database(fallbackDB)
189
199
  mongoConnections["fallback"] = mDB
190
200
  c.Set("tenantMongoDB", mDB)
@@ -214,11 +224,21 @@ func TenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
214
224
 
215
225
  // The FIRST one in our sorted list is the primary/lead silo for this request
216
226
  if len(mappings) > 0 {
217
- primaryConn, _ := mgr.GetDB(mappings[0].DBName)
227
+ primaryConn, err := mgr.GetDB(mappings[0].DBName)
228
+ if err != nil || primaryConn == nil {
229
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to resolve primary tenant database connection"})
230
+ c.Abort()
231
+ return
232
+ }
218
233
  c.Set("tenantDBConn", primaryConn)
219
234
 
220
235
  if cfg.GoDuck.Datasource.MongoDB.Enabled {
221
- mClient, _ := mgr.GetMongoClient(mappings[0].DBName)
236
+ mClient, err := mgr.GetMongoClient(mappings[0].DBName)
237
+ if err != nil || mClient == nil {
238
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to resolve primary tenant MongoDB connection"})
239
+ c.Abort()
240
+ return
241
+ }
222
242
  c.Set("tenantMongoDB", mClient.Database(mappings[0].DBName))
223
243
  }
224
244
 
@@ -309,7 +329,7 @@ func CreateDatabaseAndMigrate(masterDB *gorm.DB) gin.HandlerFunc {
309
329
  var exists int
310
330
  masterDB.Raw("SELECT 1 FROM pg_database WHERE datname = ?", req.DBName).Scan(&exists)
311
331
  if exists == 0 {
312
- masterDB.Exec(fmt.Sprintf("CREATE DATABASE %s", req.DBName))
332
+ masterDB.Exec(fmt.Sprintf("CREATE DATABASE \"%s\"", req.DBName))
313
333
  }
314
334
 
315
335
  // 2. Clear other primary flags for this role if setting new primary
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "go-duck-cli",
3
- "version": "1.1.18",
3
+ "version": "1.1.20",
4
4
  "description": "The Ultimate Evolutionary Go Microservice Scaffolder.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -2,8 +2,10 @@ package router
2
2
 
3
3
  import (
4
4
  "context"
5
+ "fmt"
5
6
  "log"
6
7
  "net/http"
8
+ "strings"
7
9
  "time"
8
10
 
9
11
  "github.com/gin-gonic/gin"
@@ -84,6 +86,32 @@ func SetupRouter(appConfig *config.Config) *gin.Engine {
84
86
  if err := migrations.RunGoNativeMigrations(masterDB); err != nil {
85
87
  logger.Error("Goose Migration failed: %v", err)
86
88
  }
89
+
90
+ // 10b. Initialize and Migrate Fallback DB if multi-tenancy is enabled
91
+ if appConfig.GoDuck.Multitenancy.Enabled {
92
+ fallbackDB := strings.ToLower(appConfig.GoDuck.Name) + "_fallback"
93
+ var exists int
94
+ masterDB.Raw("SELECT 1 FROM pg_database WHERE datname = ?", fallbackDB).Scan(&exists)
95
+ if exists == 0 {
96
+ if err := masterDB.Exec(fmt.Sprintf("CREATE DATABASE \"%s\"", fallbackDB)).Error; err != nil {
97
+ log.Printf("Warning: Failed to create fallback database %s: %v", fallbackDB, err)
98
+ } else {
99
+ log.Printf("✅ Created fallback database: %s", fallbackDB)
100
+ }
101
+ }
102
+
103
+ // Run tenant migrations on the fallback database
104
+ mgr := middleware.GetTenantManager(masterDB, appConfig)
105
+ if fDB, err := mgr.GetDB(fallbackDB); err == nil {
106
+ if err := migrations.RunGoNativeMigrationsForTenant(fDB); err != nil {
107
+ log.Printf("Warning: Failed to run migrations on fallback database: %v", err)
108
+ } else {
109
+ log.Printf("✅ Migrated fallback database: %s", fallbackDB)
110
+ }
111
+ } else {
112
+ log.Printf("Warning: Failed to connect to fallback database for migration: %v", err)
113
+ }
114
+ }
87
115
  }
88
116
 
89
117
  var masterMongo *mongo.Client