feat: task system
All checks were successful
Build and Push App Image / build-and-push (push) Successful in 1m55s

This commit is contained in:
domrichardson
2026-03-27 16:33:11 +00:00
parent d793b5ccf2
commit 1b336299ee
15 changed files with 3876 additions and 17 deletions

View File

@@ -452,6 +452,141 @@ func NewCategoryDTO(category *entities.Category) *CategoryDTO {
}
}
// ========== TASK DTOs ==========
// CreateTaskRequest represents task creation input.
type CreateTaskRequest struct {
Title string `json:"title" validate:"required,min=1,max=255"`
Description string `json:"description" validate:"max=2000"`
CategoryID *string `json:"category_id,omitempty"`
StatusID string `json:"status_id" validate:"required"`
ParentTaskID *string `json:"parent_task_id,omitempty"`
NoteLinks []string `json:"note_links"`
}
// UpdateTaskRequest represents task update input.
type UpdateTaskRequest struct {
Title *string `json:"title,omitempty"`
Description *string `json:"description,omitempty"`
CategoryID *string `json:"category_id,omitempty"`
StatusID *string `json:"status_id,omitempty"`
ParentTaskID *string `json:"parent_task_id,omitempty"`
NoteLinks []string `json:"note_links,omitempty"`
}
// TaskTransitionRequest allows moving task status by one step.
type TaskTransitionRequest struct {
Direction string `json:"direction" validate:"required,oneof=forward backward"`
}
// LinkTaskNoteRequest links/unlinks a note from a task.
type LinkTaskNoteRequest struct {
NoteID string `json:"note_id" validate:"required"`
}
// TaskDTO represents a task in API responses.
type TaskDTO struct {
ID string `json:"id"`
SpaceID string `json:"space_id"`
Title string `json:"title"`
Description string `json:"description"`
CategoryID *string `json:"category_id,omitempty"`
StatusID string `json:"status_id"`
ParentTaskID *string `json:"parent_task_id,omitempty"`
Depth int `json:"depth"`
NoteLinks []string `json:"note_links"`
CreatedBy string `json:"created_by"`
UpdatedBy string `json:"updated_by"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// TaskWithStatusDTO includes status details and child tasks for detail views.
type TaskWithStatusDTO struct {
*TaskDTO
StatusName string `json:"status_name"`
StatusColor string `json:"status_color,omitempty"`
StatusOrder int `json:"status_order"`
Subtasks []*TaskDTO `json:"subtasks"`
}
// CreateTaskStatusRequest represents task status creation input.
type CreateTaskStatusRequest struct {
Name string `json:"name" validate:"required,min=1,max=100"`
Color string `json:"color,omitempty" validate:"max=20"`
}
// UpdateTaskStatusRequest represents task status updates.
type UpdateTaskStatusRequest struct {
Name string `json:"name" validate:"required,min=1,max=100"`
Color string `json:"color,omitempty" validate:"max=20"`
}
// ReorderTaskStatusesRequest represents a full ordered status ID list.
type ReorderTaskStatusesRequest struct {
OrderedStatusIDs []string `json:"ordered_status_ids"`
}
// TaskStatusDTO represents a task status in API responses.
type TaskStatusDTO struct {
ID string `json:"id"`
SpaceID string `json:"space_id"`
Name string `json:"name"`
Color string `json:"color,omitempty"`
Order int `json:"order"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// NewTaskDTO creates a DTO from a task entity.
func NewTaskDTO(task *entities.Task) *TaskDTO {
var categoryID *string
if task.CategoryID != nil {
id := task.CategoryID.Hex()
categoryID = &id
}
var parentTaskID *string
if task.ParentTaskID != nil {
id := task.ParentTaskID.Hex()
parentTaskID = &id
}
noteLinks := make([]string, 0, len(task.NoteLinks))
for _, noteID := range task.NoteLinks {
noteLinks = append(noteLinks, noteID.Hex())
}
return &TaskDTO{
ID: task.ID.Hex(),
SpaceID: task.SpaceID.Hex(),
Title: task.Title,
Description: task.Description,
CategoryID: categoryID,
StatusID: task.StatusID.Hex(),
ParentTaskID: parentTaskID,
Depth: task.Depth,
NoteLinks: noteLinks,
CreatedBy: task.CreatedBy.Hex(),
UpdatedBy: task.UpdatedBy.Hex(),
CreatedAt: task.CreatedAt.Format("2006-01-02T15:04:05Z"),
UpdatedAt: task.UpdatedAt.Format("2006-01-02T15:04:05Z"),
}
}
// NewTaskStatusDTO creates a DTO from a task status entity.
func NewTaskStatusDTO(status *entities.TaskStatus) *TaskStatusDTO {
return &TaskStatusDTO{
ID: status.ID.Hex(),
SpaceID: status.SpaceID.Hex(),
Name: status.Name,
Color: status.Color,
Order: status.Order,
CreatedAt: status.CreatedAt.Format("2006-01-02T15:04:05Z"),
UpdatedAt: status.UpdatedAt.Format("2006-01-02T15:04:05Z"),
}
}
// ========== ERROR DTOs ==========
// ErrorResponse represents an error response