package kanban import ( "time" "tm/pkg/mongo" ) // Board represents a kanban board type Board struct { mongo.Model `bson:",inline"` Name string `bson:"name" json:"name"` Description string `bson:"description" json:"description"` Columns []Column `bson:"columns" json:"columns"` IsDefault bool `bson:"is_default" json:"is_default"` // Whether this is the default board UserID string `bson:"user_id" json:"user_id"` // User who owns this board } // Column represents a column on a kanban board type Column struct { mongo.Model `bson:",inline"` BoardID string `bson:"board_id" json:"board_id"` Name string `bson:"name" json:"name"` Status string `bson:"status" json:"status"` StatusCategory string `bson:"status_category" json:"status_category"` Order int `bson:"order" json:"order"` // Display order in the board Color string `bson:"color" json:"color"` // Hex color code for the column Limit *int `bson:"limit,omitempty" json:"limit,omitempty"` // WIP limit (optional) } // Card represents a card on a kanban board (references a tender) type Card struct { mongo.Model `bson:",inline"` ColumnID string `bson:"column_id" json:"column_id"` TenderID string `bson:"tender_id" json:"tender_id"` // Reference to the tender Title string `bson:"title" json:"title"` // Cached title from tender Order int `bson:"order" json:"order"` // Position within the column Priority CardPriority `bson:"priority" json:"priority"` Labels []string `bson:"labels,omitempty" json:"labels,omitempty"` DueDate *int64 `bson:"due_date,omitempty" json:"due_date,omitempty"` // Unix timestamp } // CardPriority represents the priority level of a card type CardPriority string const ( CardPriorityLow CardPriority = "low" CardPriorityMedium CardPriority = "medium" CardPriorityHigh CardPriority = "high" CardPriorityUrgent CardPriority = "urgent" ) // GetID returns the board ID func (b *Board) GetID() string { return b.ID.Hex() } // GetID returns the column ID func (c *Column) GetID() string { return c.ID.Hex() } // GetID returns the card ID func (c *Card) GetID() string { return c.ID.Hex() } // IsOverLimit returns true if the column has a WIP limit and is over it func (c *Column) IsOverLimit(cardCount int) bool { if c.Limit == nil { return false } return cardCount > *c.Limit } // UpdateOrder updates the column's display order func (c *Column) UpdateOrder(order int) { c.Order = order c.UpdatedAt = time.Now().Unix() } // UpdateOrder updates the card's position within the column func (c *Card) UpdateOrder(order int) { c.Order = order c.UpdatedAt = time.Now().Unix() } // MoveToColumn moves the card to a different column and resets order func (c *Card) MoveToColumn(columnID string, order int) { c.ColumnID = columnID c.Order = order c.UpdatedAt = time.Now().Unix() } // UpdatePriority updates the card's priority func (c *Card) UpdatePriority(priority CardPriority) { c.Priority = priority c.UpdatedAt = time.Now().Unix() } // AddLabel adds a label to the card func (c *Card) AddLabel(label string) { if c.Labels == nil { c.Labels = []string{} } // Check if label already exists for _, l := range c.Labels { if l == label { return } } c.Labels = append(c.Labels, label) c.UpdatedAt = time.Now().Unix() } // RemoveLabel removes a label from the card func (c *Card) RemoveLabel(label string) { if c.Labels == nil { return } for i, l := range c.Labels { if l == label { c.Labels = append(c.Labels[:i], c.Labels[i+1:]...) c.UpdatedAt = time.Now().Unix() return } } }