Files
honeyDueAPI/internal/notifications/reminder_config.go
Trey t 69206c6930 Add smart notification reminder system with frequency-aware scheduling
Replaces one-size-fits-all "2 days before" reminders with intelligent
scheduling based on task frequency. Infrequent tasks (annual) get 30-day
advance notice while frequent tasks (weekly) only get day-of reminders.

Key features:
- Frequency-aware pre-reminders: annual (30d, 14d, 7d), quarterly (7d, 3d),
  monthly (3d), bi-weekly (1d), daily/weekly/once (day-of only)
- Overdue tapering: daily for 3 days, then every 3 days, stops after 14 days
- Reminder log table prevents duplicate notifications per due date/stage
- Admin endpoint displays notification schedules for all frequencies
- Comprehensive test suite (100 random tasks, 61 days each, 10 test functions)

New files:
- internal/notifications/reminder_config.go - Editable schedule configuration
- internal/notifications/reminder_schedule.go - Schedule lookup logic
- internal/notifications/reminder_schedule_test.go - Dynamic test suite
- internal/models/reminder_log.go - TaskReminderLog model
- internal/repositories/reminder_repo.go - Reminder log repository
- migrations/010_add_task_reminder_log.{up,down}.sql

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 23:03:28 -06:00

64 lines
2.5 KiB
Go

package notifications
// ============================================================
// REMINDER CONFIGURATION
// Edit these values to adjust notification behavior
// ============================================================
// OverdueConfig controls when and how often overdue reminders are sent
var OverdueConfig = struct {
DailyReminderDays int // Send daily reminders for first N days overdue
TaperIntervalDays int // After daily period, remind every N days
MaxOverdueDays int // Stop reminding after N days overdue
}{
DailyReminderDays: 3, // Daily for days 1-3
TaperIntervalDays: 3, // Then every 3 days (4, 7, 10, 13)
MaxOverdueDays: 14, // Stop after 14 days
}
// FrequencySchedules - EXPLICIT entry for each of the 9 seeded frequencies
// Key: interval days (matches TaskFrequency.days in DB, 0 = Once/null)
// Value: array of days before due date to send reminders (0 = day-of)
//
// To add a reminder: append the number of days before to the slice
// Example: FrequencySchedules[30] = []int{7, 3, 0} adds 7-day warning to Monthly
var FrequencySchedules = map[int][]int{
0: {0}, // 1. Once (null/0): day-of only
1: {0}, // 2. Daily: day-of only
7: {0}, // 3. Weekly: day-of only
14: {1, 0}, // 4. Bi-Weekly: 1 day before, day-of
30: {3, 0}, // 5. Monthly: 3 days before, day-of
90: {7, 3, 0}, // 6. Quarterly: 7d, 3d, day-of
180: {14, 7, 0}, // 7. Semi-Annually: 14d, 7d, day-of
365: {30, 14, 7, 0}, // 8. Annually: 30d, 14d, 7d, day-of
}
// HumanReadableSchedule returns admin-friendly description for each frequency
// Key: interval days (matches FrequencySchedules keys)
// Value: human-readable description of the reminder schedule
var HumanReadableSchedule = map[int]string{
0: "Day-of → Overdue (tapering)",
1: "Day-of → Overdue (tapering)",
7: "Day-of → Overdue (tapering)",
14: "1 day before → Day-of → Overdue",
30: "3 days before → Day-of → Overdue",
90: "7d → 3d → Day-of → Overdue",
180: "14d → 7d → Day-of → Overdue",
365: "30d → 14d → 7d → Day-of → Overdue",
}
// FrequencyNames maps interval days to frequency names for display
var FrequencyNames = map[int]string{
0: "Once",
1: "Daily",
7: "Weekly",
14: "Bi-Weekly",
30: "Monthly",
90: "Quarterly",
180: "Semi-Annually",
365: "Annually",
}
// OrderedFrequencies defines the display order for frequencies
var OrderedFrequencies = []int{0, 1, 7, 14, 30, 90, 180, 365}