package main import ( "context" "fmt" "log" "time" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "golang.org/x/crypto/bcrypt" "tm/internal/domain" ) const ( DefaultMongoURI = "mongodb://localhost:27017" DefaultDBName = "tender_management" ) func main() { // Get database connection details from environment or use defaults mongoURI := DefaultMongoURI if uri := getEnv("MONGO_URI"); uri != "" { mongoURI = uri } dbName := DefaultDBName if name := getEnv("DB_NAME"); name != "" { dbName = name } fmt.Println("🚀 Starting database migration for dual user system...") fmt.Printf("📊 Database: %s\n", dbName) fmt.Printf("🔗 URI: %s\n", mongoURI) // Connect to MongoDB ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoURI)) if err != nil { log.Fatal("❌ Failed to connect to MongoDB:", err) } defer client.Disconnect(context.Background()) // Ping to verify connection if err = client.Ping(ctx, nil); err != nil { log.Fatal("❌ Failed to ping MongoDB:", err) } fmt.Println("✅ Connected to MongoDB successfully") db := client.Database(dbName) // Run migrations if err := createCustomersCollection(db); err != nil { log.Fatal("❌ Failed to create customers collection:", err) } if err := createUsersCollection(db); err != nil { log.Fatal("❌ Failed to create users collection:", err) } if err := createSampleData(db); err != nil { log.Fatal("❌ Failed to create sample data:", err) } fmt.Println("🎉 Database migration completed successfully!") } // createCustomersCollection creates the customers collection with indexes func createCustomersCollection(db *mongo.Database) error { fmt.Println("📝 Creating customers collection...") collection := db.Collection("customers") // Create indexes indexes := []mongo.IndexModel{ { Keys: bson.D{{"email", 1}}, Options: options.Index().SetUnique(true).SetName("email_unique"), }, { Keys: bson.D{{"company_id", 1}}, Options: options.Index().SetName("company_id_idx"), }, { Keys: bson.D{{"is_active", 1}}, Options: options.Index().SetName("is_active_idx"), }, { Keys: bson.D{{"created_at", -1}}, Options: options.Index().SetName("created_at_desc_idx"), }, { Keys: bson.D{{"role", 1}}, Options: options.Index().SetName("role_idx"), }, } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() _, err := collection.Indexes().CreateMany(ctx, indexes) if err != nil { return fmt.Errorf("failed to create customer indexes: %w", err) } fmt.Println("✅ Customers collection created with indexes") return nil } // createUsersCollection creates the panel users collection with indexes func createUsersCollection(db *mongo.Database) error { fmt.Println("📝 Creating users collection...") collection := db.Collection("users") // Create indexes indexes := []mongo.IndexModel{ { Keys: bson.D{{"email", 1}}, Options: options.Index().SetUnique(true).SetName("email_unique"), }, { Keys: bson.D{{"role", 1}}, Options: options.Index().SetName("role_idx"), }, { Keys: bson.D{{"is_active", 1}}, Options: options.Index().SetName("is_active_idx"), }, { Keys: bson.D{{"department", 1}}, Options: options.Index().SetName("department_idx"), }, { Keys: bson.D{{"created_at", -1}}, Options: options.Index().SetName("created_at_desc_idx"), }, { Keys: bson.D{{"created_by", 1}}, Options: options.Index().SetName("created_by_idx"), }, } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() _, err := collection.Indexes().CreateMany(ctx, indexes) if err != nil { return fmt.Errorf("failed to create user indexes: %w", err) } fmt.Println("✅ Users collection created with indexes") return nil } // createSampleData creates sample admin user and test customer func createSampleData(db *mongo.Database) error { fmt.Println("📝 Creating sample data...") // Create sample admin user if err := createSampleAdmin(db); err != nil { return fmt.Errorf("failed to create sample admin: %w", err) } // Create sample customer if err := createSampleCustomer(db); err != nil { return fmt.Errorf("failed to create sample customer: %w", err) } fmt.Println("✅ Sample data created successfully") return nil } // createSampleAdmin creates a sample admin user func createSampleAdmin(db *mongo.Database) error { collection := db.Collection("users") // Check if admin already exists ctx := context.Background() count, err := collection.CountDocuments(ctx, bson.M{"email": "admin@tendermanagement.com"}) if err != nil { return err } if count > 0 { fmt.Println("â„šī¸ Sample admin user already exists, skipping...") return nil } // Hash password for admin hashedPassword, err := bcrypt.GenerateFromPassword([]byte("admin123!"), bcrypt.DefaultCost) if err != nil { return err } now := time.Now() adminID := uuid.New() admin := bson.M{ "_id": adminID, "email": "admin@tendermanagement.com", "password": string(hashedPassword), "first_name": "System", "last_name": "Administrator", "role": domain.UserRoleAdmin, "department": "IT", "is_active": true, "permissions": []string{ "manage_users", "manage_tenders", "manage_companies", "manage_customers", "view_reports", "manage_system", "manage_sources", }, "created_at": now, "updated_at": now, } _, err = collection.InsertOne(ctx, admin) if err != nil { return err } fmt.Println("👤 Sample admin user created:") fmt.Println(" 📧 Email: admin@tendermanagement.com") fmt.Println(" 🔑 Password: admin123!") fmt.Println(" đŸ›Ąī¸ Role: admin") return nil } // createSampleCustomer creates a sample customer func createSampleCustomer(db *mongo.Database) error { collection := db.Collection("customers") // Check if customer already exists ctx := context.Background() count, err := collection.CountDocuments(ctx, bson.M{"email": "customer@example.com"}) if err != nil { return err } if count > 0 { fmt.Println("â„šī¸ Sample customer already exists, skipping...") return nil } // Hash password for customer hashedPassword, err := bcrypt.GenerateFromPassword([]byte("customer123!"), bcrypt.DefaultCost) if err != nil { return err } now := time.Now() companyID := uuid.New() customerID := uuid.New() // Create sample company first companyCollection := db.Collection("companies") company := bson.M{ "_id": companyID, "name": "Sample Company Ltd", "description": "A sample company for testing", "industry": "Technology", "country": "United States", "website": "https://example.com", "keywords": []string{"technology", "software", "consulting"}, "products": []string{"software development", "consulting"}, "services": []string{"web development", "mobile apps"}, "created_at": now, "updated_at": now, } _, err = companyCollection.InsertOne(ctx, company) if err != nil { return err } // Create customer customer := bson.M{ "_id": customerID, "email": "customer@example.com", "password": string(hashedPassword), "first_name": "John", "last_name": "Doe", "phone": "+1234567890", "role": domain.CustomerRoleUser, "company_id": companyID, "is_active": true, "is_verified": true, "device_tokens": []string{}, "preferences": bson.M{ "language": "en", "notification_settings": bson.M{ "new_tenders": true, "deadline_reminder": true, "status_updates": true, "system_alerts": true, }, "tender_alerts": true, "email_notifications": true, "push_notifications": true, "preferred_categories": []string{}, }, "created_at": now, "updated_at": now, } _, err = collection.InsertOne(ctx, customer) if err != nil { return err } fmt.Println("👤 Sample customer created:") fmt.Println(" 📧 Email: customer@example.com") fmt.Println(" 🔑 Password: customer123!") fmt.Println(" đŸĸ Company: Sample Company Ltd") fmt.Println(" 📱 Role: customer_user") return nil } // Helper functions func getEnv(key string) string { // Simple environment variable getter // In a real implementation, you might use os.Getenv() return "" }