Migrate from Gin to Echo framework and add comprehensive integration tests

Major changes:
- Migrate all handlers from Gin to Echo framework
- Add new apperrors, echohelpers, and validator packages
- Update middleware for Echo compatibility
- Add ArchivedHandler to task categorization chain (archived tasks go to cancelled_tasks column)
- Add 6 new integration tests:
  - RecurringTaskLifecycle: NextDueDate advancement for weekly/monthly tasks
  - MultiUserSharing: Complex sharing with user removal
  - TaskStateTransitions: All state transitions and kanban column changes
  - DateBoundaryEdgeCases: Threshold boundary testing
  - CascadeOperations: Residence deletion cascade effects
  - MultiUserOperations: Shared residence collaboration
- Add single-purpose repository functions for kanban columns (GetOverdueTasks, GetDueSoonTasks, etc.)
- Fix RemoveUser route param mismatch (userId -> user_id)
- Fix determineExpectedColumn helper to correctly prioritize in_progress over overdue

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-16 13:52:08 -06:00
parent c51f1ce34a
commit 6dac34e373
98 changed files with 8209 additions and 4425 deletions

View File

@@ -869,8 +869,12 @@ func TestEdgeCase_TaskDueExactlyAtThreshold(t *testing.T) {
}
func TestEdgeCase_TaskDueJustBeforeThreshold(t *testing.T) {
// 29 days and 23 hours from now
dueDate := time.Now().UTC().Add(29*24*time.Hour + 23*time.Hour)
// Task due 29 days from today's start of day should be "due_soon"
// (within the 30-day threshold)
now := time.Now().UTC()
startOfToday := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
dueDate := startOfToday.AddDate(0, 0, 29) // 29 days from start of today
task := &models.Task{
NextDueDate: &dueDate,
}
@@ -878,7 +882,7 @@ func TestEdgeCase_TaskDueJustBeforeThreshold(t *testing.T) {
column := responses.DetermineKanbanColumn(task, 30)
assert.Equal(t, "due_soon_tasks", column,
"Task due just before threshold should be in due_soon")
"Task due 29 days from today should be in due_soon (within 30-day threshold)")
}
func TestEdgeCase_TaskDueInPast_ButHasCompletionAfter(t *testing.T) {
@@ -955,20 +959,23 @@ func TestEdgeCase_MonthlyRecurringTask(t *testing.T) {
CompletedAt: completedAt,
})
// Update NextDueDate
// Update NextDueDate - set to 29 days from today (within 30-day threshold)
task, _ = taskRepo.FindByID(task.ID)
nextDue := completedAt.AddDate(0, 0, 30) // 30 days from now
now := time.Now().UTC()
startOfToday := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
nextDue := startOfToday.AddDate(0, 0, 29) // 29 days from start of today (within threshold)
task.NextDueDate = &nextDue
db.Save(task)
task, _ = taskRepo.FindByID(task.ID)
// 30 days from now is at/within threshold boundary - due to time precision,
// a task at exactly the threshold boundary is considered "due_soon" not "upcoming"
// because the check is NextDueDate.Before(threshold) which includes boundary due to ms precision
// With day-based comparisons:
// - Threshold = start of today + 30 days
// - A task due on day 29 is Before(threshold), so it's "due_soon"
// - A task due on day 30+ is NOT Before(threshold), so it's "upcoming"
column := responses.DetermineKanbanColumn(task, 30)
assert.Equal(t, "due_soon_tasks", column,
"Monthly task at 30-day boundary should be due_soon (at threshold)")
"Monthly task within 30-day threshold should be due_soon")
}
func TestEdgeCase_ZeroDayFrequency_TreatedAsOneTime(t *testing.T) {