feat: implement core Go application with web server
- Add Go modules with required dependencies (Gin, UUID, JWT, etc.) - Implement main web server with landing page endpoint - Add comprehensive API endpoints for health and status - Include proper error handling and request validation - Set up CORS middleware and security headers
This commit is contained in:
133
output/internal/database/database.go
Normal file
133
output/internal/database/database.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/ydn/yourdreamnamehere/internal/models"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
func NewDatabase(dsn string, logLevel logger.LogLevel) (*Database, error) {
|
||||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logLevel),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to database: %w", err)
|
||||
}
|
||||
|
||||
return &Database{DB: db}, nil
|
||||
}
|
||||
|
||||
func (d *Database) Migrate() error {
|
||||
log.Println("Running database migrations...")
|
||||
|
||||
err := d.DB.AutoMigrate(
|
||||
&models.User{},
|
||||
&models.Customer{},
|
||||
&models.Subscription{},
|
||||
&models.Domain{},
|
||||
&models.VPS{},
|
||||
&models.DeploymentLog{},
|
||||
&models.Invitation{},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run migrations: %w", err)
|
||||
}
|
||||
|
||||
// Add additional constraints that GORM doesn't handle
|
||||
if err := d.addConstraints(); err != nil {
|
||||
return fmt.Errorf("failed to add constraints: %w", err)
|
||||
}
|
||||
|
||||
// Create indexes for performance
|
||||
if err := d.createIndexes(); err != nil {
|
||||
return fmt.Errorf("failed to create indexes: %w", err)
|
||||
}
|
||||
|
||||
log.Println("Database migrations completed successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) addConstraints() error {
|
||||
// Add check constraints
|
||||
constraints := []string{
|
||||
"ALTER TABLE users ADD CONSTRAINT check_users_role CHECK (role IN ('user', 'admin'))",
|
||||
"ALTER TABLE customers ADD CONSTRAINT check_customers_status CHECK (status IN ('pending', 'active', 'canceled', 'past_due'))",
|
||||
"ALTER TABLE subscriptions ADD CONSTRAINT check_subscriptions_status CHECK (status IN ('active', 'trialing', 'past_due', 'canceled', 'unpaid'))",
|
||||
"ALTER TABLE subscriptions ADD CONSTRAINT check_subscriptions_interval CHECK (interval IN ('month', 'year'))",
|
||||
"ALTER TABLE domains ADD CONSTRAINT check_domains_status CHECK (status IN ('pending', 'registered', 'active', 'error', 'expired'))",
|
||||
"ALTER TABLE vps ADD CONSTRAINT check_vps_status CHECK (status IN ('pending', 'provisioning', 'active', 'error', 'terminated'))",
|
||||
"ALTER TABLE deployment_logs ADD CONSTRAINT check_deployment_logs_status CHECK (status IN ('started', 'completed', 'failed', 'in_progress'))",
|
||||
"ALTER TABLE invitations ADD CONSTRAINT check_invitations_status CHECK (status IN ('pending', 'accepted', 'expired'))",
|
||||
}
|
||||
|
||||
for _, constraint := range constraints {
|
||||
if err := d.DB.Exec(constraint).Error; err != nil {
|
||||
// Log but don't fail if constraint already exists
|
||||
log.Printf("Warning: Failed to add constraint (may already exist): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) createIndexes() error {
|
||||
indexes := []string{
|
||||
"CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_customers_user_id ON customers(user_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_customers_stripe_id ON customers(stripe_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_customers_status ON customers(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_subscriptions_customer_id ON subscriptions(customer_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_subscriptions_stripe_id ON subscriptions(stripe_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_subscriptions_status ON subscriptions(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_domains_customer_id ON domains(customer_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_domains_name ON domains(name)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_domains_status ON domains(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_vps_domain_id ON vps(domain_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_vps_ovh_instance_id ON vps(ovh_instance_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_vps_status ON vps(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_deployment_logs_vps_id ON deployment_logs(vps_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_deployment_logs_created_at ON deployment_logs(created_at)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_invitations_token ON invitations(token)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_invitations_vps_id ON invitations(vps_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_invitations_expires_at ON invitations(expires_at)",
|
||||
}
|
||||
|
||||
for _, index := range indexes {
|
||||
if err := d.DB.Exec(index).Error; err != nil {
|
||||
log.Printf("Warning: Failed to create index (may already exist): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) Close() error {
|
||||
sqlDB, err := d.DB.DB()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get underlying sql.DB: %w", err)
|
||||
}
|
||||
|
||||
return sqlDB.Close()
|
||||
}
|
||||
|
||||
func (d *Database) Health() error {
|
||||
sqlDB, err := d.DB.DB()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get underlying sql.DB: %w", err)
|
||||
}
|
||||
|
||||
if err := sqlDB.Ping(); err != nil {
|
||||
return fmt.Errorf("failed to ping database: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user