- 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
160 lines
6.8 KiB
Go
160 lines
6.8 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type User struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
Email string `gorm:"uniqueIndex;not null" json:"email"`
|
|
FirstName string `gorm:"not null" json:"first_name"`
|
|
LastName string `gorm:"not null" json:"last_name"`
|
|
PasswordHash string `gorm:"not null" json:"-"`
|
|
Role string `gorm:"default:'user'" json:"role"` // user, admin
|
|
IsActive bool `gorm:"default:true" json:"is_active"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
|
|
// Relationships with constraints
|
|
Customers []Customer `gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE" json:"customers,omitempty"`
|
|
}
|
|
|
|
func (u *User) BeforeCreate(tx *gorm.DB) error {
|
|
if u.Role == "" {
|
|
u.Role = "user"
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Customer struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id"`
|
|
StripeID string `gorm:"uniqueIndex;not null" json:"stripe_id"`
|
|
Email string `gorm:"not null" json:"email"`
|
|
Status string `gorm:"default:'pending'" json:"status"` // pending, active, canceled, past_due
|
|
Balance float64 `gorm:"default:0" json:"balance"`
|
|
Currency string `gorm:"default:'usd'" json:"currency"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
|
|
|
// Relationships with proper constraints
|
|
User User `gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE" json:"user,omitempty"`
|
|
Subscriptions []Subscription `gorm:"foreignKey:CustomerID;constraint:OnDelete:CASCADE" json:"subscriptions,omitempty"`
|
|
Domains []Domain `gorm:"foreignKey:CustomerID;constraint:OnDelete:CASCADE" json:"domains,omitempty"`
|
|
}
|
|
|
|
func (c *Customer) BeforeCreate(tx *gorm.DB) error {
|
|
if c.Status == "" {
|
|
c.Status = "pending"
|
|
}
|
|
if c.Currency == "" {
|
|
c.Currency = "usd"
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Subscription struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
CustomerID uuid.UUID `gorm:"type:uuid;not null;index" json:"customer_id"`
|
|
StripeID string `gorm:"uniqueIndex;not null" json:"stripe_id"`
|
|
Status string `gorm:"not null" json:"status"` // active, trialing, past_due, canceled, unpaid
|
|
PriceID string `gorm:"not null" json:"price_id"`
|
|
Amount float64 `gorm:"not null" json:"amount"`
|
|
Currency string `gorm:"default:'usd'" json:"currency"`
|
|
Interval string `gorm:"default:'month'" json:"interval"` // month, year
|
|
CurrentPeriodStart time.Time `json:"current_period_start"`
|
|
CurrentPeriodEnd time.Time `json:"current_period_end"`
|
|
CancelAtPeriodEnd bool `gorm:"default:false" json:"cancel_at_period_end"`
|
|
CanceledAt *time.Time `json:"canceled_at,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
|
|
// Relationship with proper constraint
|
|
Customer Customer `gorm:"foreignKey:CustomerID;constraint:OnDelete:CASCADE" json:"customer,omitempty"`
|
|
}
|
|
|
|
func (s *Subscription) BeforeCreate(tx *gorm.DB) error {
|
|
if s.Status == "" {
|
|
s.Status = "active"
|
|
}
|
|
if s.Currency == "" {
|
|
s.Currency = "usd"
|
|
}
|
|
if s.Interval == "" {
|
|
s.Interval = "month"
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Domain struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
CustomerID uuid.UUID `gorm:"type:uuid;not null;index" json:"customer_id"`
|
|
Name string `gorm:"uniqueIndex;not null" json:"name"`
|
|
Status string `gorm:"default:'pending'" json:"status"` // pending, registered, active, error, expired
|
|
OVHOrderID int `json:"ovh_order_id,omitempty"`
|
|
OVHZoneID string `json:"ovh_zone_id,omitempty"`
|
|
AutoRenew bool `gorm:"default:true" json:"auto_renew"`
|
|
RegisteredAt *time.Time `json:"registered_at,omitempty"`
|
|
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
|
|
|
// Relationships with proper constraints
|
|
Customer Customer `gorm:"foreignKey:CustomerID;constraint:OnDelete:CASCADE" json:"customer,omitempty"`
|
|
VPS []VPS `gorm:"foreignKey:DomainID;constraint:OnDelete:CASCADE" json:"vps,omitempty"`
|
|
}
|
|
|
|
func (d *Domain) BeforeCreate(tx *gorm.DB) error {
|
|
if d.Status == "" {
|
|
d.Status = "pending"
|
|
}
|
|
d.AutoRenew = true
|
|
return nil
|
|
}
|
|
|
|
type VPS struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
DomainID uuid.UUID `gorm:"type:uuid;not null" json:"domain_id"`
|
|
OVHInstanceID string `gorm:"uniqueIndex;not null" json:"ovh_instance_id"`
|
|
Name string `gorm:"not null" json:"name"`
|
|
Status string `gorm:"default:'pending'" json:"status"` // pending, provisioning, active, error, terminated
|
|
IPAddress string `json:"ip_address,omitempty"`
|
|
SSHKey string `gorm:"not null" json:"-"`
|
|
CloudronURL string `json:"cloudron_url,omitempty"`
|
|
CloudronStatus string `json:"cloudron_status,omitempty"` // installing, ready, error
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
TerminatedAt *time.Time `json:"terminated_at,omitempty"`
|
|
|
|
Domain Domain `gorm:"foreignKey:DomainID" json:"domain,omitempty"`
|
|
}
|
|
|
|
type DeploymentLog struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
VPSID uuid.UUID `gorm:"type:uuid;not null" json:"vps_id"`
|
|
Step string `gorm:"not null" json:"step"` // vps_provision, cloudron_install, dns_config, etc
|
|
Status string `gorm:"not null" json:"status"` // started, completed, failed
|
|
Message string `gorm:"type:text" json:"message,omitempty"`
|
|
Details string `gorm:"type:text" json:"details,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
|
|
VPS VPS `gorm:"foreignKey:VPSID" json:"vps,omitempty"`
|
|
}
|
|
|
|
type Invitation struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
VPSID uuid.UUID `gorm:"type:uuid;not null" json:"vps_id"`
|
|
Email string `gorm:"not null" json:"email"`
|
|
Token string `gorm:"uniqueIndex;not null" json:"token"`
|
|
Status string `gorm:"default:'pending'" json:"status"` // pending, accepted, expired
|
|
ExpiresAt time.Time `json:"expires_at"`
|
|
AcceptedAt *time.Time `json:"accepted_at,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
|
|
VPS VPS `gorm:"foreignKey:VPSID" json:"vps,omitempty"`
|
|
} |