package models import ( "time" "gorm.io/gorm" ) type Epic struct { ID uint `json:"id" gorm:"primaryKey"` ProjectID uint `json:"project_id"` Title string `json:"title" gorm:"not null"` Description string `json:"description"` Status string `json:"status" gorm:"default:'backlog'"` Priority string `json:"priority" gorm:"default:'medium'"` AssigneeID *uint `json:"assignee_id"` ReporterID uint `json:"reporter_id"` StartDate *time.Time `json:"start_date"` DueDate *time.Time `json:"due_date"` EstimatedHours *float64 `json:"estimated_hours"` ActualHours float64 `json:"actual_hours" gorm:"default:0"` ProgressPercentage int `json:"progress_percentage" gorm:"default:0"` Project Project `json:"project" gorm:"foreignKey:ProjectID"` Assignee *User `json:"assignee" gorm:"foreignKey:AssigneeID"` Reporter User `json:"reporter" gorm:"foreignKey:ReporterID"` Stories []Story `json:"stories" gorm:"foreignKey:EpicID"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type EpicStatus string const ( EpicStatusBacklog EpicStatus = "backlog" EpicStatusPlanning EpicStatus = "planning" EpicStatusInProgress EpicStatus = "in_progress" EpicStatusTesting EpicStatus = "testing" EpicStatusDone EpicStatus = "done" EpicStatusCancelled EpicStatus = "cancelled" ) func (e *Epic) BeforeCreate(tx *gorm.DB) error { return nil } func (e *Epic) UpdateProgress() error { var totalStories int64 var completedStories int64 err := DB.Model(&Story{}).Where("epic_id = ?", e.ID).Count(&totalStories).Error if err != nil { return err } if totalStories == 0 { e.ProgressPercentage = 0 return DB.Save(e).Error } err = DB.Model(&Story{}).Where("epic_id = ? AND status = 'done'", e.ID).Count(&completedStories).Error if err != nil { return err } e.ProgressPercentage = int(float64(completedStories) / float64(totalStories) * 100) return DB.Save(e).Error } func (e *Epic) GetStories() ([]Story, error) { var stories []Story err := DB.Where("epic_id = ?", e.ID).Preload("Assignee").Find(&stories).Error return stories, err } func CreateEpic(epic *Epic) error { return DB.Create(epic).Error } func GetEpicByID(id uint) (*Epic, error) { var epic Epic err := DB.Preload("Project").Preload("Assignee").Preload("Reporter"). Preload("Stories").First(&epic, id).Error return &epic, err } func GetEpicsByProject(projectID uint) ([]Epic, error) { var epics []Epic err := DB.Where("project_id = ?", projectID). Preload("Assignee").Preload("Reporter"). Find(&epics).Error return epics, err } func UpdateEpic(epic *Epic) error { return DB.Save(epic).Error } func DeleteEpic(id uint) error { return DB.Delete(&Epic{}, id).Error } func ListEpics(offset, limit int, filters map[string]interface{}) ([]Epic, int64, error) { var epics []Epic var total int64 query := DB.Model(&Epic{}) for key, value := range filters { switch key { case "project_id": query = query.Where("project_id = ?", value) case "status": query = query.Where("status = ?", value) case "priority": query = query.Where("priority = ?", value) case "assignee_id": query = query.Where("assignee_id = ?", value) } } err := query.Count(&total).Error if err != nil { return nil, 0, err } err = query.Preload("Project").Preload("Assignee").Preload("Reporter"). Offset(offset).Limit(limit).Find(&epics).Error return epics, total, err }