From 12eac24632c0e5117d8c1e193751358ebca2f17e Mon Sep 17 00:00:00 2001 From: Trey t Date: Mon, 8 Dec 2025 22:43:53 -0600 Subject: [PATCH] Remove remaining status_id references after in_progress migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove Preload("Status") from worker handler and repositories - Update seeds to use in_progress boolean instead of status_id - Remove task_taskstatus table creation from lookup seeds - Update documentation to reflect in_progress boolean pattern Fixes notification worker error: "Status: unsupported relations for schema Task" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- docs/TASK_KANBAN_CATEGORIZATION.md | 19 ++-- docs/TASK_KANBAN_LOGIC.md | 4 +- docs/TASK_LOGIC_ARCHITECTURE.md | 22 ++-- internal/repositories/contractor_repo.go | 1 - internal/repositories/residence_repo.go | 1 - internal/worker/jobs/handler.go | 4 +- seeds/001_lookups.sql | 16 +-- seeds/002_test_data.sql | 133 +++++++++++------------ 8 files changed, 89 insertions(+), 111 deletions(-) diff --git a/docs/TASK_KANBAN_CATEGORIZATION.md b/docs/TASK_KANBAN_CATEGORIZATION.md index 238533c..88cf6a2 100644 --- a/docs/TASK_KANBAN_CATEGORIZATION.md +++ b/docs/TASK_KANBAN_CATEGORIZATION.md @@ -82,14 +82,14 @@ if task.NextDueDate == nil && len(task.Completions) > 0 { **Handler**: `InProgressHandler` -**Condition**: `task.Status != nil && task.Status.Name == "In Progress"` +**Condition**: `task.InProgress == true` **Result**: `in_progress_tasks` -Tasks with the "In Progress" status are grouped together regardless of their due date. This allows users to see what's actively being worked on. +Tasks marked as "In Progress" are grouped together regardless of their due date. This allows users to see what's actively being worked on. ```go -if task.Status != nil && task.Status.Name == "In Progress" { +if task.InProgress { return "in_progress_tasks" } ``` @@ -188,15 +188,14 @@ return "upcoming_tasks" This is by design - "In Progress" indicates active work, so the task should be visible there. However, this means: 1. If a recurring task is marked "In Progress" and then completed -2. The status MUST be reset to "Pending" after completion +2. The `in_progress` flag MUST be reset to `false` after completion 3. Otherwise, the task stays in "In Progress" instead of moving to "Upcoming" This is handled automatically in `TaskService.CreateCompletion()`: ```go if isRecurringTask { - pendingStatusID := uint(1) - task.StatusID = &pendingStatusID + task.InProgress = false } ``` @@ -246,8 +245,8 @@ Each column has associated metadata for UI rendering: import "github.com/treytartt/casera-api/internal/task/categorization" task := &models.Task{ - DueDate: time.Now().AddDate(0, 0, 15), // 15 days from now - Status: &models.TaskStatus{Name: "Pending"}, + DueDate: time.Now().AddDate(0, 0, 15), // 15 days from now + InProgress: false, } column := categorization.DetermineKanbanColumn(task, 30) @@ -291,14 +290,14 @@ Key test scenarios: 1. **Check `IsCancelled`**: Cancelled takes highest priority 2. **Check `NextDueDate`**: For recurring tasks, this determines placement -3. **Check `Status`**: "In Progress" overrides date-based categorization +3. **Check `InProgress`**: `true` overrides date-based categorization 4. **Check `Completions`**: Empty + nil NextDueDate = upcoming, not completed ### Recurring task not moving to Upcoming after completion? Verify that `CreateCompletion` is: 1. Setting `NextDueDate` correctly -2. Resetting `StatusID` to Pending (1) +2. Resetting `InProgress` to `false` ### Task showing overdue but due date looks correct? diff --git a/docs/TASK_KANBAN_LOGIC.md b/docs/TASK_KANBAN_LOGIC.md index 1a7921e..39d4ac1 100644 --- a/docs/TASK_KANBAN_LOGIC.md +++ b/docs/TASK_KANBAN_LOGIC.md @@ -103,12 +103,12 @@ if len(task.Completions) > 0 { ### 3. In Progress ```go -if task.Status != nil && task.Status.Name == "In Progress" { +if task.InProgress { inProgress = append(inProgress, task) continue } ``` -- **Condition**: Task's status name is exactly `"In Progress"` +- **Condition**: Task's `in_progress` boolean is `true` - **Button Types**: `edit`, `complete`, `cancel` - **Rationale**: In-progress tasks can be edited, marked complete, or cancelled if work is abandoned diff --git a/docs/TASK_LOGIC_ARCHITECTURE.md b/docs/TASK_LOGIC_ARCHITECTURE.md index 35a0f1a..2ce360f 100644 --- a/docs/TASK_LOGIC_ARCHITECTURE.md +++ b/docs/TASK_LOGIC_ARCHITECTURE.md @@ -29,7 +29,7 @@ predicates.IsCompleted(task) // NextDueDate == nil && len(Completions) > 0 predicates.IsActive(task) // !IsCancelled && !IsArchived predicates.IsCancelled(task) // IsCancelled == true predicates.IsArchived(task) // IsArchived == true -predicates.IsInProgress(task) // Status.Name == "In Progress" +predicates.IsInProgress(task) // InProgress == true // Date calculations predicates.EffectiveDate(task) // NextDueDate ?? DueDate @@ -105,7 +105,7 @@ These rules are defined in `predicates/predicates.go` and enforced everywhere: |---------|------------|----------------| | **Completed** | `NextDueDate == nil && len(Completions) > 0` | `next_due_date IS NULL AND EXISTS (SELECT 1 FROM task_taskcompletion WHERE task_id = ?)` | | **Active** | `!IsCancelled && !IsArchived` | `is_cancelled = false AND is_archived = false` | -| **In Progress** | `Status.Name == "In Progress"` | `JOIN task_taskstatus WHERE name = 'In Progress'` | +| **In Progress** | `InProgress == true` | `in_progress = true` | | **Effective Date** | `NextDueDate ?? DueDate` | `COALESCE(next_due_date, due_date)` | | **Overdue** | `Active && !Completed && EffectiveDate < now` | Active + NotCompleted + `COALESCE(...) < ?` | | **Due Soon** | `Active && !Completed && now <= EffectiveDate < threshold` | Active + NotCompleted + `COALESCE(...) >= ? AND COALESCE(...) < ?` | @@ -117,7 +117,7 @@ When categorizing a task, the chain evaluates in this priority order: 1. **Cancelled** (highest) - `IsCancelled == true` 2. **Completed** - `NextDueDate == nil && len(Completions) > 0` -3. **In Progress** - `Status.Name == "In Progress"` +3. **In Progress** - `InProgress == true` 4. **Overdue** - `EffectiveDate < now` 5. **Due Soon** - `now <= EffectiveDate < threshold` 6. **Upcoming** (lowest/default) - Everything else @@ -139,7 +139,7 @@ db.Model(&models.Task{}). ```go // Load tasks with preloads var tasks []models.Task -db.Preload("Status").Preload("Completions"). +db.Preload("Completions"). Scopes(task.ScopeForResidence(residenceID)). Find(&tasks) @@ -329,18 +329,14 @@ db.Preload("Completions").Find(&tasks) predicates.IsCompleted(task) // Correct result ``` -### Forgetting to Preload Status +### In Progress Boolean Field -The `IsInProgress` predicate checks `task.Status.Name == "In Progress"`. Without preloading: +The `IsInProgress` predicate now uses a simple boolean field instead of a Status relation: ```go -// BAD: Status not loaded -db.Find(&tasks) -predicates.IsInProgress(task) // Nil pointer or always false - -// GOOD: Preload status -db.Preload("Status").Find(&tasks) -predicates.IsInProgress(task) // Correct result +// IsInProgress uses the in_progress boolean field directly +// No preloading required for this check +predicates.IsInProgress(task) // Checks task.InProgress boolean ``` ## Quick Reference Import diff --git a/internal/repositories/contractor_repo.go b/internal/repositories/contractor_repo.go index 72a9fc9..fccc6f1 100644 --- a/internal/repositories/contractor_repo.go +++ b/internal/repositories/contractor_repo.go @@ -105,7 +105,6 @@ func (r *ContractorRepository) GetTasksForContractor(contractorID uint) ([]model var tasks []models.Task err := r.db.Preload("Category"). Preload("Priority"). - Preload("Status"). Where("contractor_id = ?", contractorID). Order("due_date ASC NULLS LAST"). Find(&tasks).Error diff --git a/internal/repositories/residence_repo.go b/internal/repositories/residence_repo.go index 653a655..c48b457 100644 --- a/internal/repositories/residence_repo.go +++ b/internal/repositories/residence_repo.go @@ -316,7 +316,6 @@ func (r *ResidenceRepository) GetTasksForReport(residenceID uint) ([]models.Task err := r.db. Preload("Category"). Preload("Priority"). - Preload("Status"). Preload("Completions"). Preload("Completions.Images"). Preload("Completions.CompletedBy"). diff --git a/internal/worker/jobs/handler.go b/internal/worker/jobs/handler.go index 6c25a31..6727426 100644 --- a/internal/worker/jobs/handler.go +++ b/internal/worker/jobs/handler.go @@ -117,7 +117,7 @@ func (h *Handler) HandleTaskReminder(ctx context.Context, task *asynq.Task) erro // A task is "completed" when NextDueDate == nil AND has at least one completion. // See internal/task/scopes.ScopeNotCompleted for the SQL equivalent. var dueSoonTasks []models.Task - err = h.db.Preload("Status").Preload("Completions").Preload("Residence"). + err = h.db.Preload("Completions").Preload("Residence"). Where("(due_date >= ? AND due_date < ?) OR (next_due_date >= ? AND next_due_date < ?)", today, dayAfterTomorrow, today, dayAfterTomorrow). Where("is_cancelled = false"). @@ -220,7 +220,7 @@ func (h *Handler) HandleOverdueReminder(ctx context.Context, task *asynq.Task) e // A task is "completed" when NextDueDate == nil AND has at least one completion. // See internal/task/scopes.ScopeNotCompleted for the SQL equivalent. var overdueTasks []models.Task - err = h.db.Preload("Status").Preload("Completions").Preload("Residence"). + err = h.db.Preload("Completions").Preload("Residence"). Where("due_date < ? OR next_due_date < ?", today, today). Where("is_cancelled = false"). Where("is_archived = false"). diff --git a/seeds/001_lookups.sql b/seeds/001_lookups.sql index c37abe6..264a713 100644 --- a/seeds/001_lookups.sql +++ b/seeds/001_lookups.sql @@ -53,20 +53,7 @@ ON CONFLICT (id) DO UPDATE SET display_order = EXCLUDED.display_order, updated_at = NOW(); --- Task Statuses (has: name, description, color, display_order - NO is_terminal) -INSERT INTO task_taskstatus (id, created_at, updated_at, name, description, color, display_order) -VALUES - (1, NOW(), NOW(), 'Pending', 'Task has not been started', '#95a5a6', 1), - (2, NOW(), NOW(), 'In Progress', 'Task is currently being worked on', '#3498db', 2), - (3, NOW(), NOW(), 'Completed', 'Task has been completed', '#27ae60', 3), - (4, NOW(), NOW(), 'Cancelled', 'Task has been cancelled', '#e74c3c', 4), - (5, NOW(), NOW(), 'On Hold', 'Task is on hold', '#f39c12', 5) -ON CONFLICT (id) DO UPDATE SET - name = EXCLUDED.name, - description = EXCLUDED.description, - color = EXCLUDED.color, - display_order = EXCLUDED.display_order, - updated_at = NOW(); +-- NOTE: task_taskstatus table removed - replaced with in_progress boolean field on task_task -- Task Frequencies (has: name, days, display_order) INSERT INTO task_taskfrequency (id, created_at, updated_at, name, days, display_order) @@ -162,7 +149,6 @@ ON CONFLICT (id) DO UPDATE SET SELECT setval('residence_residencetype_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM residence_residencetype), false); SELECT setval('task_taskcategory_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM task_taskcategory), false); SELECT setval('task_taskpriority_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM task_taskpriority), false); -SELECT setval('task_taskstatus_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM task_taskstatus), false); SELECT setval('task_taskfrequency_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM task_taskfrequency), false); SELECT setval('task_contractorspecialty_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM task_contractorspecialty), false); SELECT setval('subscription_tierlimits_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM subscription_tierlimits), false); diff --git a/seeds/002_test_data.sql b/seeds/002_test_data.sql index 1a347b6..7e4b43d 100644 --- a/seeds/002_test_data.sql +++ b/seeds/002_test_data.sql @@ -185,131 +185,130 @@ VALUES ON CONFLICT DO NOTHING; -- ===================================================== --- TASKS (comprehensive coverage of all categories, priorities, statuses, frequencies) +-- TASKS (comprehensive coverage of all categories, priorities, frequencies) -- Categories: 1=Plumbing, 2=Electrical, 3=HVAC, 4=Appliances, 5=Outdoor/Landscaping, 6=Structural, 7=Safety, 8=Cleaning, 9=Pest Control, 10=Other -- Priorities: 1=Low, 2=Medium, 3=High, 4=Urgent --- Statuses: 1=Pending, 2=In Progress, 3=Completed, 4=On Hold, 5=Cancelled +-- in_progress: true = actively being worked on, false = not in progress -- Frequencies: 1=Once, 2=Daily, 3=Weekly, 4=Bi-Weekly, 5=Monthly, 6=Quarterly, 7=Semi-Annual, 8=Annual -- ===================================================== -- IMPORTANT: For recurring tasks (frequency > 1) that have completions, we must set: --- - status_id = 1 (Pending) - so they appear in date-based columns, not "Completed" -- - next_due_date = completion_date + frequency_days --- Only one-time tasks (frequency_id = 1) with completions should have status_id = 3 and next_due_date = NULL -INSERT INTO task_task (id, created_at, updated_at, residence_id, created_by_id, assigned_to_id, title, description, category_id, priority_id, status_id, frequency_id, due_date, next_due_date, estimated_cost, contractor_id, is_cancelled, is_archived) +-- Completion is determined by: next_due_date IS NULL AND has at least one completion record +INSERT INTO task_task (id, created_at, updated_at, residence_id, created_by_id, assigned_to_id, title, description, category_id, priority_id, in_progress, frequency_id, due_date, next_due_date, estimated_cost, contractor_id, is_cancelled, is_archived) VALUES -- ===== RESIDENCE 1 (John's Main Home) - 15 tasks ===== -- Plumbing tasks - (1, NOW() - INTERVAL '30 days', NOW(), 1, 2, 2, 'Fix leaky kitchen faucet', 'Kitchen faucet has been dripping for a week. Washer may need replacement.', 1, 2, 1, 1, CURRENT_DATE + INTERVAL '7 days', NULL, 150.00, 1, false, false), - (2, NOW() - INTERVAL '60 days', NOW(), 1, 2, 3, 'Unclog bathroom drain', 'Master bathroom sink draining slowly. Tried Drano with no success.', 1, 3, 3, 1, CURRENT_DATE - INTERVAL '45 days', NULL, 85.00, 1, false, false), - (3, NOW() - INTERVAL '15 days', NOW(), 1, 2, NULL, 'Water heater inspection', 'Annual inspection and flush of water heater tank', 1, 1, 1, 8, CURRENT_DATE + INTERVAL '30 days', NULL, 175.00, 1, false, false), + (1, NOW() - INTERVAL '30 days', NOW(), 1, 2, 2, 'Fix leaky kitchen faucet', 'Kitchen faucet has been dripping for a week. Washer may need replacement.', 1, 2, false, 1, CURRENT_DATE + INTERVAL '7 days', NULL, 150.00, 1, false, false), + (2, NOW() - INTERVAL '60 days', NOW(), 1, 2, 3, 'Unclog bathroom drain', 'Master bathroom sink draining slowly. Tried Drano with no success.', 1, 3, false, 1, CURRENT_DATE - INTERVAL '45 days', NULL, 85.00, 1, false, false), + (3, NOW() - INTERVAL '15 days', NOW(), 1, 2, NULL, 'Water heater inspection', 'Annual inspection and flush of water heater tank', 1, 1, false, 8, CURRENT_DATE + INTERVAL '30 days', NULL, 175.00, 1, false, false), -- Electrical tasks - (4, NOW() - INTERVAL '20 days', NOW(), 1, 2, 2, 'Install ceiling fan', 'Replace light fixture in master bedroom with ceiling fan', 2, 2, 2, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 350.00, 2, false, false), + (4, NOW() - INTERVAL '20 days', NOW(), 1, 2, 2, 'Install ceiling fan', 'Replace light fixture in master bedroom with ceiling fan', 2, 2, true, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 350.00, 2, false, false), -- Task 5: Annual recurring, completed 60 days ago -> next_due_date = completion + 365 days = ~305 days from now - (5, NOW() - INTERVAL '90 days', NOW(), 1, 2, NULL, 'Replace smoke detector batteries', 'Replace batteries in all 6 smoke detectors', 7, 3, 1, 8, CURRENT_DATE - INTERVAL '60 days', CURRENT_DATE + INTERVAL '305 days', 30.00, NULL, false, false), - (6, NOW() - INTERVAL '5 days', NOW(), 1, 2, NULL, 'Fix flickering lights', 'Living room lights flicker occasionally. May need new switch.', 2, 2, 1, 1, CURRENT_DATE + INTERVAL '10 days', NULL, 125.00, 2, false, false), + (5, NOW() - INTERVAL '90 days', NOW(), 1, 2, NULL, 'Replace smoke detector batteries', 'Replace batteries in all 6 smoke detectors', 7, 3, false, 8, CURRENT_DATE - INTERVAL '60 days', CURRENT_DATE + INTERVAL '305 days', 30.00, NULL, false, false), + (6, NOW() - INTERVAL '5 days', NOW(), 1, 2, NULL, 'Fix flickering lights', 'Living room lights flicker occasionally. May need new switch.', 2, 2, false, 1, CURRENT_DATE + INTERVAL '10 days', NULL, 125.00, 2, false, false), -- HVAC tasks -- Task 7: Monthly recurring, completed 15 days ago -> next_due_date = completion + 30 days = ~15 days from now - (7, NOW() - INTERVAL '45 days', NOW(), 1, 2, 2, 'Replace HVAC filters', 'Monthly filter replacement for central air system', 3, 2, 1, 5, CURRENT_DATE - INTERVAL '15 days', CURRENT_DATE + INTERVAL '15 days', 45.00, 3, false, false), - (8, NOW() - INTERVAL '10 days', NOW(), 1, 2, NULL, 'Schedule AC tune-up', 'Pre-summer AC maintenance and coolant check', 3, 2, 1, 8, CURRENT_DATE + INTERVAL '60 days', NULL, 200.00, 3, false, false), + (7, NOW() - INTERVAL '45 days', NOW(), 1, 2, 2, 'Replace HVAC filters', 'Monthly filter replacement for central air system', 3, 2, false, 5, CURRENT_DATE - INTERVAL '15 days', CURRENT_DATE + INTERVAL '15 days', 45.00, 3, false, false), + (8, NOW() - INTERVAL '10 days', NOW(), 1, 2, NULL, 'Schedule AC tune-up', 'Pre-summer AC maintenance and coolant check', 3, 2, false, 8, CURRENT_DATE + INTERVAL '60 days', NULL, 200.00, 3, false, false), -- Outdoor/Landscaping tasks -- Task 9: Weekly recurring, completed 2 days ago -> next_due_date = completion + 7 days = ~5 days from now - (9, NOW() - INTERVAL '7 days', NOW(), 1, 2, 3, 'Mow lawn', 'Weekly lawn mowing and edging', 5, 1, 1, 3, CURRENT_DATE - INTERVAL '2 days', CURRENT_DATE + INTERVAL '5 days', 50.00, 5, false, false), - (10, NOW() - INTERVAL '25 days', NOW(), 1, 2, NULL, 'Trim hedges', 'Trim front and back yard hedges', 5, 1, 1, 6, CURRENT_DATE + INTERVAL '20 days', NULL, 150.00, 5, false, false), + (9, NOW() - INTERVAL '7 days', NOW(), 1, 2, 3, 'Mow lawn', 'Weekly lawn mowing and edging', 5, 1, false, 3, CURRENT_DATE - INTERVAL '2 days', CURRENT_DATE + INTERVAL '5 days', 50.00, 5, false, false), + (10, NOW() - INTERVAL '25 days', NOW(), 1, 2, NULL, 'Trim hedges', 'Trim front and back yard hedges', 5, 1, false, 6, CURRENT_DATE + INTERVAL '20 days', NULL, 150.00, 5, false, false), -- Task 11: Semi-annual recurring, completed 70 days ago -> next_due_date = completion + 180 days = ~110 days from now - (11, NOW() - INTERVAL '100 days', NOW(), 1, 2, 5, 'Clean gutters', 'Remove leaves and debris from all gutters', 5, 2, 1, 7, CURRENT_DATE - INTERVAL '70 days', CURRENT_DATE + INTERVAL '110 days', 175.00, NULL, false, false), - (12, NOW() - INTERVAL '3 days', NOW(), 1, 2, NULL, 'Fertilize lawn', 'Apply spring fertilizer treatment', 5, 1, 1, 6, CURRENT_DATE + INTERVAL '5 days', NULL, 75.00, 5, false, false), + (11, NOW() - INTERVAL '100 days', NOW(), 1, 2, 5, 'Clean gutters', 'Remove leaves and debris from all gutters', 5, 2, false, 7, CURRENT_DATE - INTERVAL '70 days', CURRENT_DATE + INTERVAL '110 days', 175.00, NULL, false, false), + (12, NOW() - INTERVAL '3 days', NOW(), 1, 2, NULL, 'Fertilize lawn', 'Apply spring fertilizer treatment', 5, 1, false, 6, CURRENT_DATE + INTERVAL '5 days', NULL, 75.00, 5, false, false), -- Safety tasks -- Task 13: Annual recurring, completed 150 days ago -> next_due_date = completion + 365 days = ~215 days from now - (13, NOW() - INTERVAL '180 days', NOW(), 1, 2, 2, 'Test fire extinguishers', 'Annual inspection of all fire extinguishers', 7, 3, 1, 8, CURRENT_DATE - INTERVAL '150 days', CURRENT_DATE + INTERVAL '215 days', 0.00, NULL, false, false), + (13, NOW() - INTERVAL '180 days', NOW(), 1, 2, 2, 'Test fire extinguishers', 'Annual inspection of all fire extinguishers', 7, 3, false, 8, CURRENT_DATE - INTERVAL '150 days', CURRENT_DATE + INTERVAL '215 days', 0.00, NULL, false, false), -- Cleaning tasks -- Task 14: Annual recurring, completed 25 days ago -> next_due_date = completion + 365 days = ~340 days from now - (14, NOW() - INTERVAL '40 days', NOW(), 1, 2, 3, 'Deep clean carpets', 'Professional carpet cleaning for all rooms', 8, 1, 1, 8, CURRENT_DATE - INTERVAL '25 days', CURRENT_DATE + INTERVAL '340 days', 350.00, NULL, false, false), + (14, NOW() - INTERVAL '40 days', NOW(), 1, 2, 3, 'Deep clean carpets', 'Professional carpet cleaning for all rooms', 8, 1, false, 8, CURRENT_DATE - INTERVAL '25 days', CURRENT_DATE + INTERVAL '340 days', 350.00, NULL, false, false), -- On hold task - (15, NOW() - INTERVAL '50 days', NOW(), 1, 2, NULL, 'Paint exterior', 'Repaint exterior trim and shutters', 6, 2, 4, 1, CURRENT_DATE + INTERVAL '90 days', NULL, 2500.00, NULL, false, false), + (15, NOW() - INTERVAL '50 days', NOW(), 1, 2, NULL, 'Paint exterior', 'Repaint exterior trim and shutters', 6, 2, false, 1, CURRENT_DATE + INTERVAL '90 days', NULL, 2500.00, NULL, false, false), -- ===== RESIDENCE 2 (Beach House) - 8 tasks ===== -- Task 16: Weekly recurring, completed 6 days ago -> next_due_date = completion + 7 days = ~1 day from now - (16, NOW() - INTERVAL '20 days', NOW(), 2, 2, 2, 'Check pool chemicals', 'Weekly pool water testing and chemical balance', 10, 2, 1, 3, CURRENT_DATE - INTERVAL '6 days', CURRENT_DATE + INTERVAL '1 day', 50.00, NULL, false, false), - (17, NOW() - INTERVAL '15 days', NOW(), 2, 2, NULL, 'Hurricane shutter inspection', 'Annual inspection before hurricane season', 7, 3, 1, 8, CURRENT_DATE + INTERVAL '45 days', NULL, 300.00, 7, false, false), - (18, NOW() - INTERVAL '30 days', NOW(), 2, 2, NULL, 'AC filter change', 'Replace AC filters - salt air requires more frequent changes', 3, 2, 1, 5, CURRENT_DATE + INTERVAL '5 days', NULL, 60.00, NULL, false, false), - (19, NOW() - INTERVAL '60 days', NOW(), 2, 2, 2, 'Fix outdoor shower', 'Outdoor shower has low pressure', 1, 2, 3, 1, CURRENT_DATE - INTERVAL '40 days', NULL, 200.00, 6, false, false), - (20, NOW() - INTERVAL '5 days', NOW(), 2, 2, NULL, 'Pressure wash deck', 'Clean salt buildup from deck and railings', 8, 1, 1, 6, CURRENT_DATE + INTERVAL '30 days', NULL, 250.00, NULL, false, false), + (16, NOW() - INTERVAL '20 days', NOW(), 2, 2, 2, 'Check pool chemicals', 'Weekly pool water testing and chemical balance', 10, 2, false, 3, CURRENT_DATE - INTERVAL '6 days', CURRENT_DATE + INTERVAL '1 day', 50.00, NULL, false, false), + (17, NOW() - INTERVAL '15 days', NOW(), 2, 2, NULL, 'Hurricane shutter inspection', 'Annual inspection before hurricane season', 7, 3, false, 8, CURRENT_DATE + INTERVAL '45 days', NULL, 300.00, 7, false, false), + (18, NOW() - INTERVAL '30 days', NOW(), 2, 2, NULL, 'AC filter change', 'Replace AC filters - salt air requires more frequent changes', 3, 2, false, 5, CURRENT_DATE + INTERVAL '5 days', NULL, 60.00, NULL, false, false), + (19, NOW() - INTERVAL '60 days', NOW(), 2, 2, 2, 'Fix outdoor shower', 'Outdoor shower has low pressure', 1, 2, false, 1, CURRENT_DATE - INTERVAL '40 days', NULL, 200.00, 6, false, false), + (20, NOW() - INTERVAL '5 days', NOW(), 2, 2, NULL, 'Pressure wash deck', 'Clean salt buildup from deck and railings', 8, 1, false, 6, CURRENT_DATE + INTERVAL '30 days', NULL, 250.00, NULL, false, false), -- Task 21: Quarterly recurring, completed 60 days ago -> next_due_date = completion + 90 days = ~30 days from now - (21, NOW() - INTERVAL '90 days', NOW(), 2, 2, NULL, 'Pest control treatment', 'Quarterly pest control for beach property', 9, 2, 1, 6, CURRENT_DATE - INTERVAL '60 days', CURRENT_DATE + INTERVAL '30 days', 150.00, NULL, false, false), - (22, NOW() - INTERVAL '10 days', NOW(), 2, 2, NULL, 'Replace patio furniture', 'Sun-damaged furniture needs replacement', 10, 1, 4, 1, CURRENT_DATE + INTERVAL '60 days', NULL, 1200.00, NULL, false, false), - (23, NOW() - INTERVAL '180 days', NOW(), 2, 2, 2, 'Install security cameras', 'Add 4 outdoor security cameras', 7, 2, 3, 1, CURRENT_DATE - INTERVAL '150 days', NULL, 800.00, NULL, false, false), + (21, NOW() - INTERVAL '90 days', NOW(), 2, 2, NULL, 'Pest control treatment', 'Quarterly pest control for beach property', 9, 2, false, 6, CURRENT_DATE - INTERVAL '60 days', CURRENT_DATE + INTERVAL '30 days', 150.00, NULL, false, false), + (22, NOW() - INTERVAL '10 days', NOW(), 2, 2, NULL, 'Replace patio furniture', 'Sun-damaged furniture needs replacement', 10, 1, false, 1, CURRENT_DATE + INTERVAL '60 days', NULL, 1200.00, NULL, false, false), + (23, NOW() - INTERVAL '180 days', NOW(), 2, 2, 2, 'Install security cameras', 'Add 4 outdoor security cameras', 7, 2, false, 1, CURRENT_DATE - INTERVAL '150 days', NULL, 800.00, NULL, false, false), -- ===== RESIDENCE 3 (Investment Duplex) - 5 tasks ===== - (24, NOW() - INTERVAL '25 days', NOW(), 3, 2, NULL, 'Unit A - Repair drywall', 'Patch and paint drywall damage from tenant', 6, 2, 1, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 400.00, NULL, false, false), - (25, NOW() - INTERVAL '10 days', NOW(), 3, 2, NULL, 'Unit B - Replace dishwasher', 'Dishwasher not draining properly', 4, 3, 2, 1, CURRENT_DATE + INTERVAL '3 days', NULL, 650.00, NULL, false, false), + (24, NOW() - INTERVAL '25 days', NOW(), 3, 2, NULL, 'Unit A - Repair drywall', 'Patch and paint drywall damage from tenant', 6, 2, false, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 400.00, NULL, false, false), + (25, NOW() - INTERVAL '10 days', NOW(), 3, 2, NULL, 'Unit B - Replace dishwasher', 'Dishwasher not draining properly', 4, 3, true, 1, CURRENT_DATE + INTERVAL '3 days', NULL, 650.00, NULL, false, false), -- Task 26: Annual recurring, completed 30 days ago -> next_due_date = completion + 365 days = ~335 days from now - (26, NOW() - INTERVAL '45 days', NOW(), 3, 2, 2, 'Annual fire inspection', 'Required annual fire safety inspection', 7, 3, 1, 8, CURRENT_DATE - INTERVAL '30 days', CURRENT_DATE + INTERVAL '335 days', 150.00, NULL, false, false), - (27, NOW() - INTERVAL '5 days', NOW(), 3, 2, NULL, 'Replace hallway carpet', 'Common area carpet showing wear', 6, 1, 1, 1, CURRENT_DATE + INTERVAL '45 days', NULL, 1500.00, NULL, false, false), + (26, NOW() - INTERVAL '45 days', NOW(), 3, 2, 2, 'Annual fire inspection', 'Required annual fire safety inspection', 7, 3, false, 8, CURRENT_DATE - INTERVAL '30 days', CURRENT_DATE + INTERVAL '335 days', 150.00, NULL, false, false), + (27, NOW() - INTERVAL '5 days', NOW(), 3, 2, NULL, 'Replace hallway carpet', 'Common area carpet showing wear', 6, 1, false, 1, CURRENT_DATE + INTERVAL '45 days', NULL, 1500.00, NULL, false, false), -- Task 28: Annual recurring, archived, completed 170 days ago -> next_due_date = completion + 365 days = ~195 days from now - (28, NOW() - INTERVAL '200 days', NOW(), 3, 2, NULL, 'Roof inspection', 'Annual roof inspection', 6, 2, 1, 8, CURRENT_DATE - INTERVAL '170 days', CURRENT_DATE + INTERVAL '195 days', 250.00, NULL, false, true), + (28, NOW() - INTERVAL '200 days', NOW(), 3, 2, NULL, 'Roof inspection', 'Annual roof inspection', 6, 2, false, 8, CURRENT_DATE - INTERVAL '170 days', CURRENT_DATE + INTERVAL '195 days', 250.00, NULL, false, true), -- ===== RESIDENCE 4 (Jane's Downtown Loft) - 7 tasks ===== - (29, NOW() - INTERVAL '15 days', NOW(), 4, 3, 3, 'Fix garbage disposal', 'Disposal is jammed and making noise', 4, 3, 2, 1, CURRENT_DATE + INTERVAL '2 days', NULL, 150.00, 8, false, false), - (30, NOW() - INTERVAL '30 days', NOW(), 4, 3, NULL, 'Clean dryer vent', 'Annual dryer vent cleaning for fire safety', 7, 3, 1, 8, CURRENT_DATE + INTERVAL '30 days', NULL, 125.00, NULL, false, false), - (31, NOW() - INTERVAL '60 days', NOW(), 4, 3, 3, 'Touch up paint', 'Touch up scuff marks on walls', 6, 1, 3, 1, CURRENT_DATE - INTERVAL '45 days', NULL, 0.00, NULL, false, false), - (32, NOW() - INTERVAL '7 days', NOW(), 4, 3, NULL, 'Replace refrigerator water filter', 'Bi-annual filter replacement', 4, 1, 1, 7, CURRENT_DATE + INTERVAL '14 days', NULL, 50.00, 9, false, false), + (29, NOW() - INTERVAL '15 days', NOW(), 4, 3, 3, 'Fix garbage disposal', 'Disposal is jammed and making noise', 4, 3, true, 1, CURRENT_DATE + INTERVAL '2 days', NULL, 150.00, 8, false, false), + (30, NOW() - INTERVAL '30 days', NOW(), 4, 3, NULL, 'Clean dryer vent', 'Annual dryer vent cleaning for fire safety', 7, 3, false, 8, CURRENT_DATE + INTERVAL '30 days', NULL, 125.00, NULL, false, false), + (31, NOW() - INTERVAL '60 days', NOW(), 4, 3, 3, 'Touch up paint', 'Touch up scuff marks on walls', 6, 1, false, 1, CURRENT_DATE - INTERVAL '45 days', NULL, 0.00, NULL, false, false), + (32, NOW() - INTERVAL '7 days', NOW(), 4, 3, NULL, 'Replace refrigerator water filter', 'Bi-annual filter replacement', 4, 1, false, 7, CURRENT_DATE + INTERVAL '14 days', NULL, 50.00, 9, false, false), -- Task 33: Annual recurring, completed 60 days ago -> next_due_date = completion + 365 days = ~305 days from now - (33, NOW() - INTERVAL '90 days', NOW(), 4, 3, NULL, 'Deep clean oven', 'Professional oven cleaning', 8, 1, 1, 8, CURRENT_DATE - INTERVAL '60 days', CURRENT_DATE + INTERVAL '305 days', 100.00, NULL, false, false), - (34, NOW() - INTERVAL '120 days', NOW(), 4, 3, 3, 'Install smart thermostat', 'Replace old thermostat with Nest', 3, 2, 3, 1, CURRENT_DATE - INTERVAL '100 days', NULL, 250.00, NULL, false, false), - (35, NOW() - INTERVAL '3 days', NOW(), 4, 3, NULL, 'Repair window blinds', 'Bedroom blinds cord is broken', 10, 1, 1, 1, CURRENT_DATE + INTERVAL '21 days', NULL, 75.00, NULL, false, false), + (33, NOW() - INTERVAL '90 days', NOW(), 4, 3, NULL, 'Deep clean oven', 'Professional oven cleaning', 8, 1, false, 8, CURRENT_DATE - INTERVAL '60 days', CURRENT_DATE + INTERVAL '305 days', 100.00, NULL, false, false), + (34, NOW() - INTERVAL '120 days', NOW(), 4, 3, 3, 'Install smart thermostat', 'Replace old thermostat with Nest', 3, 2, false, 1, CURRENT_DATE - INTERVAL '100 days', NULL, 250.00, NULL, false, false), + (35, NOW() - INTERVAL '3 days', NOW(), 4, 3, NULL, 'Repair window blinds', 'Bedroom blinds cord is broken', 10, 1, false, 1, CURRENT_DATE + INTERVAL '21 days', NULL, 75.00, NULL, false, false), -- ===== RESIDENCE 5 (Bob's Mountain Condo) - 6 tasks ===== -- Task 36: Annual recurring, completed 10 days ago -> next_due_date = completion + 365 days = ~355 days from now - (36, NOW() - INTERVAL '20 days', NOW(), 5, 4, 4, 'Winterize pipes', 'Prepare plumbing for winter freeze', 1, 3, 1, 8, CURRENT_DATE - INTERVAL '10 days', CURRENT_DATE + INTERVAL '355 days', 200.00, NULL, false, false), + (36, NOW() - INTERVAL '20 days', NOW(), 5, 4, 4, 'Winterize pipes', 'Prepare plumbing for winter freeze', 1, 3, false, 8, CURRENT_DATE - INTERVAL '10 days', CURRENT_DATE + INTERVAL '355 days', 200.00, NULL, false, false), -- Task 37: One-time (frequency=1), completed -> stays completed with no next_due_date - (37, NOW() - INTERVAL '40 days', NOW(), 5, 4, NULL, 'Check roof for snow damage', 'Inspect after heavy snowfall', 6, 3, 3, 1, CURRENT_DATE - INTERVAL '35 days', NULL, 0.00, 10, false, false), - (38, NOW() - INTERVAL '10 days', NOW(), 5, 4, 12, 'Tune ski equipment storage', 'Organize ski room and check equipment', 10, 1, 2, 8, CURRENT_DATE + INTERVAL '7 days', NULL, 0.00, NULL, false, false), - (39, NOW() - INTERVAL '5 days', NOW(), 5, 4, NULL, 'Replace entry door weatherstrip', 'Cold air leaking around front door', 6, 2, 1, 1, CURRENT_DATE + INTERVAL '10 days', NULL, 100.00, NULL, false, false), + (37, NOW() - INTERVAL '40 days', NOW(), 5, 4, NULL, 'Check roof for snow damage', 'Inspect after heavy snowfall', 6, 3, false, 1, CURRENT_DATE - INTERVAL '35 days', NULL, 0.00, 10, false, false), + (38, NOW() - INTERVAL '10 days', NOW(), 5, 4, 12, 'Tune ski equipment storage', 'Organize ski room and check equipment', 10, 1, true, 8, CURRENT_DATE + INTERVAL '7 days', NULL, 0.00, NULL, false, false), + (39, NOW() - INTERVAL '5 days', NOW(), 5, 4, NULL, 'Replace entry door weatherstrip', 'Cold air leaking around front door', 6, 2, false, 1, CURRENT_DATE + INTERVAL '10 days', NULL, 100.00, NULL, false, false), -- Task 40: Annual recurring, completed 60 days ago -> next_due_date = completion + 365 days = ~305 days from now - (40, NOW() - INTERVAL '90 days', NOW(), 5, 4, 4, 'HOA deck staining', 'Required deck maintenance per HOA', 5, 2, 1, 8, CURRENT_DATE - INTERVAL '60 days', CURRENT_DATE + INTERVAL '305 days', 500.00, NULL, false, false), + (40, NOW() - INTERVAL '90 days', NOW(), 5, 4, 4, 'HOA deck staining', 'Required deck maintenance per HOA', 5, 2, false, 8, CURRENT_DATE - INTERVAL '60 days', CURRENT_DATE + INTERVAL '305 days', 500.00, NULL, false, false), -- Task 41: Annual recurring, completed 150 days ago -> next_due_date = completion + 365 days = ~215 days from now - (41, NOW() - INTERVAL '180 days', NOW(), 5, 4, NULL, 'Fireplace inspection', 'Annual chimney and fireplace check', 7, 3, 1, 8, CURRENT_DATE - INTERVAL '150 days', CURRENT_DATE + INTERVAL '215 days', 175.00, NULL, false, false), + (41, NOW() - INTERVAL '180 days', NOW(), 5, 4, NULL, 'Fireplace inspection', 'Annual chimney and fireplace check', 7, 3, false, 8, CURRENT_DATE - INTERVAL '150 days', CURRENT_DATE + INTERVAL '215 days', 175.00, NULL, false, false), -- ===== RESIDENCE 8 (Alice's Craftsman) - 6 tasks ===== - (42, NOW() - INTERVAL '25 days', NOW(), 8, 5, 5, 'Refinish hardwood floors', 'Sand and refinish original hardwood in living room', 6, 2, 2, 1, CURRENT_DATE + INTERVAL '30 days', NULL, 2000.00, 13, false, false), - (43, NOW() - INTERVAL '50 days', NOW(), 8, 5, 9, 'Repair original windows', 'Restore and weatherproof historic windows', 6, 2, 3, 1, CURRENT_DATE - INTERVAL '20 days', NULL, 1500.00, 13, false, false), - (44, NOW() - INTERVAL '15 days', NOW(), 8, 5, NULL, 'Update knob and tube wiring', 'Replace section of old wiring in attic', 2, 4, 1, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 3000.00, NULL, false, false), + (42, NOW() - INTERVAL '25 days', NOW(), 8, 5, 5, 'Refinish hardwood floors', 'Sand and refinish original hardwood in living room', 6, 2, true, 1, CURRENT_DATE + INTERVAL '30 days', NULL, 2000.00, 13, false, false), + (43, NOW() - INTERVAL '50 days', NOW(), 8, 5, 9, 'Repair original windows', 'Restore and weatherproof historic windows', 6, 2, false, 1, CURRENT_DATE - INTERVAL '20 days', NULL, 1500.00, 13, false, false), + (44, NOW() - INTERVAL '15 days', NOW(), 8, 5, NULL, 'Update knob and tube wiring', 'Replace section of old wiring in attic', 2, 4, false, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 3000.00, NULL, false, false), -- Task 45: Weekly recurring, completed 7 days ago -> next_due_date = completion + 7 days = today (due soon) - (45, NOW() - INTERVAL '30 days', NOW(), 8, 5, 5, 'Garden maintenance', 'Weekly garden care and weeding', 5, 1, 1, 3, CURRENT_DATE - INTERVAL '7 days', CURRENT_DATE, 75.00, NULL, false, false), - (46, NOW() - INTERVAL '7 days', NOW(), 8, 5, NULL, 'Fix porch swing', 'Chains need tightening and wood needs oiling', 10, 1, 1, 1, CURRENT_DATE + INTERVAL '21 days', NULL, 50.00, 13, false, false), + (45, NOW() - INTERVAL '30 days', NOW(), 8, 5, 5, 'Garden maintenance', 'Weekly garden care and weeding', 5, 1, false, 3, CURRENT_DATE - INTERVAL '7 days', CURRENT_DATE, 75.00, NULL, false, false), + (46, NOW() - INTERVAL '7 days', NOW(), 8, 5, NULL, 'Fix porch swing', 'Chains need tightening and wood needs oiling', 10, 1, false, 1, CURRENT_DATE + INTERVAL '21 days', NULL, 50.00, 13, false, false), -- Task 47: Semi-annual recurring, completed 30 days ago -> next_due_date = completion + 180 days = ~150 days from now - (47, NOW() - INTERVAL '60 days', NOW(), 8, 5, 5, 'Clean rain gutters', 'Clear leaves from craftsman-style gutters', 5, 2, 1, 7, CURRENT_DATE - INTERVAL '30 days', CURRENT_DATE + INTERVAL '150 days', 200.00, NULL, false, false), + (47, NOW() - INTERVAL '60 days', NOW(), 8, 5, 5, 'Clean rain gutters', 'Clear leaves from craftsman-style gutters', 5, 2, false, 7, CURRENT_DATE - INTERVAL '30 days', CURRENT_DATE + INTERVAL '150 days', 200.00, NULL, false, false), -- ===== RESIDENCE 11 (Edward's Fixer Upper) - 5 tasks ===== - (48, NOW() - INTERVAL '14 days', NOW(), 11, 8, 8, 'Demo bathroom tile', 'Remove old tile in master bathroom', 6, 3, 2, 1, CURRENT_DATE + INTERVAL '7 days', NULL, 500.00, 15, false, false), - (49, NOW() - INTERVAL '10 days', NOW(), 11, 8, NULL, 'Install new cabinets', 'Kitchen cabinet installation', 6, 3, 1, 1, CURRENT_DATE + INTERVAL '21 days', NULL, 5000.00, 16, false, false), - (50, NOW() - INTERVAL '7 days', NOW(), 11, 8, 8, 'Run new electrical', 'Additional outlets for kitchen', 2, 3, 2, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 1200.00, NULL, false, false), - (51, NOW() - INTERVAL '3 days', NOW(), 11, 8, NULL, 'Plumbing rough-in', 'Rough plumbing for bathroom remodel', 1, 3, 1, 1, CURRENT_DATE + INTERVAL '10 days', NULL, 2500.00, NULL, false, false), - (52, NOW() - INTERVAL '1 day', NOW(), 11, 8, 8, 'Order new appliances', 'Select and order kitchen appliances', 4, 2, 2, 1, CURRENT_DATE + INTERVAL '5 days', NULL, 4000.00, NULL, false, false), + (48, NOW() - INTERVAL '14 days', NOW(), 11, 8, 8, 'Demo bathroom tile', 'Remove old tile in master bathroom', 6, 3, true, 1, CURRENT_DATE + INTERVAL '7 days', NULL, 500.00, 15, false, false), + (49, NOW() - INTERVAL '10 days', NOW(), 11, 8, NULL, 'Install new cabinets', 'Kitchen cabinet installation', 6, 3, false, 1, CURRENT_DATE + INTERVAL '21 days', NULL, 5000.00, 16, false, false), + (50, NOW() - INTERVAL '7 days', NOW(), 11, 8, 8, 'Run new electrical', 'Additional outlets for kitchen', 2, 3, true, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 1200.00, NULL, false, false), + (51, NOW() - INTERVAL '3 days', NOW(), 11, 8, NULL, 'Plumbing rough-in', 'Rough plumbing for bathroom remodel', 1, 3, false, 1, CURRENT_DATE + INTERVAL '10 days', NULL, 2500.00, NULL, false, false), + (52, NOW() - INTERVAL '1 day', NOW(), 11, 8, 8, 'Order new appliances', 'Select and order kitchen appliances', 4, 2, true, 1, CURRENT_DATE + INTERVAL '5 days', NULL, 4000.00, NULL, false, false), -- ===== RESIDENCE 12 (Fiona's Studio) - 4 tasks ===== - (53, NOW() - INTERVAL '7 days', NOW(), 12, 9, 9, 'Setup smart lights', 'Install Philips Hue throughout studio', 2, 1, 3, 1, CURRENT_DATE - INTERVAL '3 days', NULL, 400.00, 17, false, false), - (54, NOW() - INTERVAL '5 days', NOW(), 12, 9, NULL, 'Mount TV on wall', 'Install TV mount and hide cables', 2, 1, 1, 1, CURRENT_DATE + INTERVAL '10 days', NULL, 200.00, 17, false, false), - (55, NOW() - INTERVAL '3 days', NOW(), 12, 9, 9, 'Organize closet', 'Install closet organization system', 10, 1, 2, 1, CURRENT_DATE + INTERVAL '7 days', NULL, 300.00, NULL, false, false), - (56, NOW() - INTERVAL '1 day', NOW(), 12, 9, NULL, 'Replace faucet aerator', 'Low water pressure in bathroom sink', 1, 1, 1, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 15.00, NULL, false, false), + (53, NOW() - INTERVAL '7 days', NOW(), 12, 9, 9, 'Setup smart lights', 'Install Philips Hue throughout studio', 2, 1, false, 1, CURRENT_DATE - INTERVAL '3 days', NULL, 400.00, 17, false, false), + (54, NOW() - INTERVAL '5 days', NOW(), 12, 9, NULL, 'Mount TV on wall', 'Install TV mount and hide cables', 2, 1, false, 1, CURRENT_DATE + INTERVAL '10 days', NULL, 200.00, 17, false, false), + (55, NOW() - INTERVAL '3 days', NOW(), 12, 9, 9, 'Organize closet', 'Install closet organization system', 10, 1, true, 1, CURRENT_DATE + INTERVAL '7 days', NULL, 300.00, NULL, false, false), + (56, NOW() - INTERVAL '1 day', NOW(), 12, 9, NULL, 'Replace faucet aerator', 'Low water pressure in bathroom sink', 1, 1, false, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 15.00, NULL, false, false), -- ===== RESIDENCE 13 (George's Townhome) - 5 tasks ===== -- Task 57: Quarterly recurring, completed 15 days ago -> next_due_date = completion + 90 days = ~75 days from now - (57, NOW() - INTERVAL '30 days', NOW(), 13, 12, 12, 'Service pool equipment', 'Quarterly pool pump and filter service', 10, 2, 1, 6, CURRENT_DATE - INTERVAL '15 days', CURRENT_DATE + INTERVAL '75 days', 175.00, 19, false, false), - (58, NOW() - INTERVAL '20 days', NOW(), 13, 12, NULL, 'HVAC maintenance', 'Pre-summer AC tune-up', 3, 2, 1, 8, CURRENT_DATE + INTERVAL '30 days', NULL, 200.00, 18, false, false), - (59, NOW() - INTERVAL '10 days', NOW(), 13, 12, 12, 'Trim desert landscaping', 'Prune cacti and desert plants', 5, 1, 2, 6, CURRENT_DATE + INTERVAL '5 days', NULL, 100.00, NULL, false, false), + (57, NOW() - INTERVAL '30 days', NOW(), 13, 12, 12, 'Service pool equipment', 'Quarterly pool pump and filter service', 10, 2, false, 6, CURRENT_DATE - INTERVAL '15 days', CURRENT_DATE + INTERVAL '75 days', 175.00, 19, false, false), + (58, NOW() - INTERVAL '20 days', NOW(), 13, 12, NULL, 'HVAC maintenance', 'Pre-summer AC tune-up', 3, 2, false, 8, CURRENT_DATE + INTERVAL '30 days', NULL, 200.00, 18, false, false), + (59, NOW() - INTERVAL '10 days', NOW(), 13, 12, 12, 'Trim desert landscaping', 'Prune cacti and desert plants', 5, 1, true, 6, CURRENT_DATE + INTERVAL '5 days', NULL, 100.00, NULL, false, false), -- Task 60: Monthly recurring, completed 30 days ago -> next_due_date = completion + 30 days = today (due soon) - (60, NOW() - INTERVAL '45 days', NOW(), 13, 12, 12, 'Check irrigation system', 'Test all drip irrigation zones', 5, 2, 1, 5, CURRENT_DATE - INTERVAL '30 days', CURRENT_DATE, 50.00, NULL, false, false), - (61, NOW() - INTERVAL '5 days', NOW(), 13, 12, NULL, 'Replace garage door opener', 'Old opener failing', 4, 2, 1, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 400.00, NULL, false, false), + (60, NOW() - INTERVAL '45 days', NOW(), 13, 12, 12, 'Check irrigation system', 'Test all drip irrigation zones', 5, 2, false, 5, CURRENT_DATE - INTERVAL '30 days', CURRENT_DATE, 50.00, NULL, false, false), + (61, NOW() - INTERVAL '5 days', NOW(), 13, 12, NULL, 'Replace garage door opener', 'Old opener failing', 4, 2, false, 1, CURRENT_DATE + INTERVAL '14 days', NULL, 400.00, NULL, false, false), -- Cancelled task - (62, NOW() - INTERVAL '60 days', NOW(), 1, 2, NULL, 'Build treehouse', 'Cancelled - tree not suitable', 6, 1, 5, 1, CURRENT_DATE - INTERVAL '30 days', NULL, 2000.00, NULL, true, false) + (62, NOW() - INTERVAL '60 days', NOW(), 1, 2, NULL, 'Build treehouse', 'Cancelled - tree not suitable', 6, 1, false, 1, CURRENT_DATE - INTERVAL '30 days', NULL, 2000.00, NULL, true, false) ON CONFLICT (id) DO UPDATE SET title = EXCLUDED.title, updated_at = NOW(); -- =====================================================