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

@@ -136,23 +136,18 @@ func (s *ResidenceService) GetMyResidences(userID uint, now time.Time) (*respons
// This is a lightweight endpoint for refreshing summary counts without full residence data.
// The `now` parameter should be the start of day in the user's timezone for accurate overdue detection.
func (s *ResidenceService) GetSummary(userID uint, now time.Time) (*responses.TotalSummary, error) {
residences, err := s.residenceRepo.FindByUser(userID)
// Get residence IDs (lightweight - no preloads)
residenceIDs, err := s.residenceRepo.FindResidenceIDsByUser(userID)
if err != nil {
return nil, err
}
summary := &responses.TotalSummary{
TotalResidences: len(residences),
TotalResidences: len(residenceIDs),
}
// Get task statistics if task repository is available
if s.taskRepo != nil && len(residences) > 0 {
// Collect residence IDs
residenceIDs := make([]uint, len(residences))
for i, r := range residences {
residenceIDs[i] = r.ID
}
if s.taskRepo != nil && len(residenceIDs) > 0 {
// Get aggregated statistics using user's timezone-aware time
stats, err := s.taskRepo.GetTaskStatistics(residenceIDs, now)
if err == nil && stats != nil {
@@ -167,14 +162,14 @@ func (s *ResidenceService) GetSummary(userID uint, now time.Time) (*responses.To
return summary, nil
}
// getSummaryForUser is a helper that returns summary for a user, or empty summary on error.
// Uses UTC time. For timezone-aware summary, use GetSummary directly.
func (s *ResidenceService) getSummaryForUser(userID uint) responses.TotalSummary {
summary, err := s.GetSummary(userID, time.Now().UTC())
if err != nil || summary == nil {
return responses.TotalSummary{}
}
return *summary
// getSummaryForUser returns an empty summary placeholder.
// DEPRECATED: Summary calculation has been removed from CRUD responses for performance.
// Clients should calculate summary from kanban data instead (which already includes all tasks).
// The summary field is kept in responses for backward compatibility but will always be empty.
// For actual summary data, use GetSummary() directly or rely on my-residences/kanban endpoints.
func (s *ResidenceService) getSummaryForUser(_ uint) responses.TotalSummary {
// Return empty summary - clients should calculate from kanban data
return responses.TotalSummary{}
}
// CreateResidence creates a new residence and returns it with updated summary