# Task Kanban Board Categorization Logic

This document describes how tasks are categorized into kanban columns for display in the Casera mobile app.

## Overview

Tasks are organized into 6 kanban columns based on their state and due date. The categorization logic is implemented in `internal/repositories/task_repo.go` in the `GetKanbanData` and `GetKanbanDataForMultipleResidences` functions.

## Columns Summary

| Column | Name | Color | Button Types | Description |
|--------|------|-------|--------------|-------------|
| 1 | **Overdue** | `#FF3B30` (Red) | edit, complete, cancel, mark_in_progress | Tasks past their due date |
| 2 | **Due Soon** | `#FF9500` (Orange) | edit, complete, cancel, mark_in_progress | Tasks due within the threshold (default 30 days) |
| 3 | **Upcoming** | `#007AFF` (Blue) | edit, complete, cancel, mark_in_progress | Tasks due beyond the threshold or with no due date |
| 4 | **In Progress** | `#5856D6` (Purple) | edit, complete, cancel | Tasks with status "In Progress" |
| 5 | **Completed** | `#34C759` (Green) | view | Tasks with at least one completion record |
| 6 | **Cancelled** | `#8E8E93` (Gray) | uncancel, delete | Tasks marked as cancelled |

## Categorization Flow

The categorization follows this priority order (first match wins):

```
┌─────────────────────────────────────────────────────────────────┐
│                        START: Process Task                       │
└─────────────────────────────────────────────────────────────────┘
                                  │
                                  ▼
                    ┌─────────────────────────┐
                    │   Is task cancelled?    │
                    │   (is_cancelled = true) │
                    └─────────────────────────┘
                           │           │
                          YES          NO
                           │           │
                           ▼           ▼
                    ┌──────────┐  ┌─────────────────────────┐
                    │CANCELLED │  │ Has task completions?   │
                    │  column  │  │ (len(completions) > 0)  │
                    └──────────┘  └─────────────────────────┘
                                       │           │
                                      YES          NO
                                       │           │
                                       ▼           ▼
                                ┌──────────┐ ┌─────────────────────────┐
                                │COMPLETED │ │ Is status "In Progress"?│
                                │  column  │ │ (status.name = "In...)  │
                                └──────────┘ └─────────────────────────┘
                                                   │           │
                                                  YES          NO
                                                   │           │
                                                   ▼           ▼
                                            ┌───────────┐ ┌─────────────────┐
                                            │IN PROGRESS│ │ Has due date?   │
                                            │  column   │ └─────────────────┘
                                            └───────────┘      │         │
                                                              YES        NO
                                                               │         │
                                                               ▼         ▼
                                                    ┌──────────────┐ ┌────────┐
                                                    │Check due date│ │UPCOMING│
                                                    └──────────────┘ │ column │
                                                           │         └────────┘
                                              ┌────────────┼────────────┐
                                              ▼            ▼            ▼
                                    ┌─────────────┐ ┌──────────┐ ┌────────────┐
                                    │ due < now   │ │due < now │ │due >= now +│
                                    │             │ │+ threshold│ │ threshold  │
                                    └─────────────┘ └──────────┘ └────────────┘
                                           │              │             │
                                           ▼              ▼             ▼
                                    ┌─────────┐    ┌──────────┐  ┌────────┐
                                    │ OVERDUE │    │ DUE SOON │  │UPCOMING│
                                    │  column │    │  column  │  │ column │
                                    └─────────┘    └──────────┘  └────────┘
```

## Detailed Rules

### 1. Cancelled (highest priority)
```go
if task.IsCancelled {
    cancelled = append(cancelled, task)
    continue
}
```
- **Condition**: `is_cancelled = true`
- **Button Types**: `uncancel`, `delete`
- **Rationale**: Cancelled tasks can be restored (uncancel) or permanently removed (delete)

### 2. Completed
```go
if len(task.Completions) > 0 {
    completed = append(completed, task)
    continue
}
```
- **Condition**: Task has at least one `TaskCompletion` record
- **Note**: A task is considered completed based on having completion records, NOT based on status
- **Button Types**: `view`
- **Rationale**: Completed tasks are read-only for historical purposes; users can view completion details and photos

### 3. In Progress
```go
if task.Status != nil && task.Status.Name == "In Progress" {
    inProgress = append(inProgress, task)
    continue
}
```
- **Condition**: Task's status name is exactly `"In Progress"`
- **Button Types**: `edit`, `complete`, `cancel`
- **Rationale**: In-progress tasks can be edited, marked complete, or cancelled if work is abandoned

### 4. Due Date Based Categories (only for tasks not cancelled, completed, or in progress)

#### Overdue
```go
if task.DueDate.Before(now) {
    overdue = append(overdue, task)
}
```
- **Condition**: `due_date < current_time`
- **Button Types**: `edit`, `complete`, `cancel`, `mark_in_progress`
- **Rationale**: Overdue tasks need urgent attention - can complete immediately, start working on them, edit the due date, or cancel if no longer needed

#### Due Soon
```go
if task.DueDate.Before(threshold) {
    dueSoon = append(dueSoon, task)
}
```
- **Condition**: `current_time <= due_date < (current_time + days_threshold)`
- **Default threshold**: 30 days
- **Button Types**: `edit`, `complete`, `cancel`, `mark_in_progress`
- **Rationale**: Due soon tasks are approaching their deadline - users can complete early, start working, reschedule, or cancel

#### Upcoming
```go
upcoming = append(upcoming, task)
```
- **Condition**: `due_date >= (current_time + days_threshold)` OR `due_date IS NULL`
- **Button Types**: `edit`, `complete`, `cancel`, `mark_in_progress`
- **Rationale**: Future tasks may need to be completed early (ahead of schedule), started, rescheduled, or cancelled

