package db import ( "fmt" "omega-server/local/model" "omega-server/local/utl/logging" "os" "time" "go.uber.org/dig" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" ) func Start(di *dig.Container) { // PostgreSQL connection configuration host := os.Getenv("DB_HOST") if host == "" { host = "localhost" } port := os.Getenv("DB_PORT") if port == "" { port = "5432" } user := os.Getenv("DB_USER") if user == "" { user = "postgres" } password := os.Getenv("DB_PASSWORD") if password == "" { password = "password" } dbName := os.Getenv("DB_NAME") if dbName == "" { dbName = "omega_db" } sslMode := os.Getenv("DB_SSL_MODE") if sslMode == "" { sslMode = "disable" } dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=%s TimeZone=UTC", host, user, password, dbName, port, sslMode) // Configure GORM logger gormLogger := logger.Default if os.Getenv("LOG_LEVEL") == "DEBUG" { gormLogger = logger.Default.LogMode(logger.Info) } else { gormLogger = logger.Default.LogMode(logger.Silent) } db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ Logger: gormLogger, }) if err != nil { logging.Error("Failed to connect to PostgreSQL database") logging.Error("Connection string: host=%s user=%s dbname=%s port=%s sslmode=%s", host, user, dbName, port, sslMode) logging.Error("Error: %v", err) logging.Error("Make sure PostgreSQL is running and the database exists") logging.Panic("failed to connect database: " + err.Error()) } // Configure connection pool sqlDB, err := db.DB() if err != nil { logging.Panic("failed to get database instance: " + err.Error()) } // Set connection pool settings sqlDB.SetMaxIdleConns(10) sqlDB.SetMaxOpenConns(100) sqlDB.SetConnMaxLifetime(time.Hour) err = di.Provide(func() *gorm.DB { return db }) if err != nil { logging.Panic("failed to bind database: " + err.Error()) } logging.Info("Database connected successfully") Migrate(db) } func Migrate(db *gorm.DB) { logging.Info("Starting database migration...") err := db.AutoMigrate( &model.User{}, &model.Role{}, &model.Permission{}, &model.Type{}, &model.Project{}, &model.Task{}, &model.Integration{}, &model.ProjectMember{}, &model.TaskAssignee{}, &model.SystemConfig{}, &model.AuditLog{}, &model.SecurityEvent{}, ) if err != nil { logging.Panic("failed to migrate database models: " + err.Error()) } logging.Info("Database migration completed successfully") Seed(db) } func Seed(db *gorm.DB) error { logging.Info("Starting database seeding...") if err := seedRoles(db); err != nil { return err } if err := seedPermissions(db); err != nil { return err } if err := seedDefaultAdmin(db); err != nil { return err } if err := seedDefaultTypes(db); err != nil { return err } if err := seedSystemConfigs(db); err != nil { return err } logging.Info("Database seeding completed successfully") return nil } func seedRoles(db *gorm.DB) error { roles := []model.Role{ {Name: "admin", Description: "Administrator with full access"}, {Name: "user", Description: "Regular user with limited access"}, {Name: "viewer", Description: "Read-only access"}, } for _, role := range roles { var existingRole model.Role err := db.Where("name = ?", role.Name).First(&existingRole).Error if err == gorm.ErrRecordNotFound { role.Init() if err := db.Create(&role).Error; err != nil { return err } logging.Info("Created role: %s", role.Name) } } return nil } func seedPermissions(db *gorm.DB) error { permissions := []model.Permission{ {Name: "user:create", Description: "Create new users"}, {Name: "user:read", Description: "Read user information"}, {Name: "user:update", Description: "Update user information"}, {Name: "user:delete", Description: "Delete users"}, {Name: "role:create", Description: "Create new roles"}, {Name: "role:read", Description: "Read role information"}, {Name: "role:update", Description: "Update role information"}, {Name: "role:delete", Description: "Delete roles"}, {Name: "system:config", Description: "Access system configuration"}, {Name: "system:logs", Description: "Access system logs"}, {Name: "system:admin", Description: "Full system administration"}, } for _, permission := range permissions { var existingPermission model.Permission err := db.Where("name = ?", permission.Name).First(&existingPermission).Error if err == gorm.ErrRecordNotFound { permission.Init() if err := db.Create(&permission).Error; err != nil { return err } logging.Info("Created permission: %s", permission.Name) } } // Assign all permissions to admin role var adminRole model.Role if err := db.Where("name = ?", "admin").First(&adminRole).Error; err != nil { return err } var allPermissions []model.Permission if err := db.Find(&allPermissions).Error; err != nil { return err } if err := db.Model(&adminRole).Association("Permissions").Replace(allPermissions); err != nil { return err } // Assign basic permissions to user role var userRole model.Role if err := db.Where("name = ?", "user").First(&userRole).Error; err != nil { return err } var userPermissions []model.Permission userPermissionNames := []string{"user:read", "role:read"} if err := db.Where("name IN ?", userPermissionNames).Find(&userPermissions).Error; err != nil { return err } if err := db.Model(&userRole).Association("Permissions").Replace(userPermissions); err != nil { return err } // Assign read permissions to viewer role var viewerRole model.Role if err := db.Where("name = ?", "viewer").First(&viewerRole).Error; err != nil { return err } var viewerPermissions []model.Permission viewerPermissionNames := []string{"user:read", "role:read"} if err := db.Where("name IN ?", viewerPermissionNames).Find(&viewerPermissions).Error; err != nil { return err } if err := db.Model(&viewerRole).Association("Permissions").Replace(viewerPermissions); err != nil { return err } return nil } func seedDefaultTypes(db *gorm.DB) error { defaultTypes := []model.Type{ {Name: "Web Development", Description: "Standard web development project"}, {Name: "Mobile App", Description: "Mobile application development"}, {Name: "API Development", Description: "API and backend service development"}, {Name: "Data Science", Description: "Data analysis and machine learning projects"}, {Name: "DevOps", Description: "Infrastructure and deployment projects"}, {Name: "Research", Description: "Research and documentation projects"}, } for _, projectType := range defaultTypes { var existingType model.Type err := db.Where("name = ? AND user_id IS NULL", projectType.Name).First(&existingType).Error if err == gorm.ErrRecordNotFound { projectType.Init() if err := db.Create(&projectType).Error; err != nil { return err } logging.Info("Created default project type: %s", projectType.Name) } } return nil } func seedDefaultAdmin(db *gorm.DB) error { // Check if admin user already exists var existingAdmin model.User err := db.Where("email = ?", "admin@example.com").First(&existingAdmin).Error if err != gorm.ErrRecordNotFound { return nil // Admin already exists or other error } // Get admin role var adminRole model.Role if err := db.Where("name = ?", "admin").First(&adminRole).Error; err != nil { return err } // Create default admin user defaultPassword := os.Getenv("DEFAULT_ADMIN_PASSWORD") if defaultPassword == "" { defaultPassword = "admin123" } admin := model.User{ Email: "admin@example.com", FullName: "System Administrator", PasswordHash: "", } admin.Init() if err := admin.SetPassword(defaultPassword); err != nil { return err } if err := db.Create(&admin).Error; err != nil { return err } // Assign admin role if err := db.Model(&admin).Association("Roles").Append(&adminRole); err != nil { return err } logging.Info("Created default admin user with email: %s", admin.Email) logging.Warn("Default admin password is: %s - PLEASE CHANGE THIS IMMEDIATELY!", defaultPassword) return nil } func seedSystemConfigs(db *gorm.DB) error { configs := []model.SystemConfig{ { Key: "app.name", Value: "Bootstrap App", DefaultValue: "Bootstrap App", Description: "Application name", Category: "general", DataType: "string", IsEditable: true, DateModified: time.Now().UTC().Format(time.RFC3339), }, { Key: "app.version", Value: "1.0.0", DefaultValue: "1.0.0", Description: "Application version", Category: "general", DataType: "string", IsEditable: false, DateModified: time.Now().UTC().Format(time.RFC3339), }, { Key: "security.jwt_expiry_hours", Value: "24", DefaultValue: "24", Description: "JWT token expiry time in hours", Category: "security", DataType: "integer", IsEditable: true, DateModified: time.Now().UTC().Format(time.RFC3339), }, { Key: "security.password_min_length", Value: "8", DefaultValue: "8", Description: "Minimum password length", Category: "security", DataType: "integer", IsEditable: true, DateModified: time.Now().UTC().Format(time.RFC3339), }, { Key: "security.max_login_attempts", Value: "5", DefaultValue: "5", Description: "Maximum login attempts before lockout", Category: "security", DataType: "integer", IsEditable: true, DateModified: time.Now().UTC().Format(time.RFC3339), }, { Key: "security.lockout_duration_minutes", Value: "30", DefaultValue: "30", Description: "Account lockout duration in minutes", Category: "security", DataType: "integer", IsEditable: true, DateModified: time.Now().UTC().Format(time.RFC3339), }, } for _, config := range configs { var existingConfig model.SystemConfig err := db.Where("key = ?", config.Key).First(&existingConfig).Error if err == gorm.ErrRecordNotFound { config.Init() if err := db.Create(&config).Error; err != nil { return err } logging.Info("Created system config: %s", config.Key) } } return nil }