package model import ( "errors" "strings" "gorm.io/gorm" ) // Project represents a project in the system type Project struct { BaseModel Name string `json:"name" gorm:"not null;type:varchar(255)"` Description string `json:"description" gorm:"type:text"` OwnerID string `json:"owner_id" gorm:"not null;type:uuid;index;references:users(id)"` TypeID string `json:"type_id" gorm:"not null;type:uuid;index;references:types(id)"` Owner User `json:"owner,omitempty" gorm:"foreignKey:OwnerID"` Type Type `json:"type,omitempty" gorm:"foreignKey:TypeID"` Tasks []Task `json:"tasks,omitempty" gorm:"foreignKey:ProjectID"` Members []User `json:"members,omitempty" gorm:"many2many:project_members;"` } // ProjectCreateRequest represents the request to create a new project type ProjectCreateRequest struct { Name string `json:"name" validate:"required,min=1,max=255"` Description string `json:"description" validate:"max=1000"` OwnerID string `json:"owner_id" validate:"required,uuid"` TypeID string `json:"type_id" validate:"required,uuid"` } // ProjectUpdateRequest represents the request to update a project type ProjectUpdateRequest struct { Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"` Description *string `json:"description,omitempty" validate:"omitempty,max=1000"` TypeID *string `json:"type_id,omitempty" validate:"omitempty,uuid"` } // ProjectInfo represents public project information type ProjectInfo struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` OwnerID string `json:"owner_id"` TypeID string `json:"type_id"` Owner UserInfo `json:"owner,omitempty"` Type TypeInfo `json:"type,omitempty"` TaskCount int64 `json:"task_count"` MemberCount int64 `json:"member_count"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // ProjectMember represents the many-to-many relationship between projects and users type ProjectMember struct { ProjectID string `json:"project_id" gorm:"type:uuid;primaryKey"` UserID string `json:"user_id" gorm:"type:uuid;primaryKey"` RoleID string `json:"role_id" gorm:"type:uuid;not null;references:roles(id)"` Project Project `json:"project,omitempty" gorm:"foreignKey:ProjectID"` User User `json:"user,omitempty" gorm:"foreignKey:UserID"` Role Role `json:"role,omitempty" gorm:"foreignKey:RoleID"` } // BeforeCreate is called before creating a project func (p *Project) BeforeCreate(tx *gorm.DB) error { p.BaseModel.BeforeCreate() // Normalize name and description p.Name = strings.TrimSpace(p.Name) p.Description = strings.TrimSpace(p.Description) return p.Validate() } // BeforeUpdate is called before updating a project func (p *Project) BeforeUpdate(tx *gorm.DB) error { p.BaseModel.BeforeUpdate() // Normalize fields if they're being updated if p.Name != "" { p.Name = strings.TrimSpace(p.Name) } if p.Description != "" { p.Description = strings.TrimSpace(p.Description) } return p.Validate() } // Validate validates project data func (p *Project) Validate() error { if p.Name == "" { return errors.New("name is required") } if len(p.Name) > 255 { return errors.New("name must not exceed 255 characters") } if p.OwnerID == "" { return errors.New("owner_id is required") } if p.TypeID == "" { return errors.New("type_id is required") } return nil } // ToProjectInfo converts Project to ProjectInfo (public information) func (p *Project) ToProjectInfo() ProjectInfo { projectInfo := ProjectInfo{ ID: p.ID, Name: p.Name, Description: p.Description, OwnerID: p.OwnerID, TypeID: p.TypeID, CreatedAt: p.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), UpdatedAt: p.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"), } // Add owner info if loaded if p.Owner.ID != "" { projectInfo.Owner = p.Owner.ToUserInfo() } // Add type info if loaded if p.Type.ID != "" { projectInfo.Type = p.Type.ToTypeInfo() } return projectInfo } // HasMember checks if a user is a member of the project func (p *Project) HasMember(userID string) bool { for _, member := range p.Members { if member.ID == userID { return true } } return false } // IsOwner checks if a user is the owner of the project func (p *Project) IsOwner(userID string) bool { return p.OwnerID == userID }