Add performance optimizations and database indexes

Database Indexes (migrations 006-009):
- Add case-insensitive indexes for auth lookups (email, username)
- Add composite indexes for task kanban queries
- Add indexes for notification, document, and completion queries
- Add unique index for active share codes
- Remove redundant idx_share_code_active and idx_notification_user_sent

Repository Optimizations:
- Add FindResidenceIDsByUser() lightweight method (IDs only, no preloads)
- Optimize GetResidenceUsers() with single UNION query (was 2 queries)
- Optimize kanban completion preloads to minimal columns (id, task_id, completed_at)

Service Optimizations:
- Remove Category/Priority/Frequency preloads from task queries
- Remove summary calculations from CRUD responses (client calculates)
- Use lightweight FindResidenceIDsByUser() instead of full FindByUser()

These changes reduce database load and response times for common operations.

🤖 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-14 01:06:08 -06:00
parent 2ea5cea936
commit 0cf64cfb0c
22 changed files with 436 additions and 203 deletions

View File

@@ -29,7 +29,7 @@ import (
//
// next_due_date IS NULL AND EXISTS (SELECT 1 FROM task_taskcompletion tc WHERE tc.task_id = task_task.id)
func IsCompleted(task *models.Task) bool {
return task.NextDueDate == nil && len(task.Completions) > 0
return task.NextDueDate == nil && HasCompletions(task)
}
// IsActive returns true if the task is not cancelled and not archived.
@@ -165,13 +165,27 @@ func IsUpcoming(task *models.Task, now time.Time, daysThreshold int) bool {
// =============================================================================
// HasCompletions returns true if the task has at least one completion record.
// Supports both preloaded Completions slice and computed CompletionCount field
// for optimized queries that use COUNT subqueries instead of preloading.
func HasCompletions(task *models.Task) bool {
return len(task.Completions) > 0
// If Completions were preloaded, use the slice
if len(task.Completions) > 0 {
return true
}
// Otherwise check the computed count (populated via subquery for optimized queries)
return task.CompletionCount > 0
}
// CompletionCount returns the number of completions for a task.
func CompletionCount(task *models.Task) int {
return len(task.Completions)
// GetCompletionCount returns the number of completions for a task.
// Supports both preloaded Completions slice and computed CompletionCount field
// for optimized queries that use COUNT subqueries instead of preloading.
func GetCompletionCount(task *models.Task) int {
// If Completions were preloaded, use the slice length
if len(task.Completions) > 0 {
return len(task.Completions)
}
// Otherwise return the computed count (populated via subquery for optimized queries)
return task.CompletionCount
}
// =============================================================================