Add landing page, redesign emails, and return updated task on completion

- Integrate landing page into Go app (served at root /)
- Add STATIC_DIR config for static file serving
- Redesign all email templates with modern dark theme styling
- Add app icon to email headers
- Return updated task with kanban_column in completion response
- Update task DTO to include kanban column for client-side state updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-02 21:33:17 -06:00
parent 76579e8bf8
commit 3419b66097
15 changed files with 2689 additions and 283 deletions

View File

@@ -6,16 +6,16 @@ This document describes how tasks are categorized into kanban columns for displa
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
## Columns Summary
| Column | Name | Color | Description |
|--------|------|-------|-------------|
| 1 | **Overdue** | `#FF3B30` (Red) | Tasks past their due date |
| 2 | **Due Soon** | `#FF9500` (Orange) | Tasks due within the threshold (default 30 days) |
| 3 | **Upcoming** | `#007AFF` (Blue) | Tasks due beyond the threshold or with no due date |
| 4 | **In Progress** | `#5856D6` (Purple) | Tasks with status "In Progress" |
| 5 | **Completed** | `#34C759` (Green) | Tasks with at least one completion record |
| 6 | **Cancelled** | `#8E8E93` (Gray) | Tasks marked as cancelled |
| 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
@@ -86,7 +86,8 @@ if task.IsCancelled {
}
```
- **Condition**: `is_cancelled = true`
- **Actions Available**: `uncancel`, `delete`
- **Button Types**: `uncancel`, `delete`
- **Rationale**: Cancelled tasks can be restored (uncancel) or permanently removed (delete)
### 2. Completed
```go
@@ -97,7 +98,8 @@ if len(task.Completions) > 0 {
```
- **Condition**: Task has at least one `TaskCompletion` record
- **Note**: A task is considered completed based on having completion records, NOT based on status
- **Actions Available**: `view`
- **Button Types**: `view`
- **Rationale**: Completed tasks are read-only for historical purposes; users can view completion details and photos
### 3. In Progress
```go
@@ -107,7 +109,8 @@ if task.Status != nil && task.Status.Name == "In Progress" {
}
```
- **Condition**: Task's status name is exactly `"In Progress"`
- **Actions Available**: `edit`, `complete`
- **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)
@@ -118,7 +121,8 @@ if task.DueDate.Before(now) {
}
```
- **Condition**: `due_date < current_time`
- **Actions Available**: `edit`, `cancel`, `mark_in_progress`
- **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
@@ -128,14 +132,28 @@ if task.DueDate.Before(threshold) {
```
- **Condition**: `current_time <= due_date < (current_time + days_threshold)`
- **Default threshold**: 30 days
- **Actions Available**: `edit`, `complete`, `mark_in_progress`
- **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`
- **Actions Available**: `edit`, `cancel`
- **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
@@ -145,7 +163,7 @@ Each column includes metadata for the mobile clients:
{
Name: "overdue_tasks", // Internal identifier
DisplayName: "Overdue", // User-facing label
ButtonTypes: []string{"edit", "cancel", "mark_in_progress"}, // Available actions
ButtonTypes: []string{"edit", "complete", "cancel", "mark_in_progress"},
Icons: map[string]string{ // Platform-specific icons
"ios": "exclamationmark.triangle",
"android": "Warning"
@@ -156,6 +174,17 @@ Each column includes metadata for the mobile clients:
}
```
### 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":
@@ -185,7 +214,7 @@ The following tasks are excluded from the kanban board entirely:
{
"name": "overdue_tasks",
"display_name": "Overdue",
"button_types": ["edit", "cancel", "mark_in_progress"],
"button_types": ["edit", "complete", "cancel", "mark_in_progress"],
"icons": {
"ios": "exclamationmark.triangle",
"android": "Warning"
@@ -194,13 +223,86 @@ The following tasks are excluded from the kanban board entirely:
"tasks": [...],
"count": 2
},
// ... other columns
{
"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`