package models import ( "time" "gorm.io/gorm" ) type Task struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"` Title string `json:"title" gorm:"not null"` Description string `json:"description"` Status string `json:"status" gorm:"default:'todo'"` // todo, in_progress, review, done Priority string `json:"priority" gorm:"default:'medium'"` // low, medium, high, urgent DueDate *time.Time `json:"due_date"` CompletedAt *time.Time `json:"completed_at"` Position int `json:"position" gorm:"default:0"` // For ordering in kanban board // Foreign Keys ProjectID uint `json:"project_id" gorm:"not null"` AssignedToID *uint `json:"assigned_to_id"` CreatedByID uint `json:"created_by_id" gorm:"not null"` // Relationships Project Project `json:"project" gorm:"foreignKey:ProjectID"` AssignedTo *User `json:"assigned_to" gorm:"foreignKey:AssignedToID"` CreatedBy User `json:"created_by" gorm:"foreignKey:CreatedByID"` Comments []Comment `json:"comments" gorm:"foreignKey:TaskID"` Files []FileUpload `json:"files" gorm:"foreignKey:TaskID"` Subtasks []Subtask `json:"subtasks" gorm:"foreignKey:ParentTaskID"` Labels []Label `json:"labels" gorm:"many2many:task_labels"` } type Subtask struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"` Title string `json:"title" gorm:"not null"` Description string `json:"description"` Status string `json:"status" gorm:"default:'todo'"` // todo, in_progress, done Position int `json:"position" gorm:"default:0"` CompletedAt *time.Time `json:"completed_at"` // Foreign Keys ParentTaskID uint `json:"parent_task_id" gorm:"not null"` AssignedToID *uint `json:"assigned_to_id"` // Relationships ParentTask Task `json:"parent_task" gorm:"foreignKey:ParentTaskID"` AssignedTo *User `json:"assigned_to" gorm:"foreignKey:AssignedToID"` } type Label struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"` Name string `json:"name" gorm:"not null"` Color string `json:"color" gorm:"default:'#6b7280'"` // Hex color // Foreign Keys ProjectID uint `json:"project_id" gorm:"not null"` // Relationships Project Project `json:"project" gorm:"foreignKey:ProjectID"` Tasks []Task `json:"tasks" gorm:"many2many:task_labels"` } type Comment struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"` Content string `json:"content" gorm:"not null"` // Foreign Keys TaskID uint `json:"task_id" gorm:"not null"` UserID uint `json:"user_id" gorm:"not null"` // Relationships Task Task `json:"task" gorm:"foreignKey:TaskID"` User User `json:"user" gorm:"foreignKey:UserID"` } // IsOverdue checks if the task is overdue func (t *Task) IsOverdue() bool { if t.DueDate == nil { return false } return t.Status != "done" && t.DueDate.Before(time.Now()) } // GetCompletionPercentage returns the completion percentage based on subtasks func (t *Task) GetCompletionPercentage() int { if len(t.Subtasks) == 0 { if t.Status == "done" { return 100 } return 0 } completed := 0 for _, subtask := range t.Subtasks { if subtask.Status == "done" { completed++ } } return (completed * 100) / len(t.Subtasks) } // MarkAsCompleted marks the task as completed func (t *Task) MarkAsCompleted() { t.Status = "done" now := time.Now() t.CompletedAt = &now }