## Button Types Reference

| Button Type | Action | Description |
|-------------|--------|-------------|
| `edit` | Update task | Modify task details (title, description, due date, category, etc.) |
| `complete` | Create completion | Mark task as done with optional notes and photos |
| `cancel` | Cancel task | Mark task as cancelled (soft delete, can be uncancelled) |
| `mark_in_progress` | Start work | Change status to "In Progress" to indicate work has begun |
| `view` | View details | View task and completion details (read-only) |
| `uncancel` | Restore task | Restore a cancelled task to its previous state |
| `delete` | Hard delete | Permanently remove task (only for cancelled tasks) |

## Column Metadata

Each column includes metadata for the mobile clients:

```go
{
    Name:        "overdue_tasks",          // Internal identifier
    DisplayName: "Overdue",                // User-facing label
    ButtonTypes: []string{"edit", "complete", "cancel", "mark_in_progress"},
    Icons:       map[string]string{        // Platform-specific icons
        "ios": "exclamationmark.triangle",
        "android": "Warning"
    },
    Color:       "#FF3B30",                // Display color
    Tasks:       []Task{...},              // Tasks in this column
    Count:       int,                      // Number of tasks
}
```

### Icons by Column

| Column | iOS Icon | Android Icon |
|--------|----------|--------------|
| Overdue | `exclamationmark.triangle` | `Warning` |
| Due Soon | `clock` | `Schedule` |
| Upcoming | `calendar` | `Event` |
| In Progress | `hammer` | `Build` |
| Completed | `checkmark.circle` | `CheckCircle` |
| Cancelled | `xmark.circle` | `Cancel` |

## Days Threshold Parameter

The `daysThreshold` parameter (default: 30) determines the boundary between "Due Soon" and "Upcoming":

- Tasks due within `daysThreshold` days from now → **Due Soon**
- Tasks due beyond `daysThreshold` days from now → **Upcoming**

This can be customized per request via query parameter.

## Sorting

Tasks within each column are sorted by:
1. `due_date ASC NULLS LAST` (earliest due date first, tasks without due dates at end)
2. `priority_id DESC` (higher priority first)
3. `created_at DESC` (newest first)

## Excluded Tasks

The following tasks are excluded from the kanban board entirely:
- **Archived tasks**: `is_archived = true`

## API Response Example

```json
{
  "columns": [
    {
      "name": "overdue_tasks",
      "display_name": "Overdue",
      "button_types": ["edit", "complete", "cancel", "mark_in_progress"],
      "icons": {
        "ios": "exclamationmark.triangle",
        "android": "Warning"
      },
      "color": "#FF3B30",
      "tasks": [...],
      "count": 2
    },
    {
      "name": "due_soon_tasks",
      "display_name": "Due Soon",
      "button_types": ["edit", "complete", "cancel", "mark_in_progress"],
      "icons": {
        "ios": "clock",
        "android": "Schedule"
      },
      "color": "#FF9500",
      "tasks": [...],
      "count": 5
    },
    {
      "name": "upcoming_tasks",
      "display_name": "Upcoming",
      "button_types": ["edit", "complete", "cancel", "mark_in_progress"],
      "icons": {
        "ios": "calendar",
        "android": "Event"
      },
      "color": "#007AFF",
      "tasks": [...],
      "count": 10
    },
    {
      "name": "in_progress_tasks",
      "display_name": "In Progress",
      "button_types": ["edit", "complete", "cancel"],
      "icons": {
        "ios": "hammer",
        "android": "Build"
      },
      "color": "#5856D6",
      "tasks": [...],
      "count": 3
    },
    {
      "name": "completed_tasks",
      "display_name": "Completed",
      "button_types": ["view"],
      "icons": {
        "ios": "checkmark.circle",
        "android": "CheckCircle"
      },
      "color": "#34C759",
      "tasks": [...],
      "count": 15
    },
    {
      "name": "cancelled_tasks",
      "display_name": "Cancelled",
      "button_types": ["uncancel", "delete"],
      "icons": {
        "ios": "xmark.circle",
        "android": "Cancel"
      },
      "color": "#8E8E93",
      "tasks": [...],
      "count": 1
    }
  ],
  "days_threshold": 30,
  "residence_id": "123"
}
```

## Design Decisions

### Why "In Progress" doesn't have "mark_in_progress"
Tasks already in the "In Progress" column are already marked as in progress, so this action doesn't make sense.

### Why "Completed" only has "view"
Completed tasks represent historical records. Users can view them but shouldn't be able to uncomplete or modify them. If a task was completed incorrectly, the user should delete the completion record through the completion detail view.

### Why "Cancelled" has "delete" but others don't
Hard deletion is only available for cancelled tasks as a final cleanup action. For active tasks, users should cancel first (soft delete), then delete if truly needed. This prevents accidental data loss.

### Why all active columns have "cancel"
Users should always be able to abandon a task they no longer need, regardless of its due date or progress state.

## Code Location

- **Repository**: `internal/repositories/task_repo.go`
  - `GetKanbanData()` - Single residence
  - `GetKanbanDataForMultipleResidences()` - Multiple residences (all user's properties)
- **Service**: `internal/services/task_service.go`
  - `ListTasks()` - All tasks for user
  - `GetTasksByResidence()` - Tasks for specific residence
- **Response DTOs**: `internal/dto/responses/task.go`
  - `KanbanBoardResponse`
  - `KanbanColumnResponse`
