From efc6118a983959e12997c3e5f50ca0bb8aa1431e Mon Sep 17 00:00:00 2001 From: Trey t Date: Sun, 7 Dec 2025 10:03:35 -0600 Subject: [PATCH] Fix notification handlers to exclude completed tasks from kanban MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated task reminder and overdue reminder queries to match the kanban categorization logic. A task is now considered "completed" (excluded from notifications) if it has NextDueDate IS NULL AND at least one completion record, rather than checking if completion was after the due date. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- internal/worker/jobs/handler.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/internal/worker/jobs/handler.go b/internal/worker/jobs/handler.go index bffedad..8f61550 100644 --- a/internal/worker/jobs/handler.go +++ b/internal/worker/jobs/handler.go @@ -101,13 +101,17 @@ func (h *Handler) HandleTaskReminder(ctx context.Context, task *asynq.Task) erro log.Info().Int("eligible_users", len(eligibleUserIDs)).Msg("Found users eligible for task reminders this hour") // Step 2: Query tasks due today or tomorrow only for eligible users + // A task is considered "completed" (and should be excluded) if: + // - NextDueDate IS NULL AND it has at least one completion record + // This matches the kanban categorization logic var dueSoonTasks []models.Task err = h.db.Preload("Status").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"). Where("is_archived = false"). - Where("NOT EXISTS (SELECT 1 FROM task_taskcompletion tc WHERE tc.task_id = task_task.id AND tc.completed_at >= task_task.due_date)"). + // Exclude completed tasks: tasks with no next_due_date AND at least one completion + Where("NOT (next_due_date IS NULL AND EXISTS (SELECT 1 FROM task_taskcompletion tc WHERE tc.task_id = task_task.id))"). Where("(assigned_to_id IN ? OR residence_id IN (SELECT id FROM residence_residence WHERE owner_id IN ?))", eligibleUserIDs, eligibleUserIDs). Find(&dueSoonTasks).Error @@ -214,12 +218,16 @@ func (h *Handler) HandleOverdueReminder(ctx context.Context, task *asynq.Task) e log.Info().Int("eligible_users", len(eligibleUserIDs)).Msg("Found users eligible for overdue reminders this hour") // Step 2: Query overdue tasks only for eligible users + // A task is considered "completed" (and should be excluded) if: + // - NextDueDate IS NULL AND it has at least one completion record + // This matches the kanban categorization logic var overdueTasks []models.Task err = h.db.Preload("Status").Preload("Completions").Preload("Residence"). Where("due_date < ? OR next_due_date < ?", today, today). Where("is_cancelled = false"). Where("is_archived = false"). - Where("NOT EXISTS (SELECT 1 FROM task_taskcompletion tc WHERE tc.task_id = task_task.id AND tc.completed_at >= task_task.due_date)"). + // Exclude completed tasks: tasks with no next_due_date AND at least one completion + Where("NOT (next_due_date IS NULL AND EXISTS (SELECT 1 FROM task_taskcompletion tc WHERE tc.task_id = task_task.id))"). Where("(assigned_to_id IN ? OR residence_id IN (SELECT id FROM residence_residence WHERE owner_id IN ?))", eligibleUserIDs, eligibleUserIDs). Find(&overdueTasks).Error