Fix backend API parity: document filters, task days param, i18n locales, contract tests

- Add document list filter support (residence, type, category, contractor, is_active, expiring_soon, search) to handler/service/repo
- Add `days` query param parsing to ListTasks handler (matches ListTasksByResidence)
- Add `error.invalid_token` i18n key to all 9 non-English locale files
- Update contract test to include VerificationResponse mapping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-18 18:49:48 -06:00
parent bb7493f033
commit e7c23bdeb1
16 changed files with 139 additions and 11 deletions

View File

@@ -56,8 +56,8 @@ func (s *DocumentService) GetDocument(documentID, userID uint) (*responses.Docum
return &resp, nil
}
// ListDocuments lists all documents accessible to a user
func (s *DocumentService) ListDocuments(userID uint) ([]responses.DocumentResponse, error) {
// ListDocuments lists all documents accessible to a user, with optional filters.
func (s *DocumentService) ListDocuments(userID uint, filter *repositories.DocumentFilter) ([]responses.DocumentResponse, error) {
// Get residence IDs (lightweight - no preloads)
residenceIDs, err := s.residenceRepo.FindResidenceIDsByUser(userID)
if err != nil {
@@ -68,7 +68,22 @@ func (s *DocumentService) ListDocuments(userID uint) ([]responses.DocumentRespon
return []responses.DocumentResponse{}, nil
}
documents, err := s.documentRepo.FindByUser(residenceIDs)
// If a specific residence filter is set, narrow to that single residence (if user has access)
if filter != nil && filter.ResidenceID != nil {
found := false
for _, rid := range residenceIDs {
if rid == *filter.ResidenceID {
found = true
break
}
}
if !found {
return nil, apperrors.Forbidden("error.residence_access_denied")
}
residenceIDs = []uint{*filter.ResidenceID}
}
documents, err := s.documentRepo.FindByUserFiltered(residenceIDs, filter)
if err != nil {
return nil, apperrors.Internal(err)
}

View File

@@ -103,7 +103,11 @@ func (s *TaskService) GetTask(taskID, userID uint) (*responses.TaskResponse, err
// ListTasks lists all tasks accessible to a user as a kanban board.
// The `now` parameter should be the start of day in the user's timezone for accurate overdue detection.
func (s *TaskService) ListTasks(userID uint, now time.Time) (*responses.KanbanBoardResponse, error) {
func (s *TaskService) ListTasks(userID uint, daysThreshold int, now time.Time) (*responses.KanbanBoardResponse, error) {
if daysThreshold <= 0 {
daysThreshold = 30 // Default
}
// Get all residence IDs accessible to user (lightweight - no preloads)
residenceIDs, err := s.residenceRepo.FindResidenceIDsByUser(userID)
if err != nil {
@@ -114,13 +118,13 @@ func (s *TaskService) ListTasks(userID uint, now time.Time) (*responses.KanbanBo
// Return empty kanban board
return &responses.KanbanBoardResponse{
Columns: []responses.KanbanColumnResponse{},
DaysThreshold: 30,
DaysThreshold: daysThreshold,
ResidenceID: "all",
}, nil
}
// Get kanban data aggregated across all residences using user's timezone-aware time
board, err := s.taskRepo.GetKanbanDataForMultipleResidences(residenceIDs, 30, now)
board, err := s.taskRepo.GetKanbanDataForMultipleResidences(residenceIDs, daysThreshold, now)
if err != nil {
return nil, apperrors.Internal(err)
}

View File

@@ -155,7 +155,7 @@ func TestTaskService_ListTasks(t *testing.T) {
testutil.CreateTestTask(t, db, residence.ID, user.ID, "Task 2")
testutil.CreateTestTask(t, db, residence.ID, user.ID, "Task 3")
resp, err := service.ListTasks(user.ID, time.Now().UTC())
resp, err := service.ListTasks(user.ID, 30, time.Now().UTC())
require.NoError(t, err)
// ListTasks returns a KanbanBoardResponse with columns
// Count total tasks across all columns