From 8962850003f149dc1fcfcfc6c019fcad973d2d36 Mon Sep 17 00:00:00 2001 From: Trey t Date: Mon, 22 Dec 2025 20:19:40 -0600 Subject: [PATCH] Replace old notification handlers with smart reminder system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add TaskReminderLog to AutoMigrate (table was missing) - Remove HandleTaskReminder and HandleOverdueReminder registrations - Register HandleSmartReminder which uses frequency-aware scheduling and tracks sent reminders to prevent duplicates The old handlers sent ALL overdue tasks daily regardless of age. Smart reminder tapers off (daily for 3 days, then every 3 days, stops at 14). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- cmd/worker/main.go | 20 +++++++------------- internal/database/database.go | 1 + 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/cmd/worker/main.go b/cmd/worker/main.go index f910117..729c851 100644 --- a/cmd/worker/main.go +++ b/cmd/worker/main.go @@ -134,8 +134,7 @@ func main() { // Create Asynq mux and register handlers mux := asynq.NewServeMux() - mux.HandleFunc(jobs.TypeTaskReminder, jobHandler.HandleTaskReminder) - mux.HandleFunc(jobs.TypeOverdueReminder, jobHandler.HandleOverdueReminder) + mux.HandleFunc(jobs.TypeSmartReminder, jobHandler.HandleSmartReminder) mux.HandleFunc(jobs.TypeDailyDigest, jobHandler.HandleDailyDigest) mux.HandleFunc(jobs.TypeSendEmail, jobHandler.HandleSendEmail) mux.HandleFunc(jobs.TypeSendPush, jobHandler.HandleSendPush) @@ -144,18 +143,13 @@ func main() { // Start scheduler for periodic tasks scheduler := asynq.NewScheduler(redisOpt, nil) - // Schedule task reminder notifications (runs every hour to support per-user custom times) - // The job handler filters users based on their preferred notification hour - if _, err := scheduler.Register("0 * * * *", asynq.NewTask(jobs.TypeTaskReminder, nil)); err != nil { - log.Fatal().Err(err).Msg("Failed to register task reminder job") + // Schedule smart reminder notifications (runs every hour to support per-user custom times) + // Replaces old task reminder and overdue reminder with frequency-aware system + // Uses TaskReminderLog to prevent duplicate notifications + if _, err := scheduler.Register("0 * * * *", asynq.NewTask(jobs.TypeSmartReminder, nil)); err != nil { + log.Fatal().Err(err).Msg("Failed to register smart reminder job") } - log.Info().Str("cron", "0 * * * *").Int("default_hour", cfg.Worker.TaskReminderHour).Msg("Registered task reminder job (runs hourly for per-user times)") - - // Schedule overdue reminder (runs every hour to support per-user custom times) - if _, err := scheduler.Register("0 * * * *", asynq.NewTask(jobs.TypeOverdueReminder, nil)); err != nil { - log.Fatal().Err(err).Msg("Failed to register overdue reminder job") - } - log.Info().Str("cron", "0 * * * *").Int("default_hour", cfg.Worker.OverdueReminderHour).Msg("Registered overdue reminder job (runs hourly for per-user times)") + log.Info().Str("cron", "0 * * * *").Int("default_hour", cfg.Worker.TaskReminderHour).Msg("Registered smart reminder job (runs hourly for per-user times)") // Schedule daily digest (runs every hour to support per-user custom times) // The job handler filters users based on their preferred notification hour diff --git a/internal/database/database.go b/internal/database/database.go index a8e6377..4c08a17 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -144,6 +144,7 @@ func Migrate() error { &models.NotificationPreference{}, &models.APNSDevice{}, &models.GCMDevice{}, + &models.TaskReminderLog{}, // Smart reminder tracking // Subscription tables &models.SubscriptionSettings{},