Migrate TaskService + ResidenceService to ctx-aware repos
Backend CI / Test (push) Has been cancelled
Backend CI / Contract Tests (push) Has been cancelled
Backend CI / Build (push) Has been cancelled
Backend CI / Lint (push) Has been cancelled
Backend CI / Secret Scanning (push) Has been cancelled

Every public method on TaskService and ResidenceService now takes
ctx context.Context as the first arg and routes its repo calls through
.WithContext(ctx). With otelgorm registered, this means every API
endpoint backed by these two services produces a flame graph in Jaeger
where the SQL spans nest under the parent HTTP request span — instead
of appearing as orphaned queries.

Endpoints now fully traced (HTTP → service → SQL):
- GET    /api/tasks/                       (already shipped)
- GET    /api/tasks/by-residence/:id/      (already shipped)
- GET    /api/tasks/:id/
- POST   /api/tasks/
- POST   /api/tasks/bulk/
- PUT    /api/tasks/:id/
- DELETE /api/tasks/:id/
- POST   /api/tasks/:id/in-progress/
- POST   /api/tasks/:id/cancel/
- POST   /api/tasks/:id/uncancel/
- POST   /api/tasks/:id/archive/
- POST   /api/tasks/:id/unarchive/
- POST   /api/tasks/:id/complete/
- POST   /api/tasks/:id/quick-complete/
- GET    /api/tasks/completions/* (CRUD)
- GET    /api/static_data/ (categories, priorities, frequencies)
- GET    /api/residences/
- GET    /api/residences/my/
- GET    /api/residences/summary/
- GET    /api/residences/:id/
- POST   /api/residences/
- PUT    /api/residences/:id/
- DELETE /api/residences/:id/
- Share-code + member management endpoints
- GET    /api/residences/:id/report/

Mechanical work: ~50 method signatures, ~80 handler call sites,
~25 test call sites updated. Internal sendTaskCompletedNotification
helper also takes ctx so background notification SQL nests correctly.

The remaining services (ContractorService, DocumentService,
AuthService, NotificationService, SubscriptionService) follow the same
pattern; they continue to emit untraced SQL until migrated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-04-25 16:04:01 -05:00
parent 3f5bf21e09
commit 65a9aae4e5
9 changed files with 382 additions and 378 deletions
+15 -15
View File
@@ -39,7 +39,7 @@ func (h *ResidenceHandler) ListResidences(c echo.Context) error {
return err
}
response, err := h.residenceService.ListResidences(user.ID)
response, err := h.residenceService.ListResidences(c.Request().Context(), user.ID)
if err != nil {
return err
}
@@ -55,7 +55,7 @@ func (h *ResidenceHandler) GetMyResidences(c echo.Context) error {
}
userNow := middleware.GetUserNow(c)
response, err := h.residenceService.GetMyResidences(user.ID, userNow)
response, err := h.residenceService.GetMyResidences(c.Request().Context(), user.ID, userNow)
if err != nil {
return err
}
@@ -72,7 +72,7 @@ func (h *ResidenceHandler) GetSummary(c echo.Context) error {
}
userNow := middleware.GetUserNow(c)
summary, err := h.residenceService.GetSummary(user.ID, userNow)
summary, err := h.residenceService.GetSummary(c.Request().Context(), user.ID, userNow)
if err != nil {
return err
}
@@ -93,7 +93,7 @@ func (h *ResidenceHandler) GetResidence(c echo.Context) error {
}
userNow := middleware.GetUserNow(c)
response, err := h.residenceService.GetResidence(uint(residenceID), user.ID, userNow)
response, err := h.residenceService.GetResidence(c.Request().Context(), uint(residenceID), user.ID, userNow)
if err != nil {
return err
}
@@ -116,7 +116,7 @@ func (h *ResidenceHandler) CreateResidence(c echo.Context) error {
return c.JSON(http.StatusBadRequest, validator.FormatValidationErrors(err))
}
response, err := h.residenceService.CreateResidence(&req, user.ID)
response, err := h.residenceService.CreateResidence(c.Request().Context(), &req, user.ID)
if err != nil {
return err
}
@@ -144,7 +144,7 @@ func (h *ResidenceHandler) UpdateResidence(c echo.Context) error {
return c.JSON(http.StatusBadRequest, validator.FormatValidationErrors(err))
}
response, err := h.residenceService.UpdateResidence(uint(residenceID), user.ID, &req)
response, err := h.residenceService.UpdateResidence(c.Request().Context(), uint(residenceID), user.ID, &req)
if err != nil {
return err
}
@@ -164,7 +164,7 @@ func (h *ResidenceHandler) DeleteResidence(c echo.Context) error {
return apperrors.BadRequest("error.invalid_residence_id")
}
response, err := h.residenceService.DeleteResidence(uint(residenceID), user.ID)
response, err := h.residenceService.DeleteResidence(c.Request().Context(), uint(residenceID), user.ID)
if err != nil {
return err
}
@@ -185,7 +185,7 @@ func (h *ResidenceHandler) GetShareCode(c echo.Context) error {
return apperrors.BadRequest("error.invalid_residence_id")
}
shareCode, err := h.residenceService.GetShareCode(uint(residenceID), user.ID)
shareCode, err := h.residenceService.GetShareCode(c.Request().Context(), uint(residenceID), user.ID)
if err != nil {
return err
}
@@ -213,7 +213,7 @@ func (h *ResidenceHandler) GenerateShareCode(c echo.Context) error {
// Request body is optional
c.Bind(&req)
response, err := h.residenceService.GenerateShareCode(uint(residenceID), user.ID, req.ExpiresInHours)
response, err := h.residenceService.GenerateShareCode(c.Request().Context(), uint(residenceID), user.ID, req.ExpiresInHours)
if err != nil {
return err
}
@@ -238,7 +238,7 @@ func (h *ResidenceHandler) GenerateSharePackage(c echo.Context) error {
// Request body is optional (for expires_in_hours)
c.Bind(&req)
response, err := h.residenceService.GenerateSharePackage(uint(residenceID), user.ID, req.ExpiresInHours)
response, err := h.residenceService.GenerateSharePackage(c.Request().Context(), uint(residenceID), user.ID, req.ExpiresInHours)
if err != nil {
return err
}
@@ -261,7 +261,7 @@ func (h *ResidenceHandler) JoinWithCode(c echo.Context) error {
return err
}
response, err := h.residenceService.JoinWithCode(req.Code, user.ID)
response, err := h.residenceService.JoinWithCode(c.Request().Context(), req.Code, user.ID)
if err != nil {
return err
}
@@ -281,7 +281,7 @@ func (h *ResidenceHandler) GetResidenceUsers(c echo.Context) error {
return apperrors.BadRequest("error.invalid_residence_id")
}
users, err := h.residenceService.GetResidenceUsers(uint(residenceID), user.ID)
users, err := h.residenceService.GetResidenceUsers(c.Request().Context(), uint(residenceID), user.ID)
if err != nil {
return err
}
@@ -306,7 +306,7 @@ func (h *ResidenceHandler) RemoveResidenceUser(c echo.Context) error {
return apperrors.BadRequest("error.invalid_user_id")
}
err = h.residenceService.RemoveUser(uint(residenceID), uint(userIDToRemove), user.ID)
err = h.residenceService.RemoveUser(c.Request().Context(), uint(residenceID), uint(userIDToRemove), user.ID)
if err != nil {
return err
}
@@ -316,7 +316,7 @@ func (h *ResidenceHandler) RemoveResidenceUser(c echo.Context) error {
// GetResidenceTypes handles GET /api/residences/types/
func (h *ResidenceHandler) GetResidenceTypes(c echo.Context) error {
types, err := h.residenceService.GetResidenceTypes()
types, err := h.residenceService.GetResidenceTypes(c.Request().Context())
if err != nil {
return err
}
@@ -348,7 +348,7 @@ func (h *ResidenceHandler) GenerateTasksReport(c echo.Context) error {
c.Bind(&req)
// Generate the report data
report, err := h.residenceService.GenerateTasksReport(uint(residenceID), user.ID)
report, err := h.residenceService.GenerateTasksReport(c.Request().Context(), uint(residenceID), user.ID)
if err != nil {
return err
}
+3 -2
View File
@@ -1,6 +1,7 @@
package handlers
import (
"context"
"encoding/json"
"fmt"
"net/http"
@@ -324,7 +325,7 @@ func TestResidenceHandler_JoinWithCode(t *testing.T) {
userRepo := repositories.NewUserRepository(db)
cfg := &config.Config{}
residenceService := services.NewResidenceService(residenceRepo, userRepo, cfg)
shareResp, _ := residenceService.GenerateShareCode(residence.ID, owner.ID, 24)
shareResp, _ := residenceService.GenerateShareCode(context.Background(), residence.ID, owner.ID, 24)
authGroup := e.Group("/api/residences")
authGroup.Use(testutil.MockAuthMiddleware(newUser))
@@ -357,7 +358,7 @@ func TestResidenceHandler_JoinWithCode(t *testing.T) {
t.Run("owner tries to join own residence", func(t *testing.T) {
// Generate new code
shareResp2, _ := residenceService.GenerateShareCode(residence.ID, owner.ID, 24)
shareResp2, _ := residenceService.GenerateShareCode(context.Background(), residence.ID, owner.ID, 24)
req := requests.JoinWithCodeRequest{
Code: shareResp2.ShareCode.Code,
+4 -4
View File
@@ -86,22 +86,22 @@ func (h *StaticDataHandler) GetStaticData(c echo.Context) error {
}
// Cache miss - fetch all data from services
residenceTypes, err := h.residenceService.GetResidenceTypes()
residenceTypes, err := h.residenceService.GetResidenceTypes(c.Request().Context())
if err != nil {
return err
}
taskCategories, err := h.taskService.GetCategories()
taskCategories, err := h.taskService.GetCategories(c.Request().Context())
if err != nil {
return err
}
taskPriorities, err := h.taskService.GetPriorities()
taskPriorities, err := h.taskService.GetPriorities(c.Request().Context())
if err != nil {
return err
}
taskFrequencies, err := h.taskService.GetFrequencies()
taskFrequencies, err := h.taskService.GetFrequencies(c.Request().Context())
if err != nil {
return err
}
+20 -20
View File
@@ -83,7 +83,7 @@ func (h *TaskHandler) GetTask(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
response, err := h.taskService.GetTask(uint(taskID), user.ID)
response, err := h.taskService.GetTask(c.Request().Context(), uint(taskID), user.ID)
if err != nil {
return err
}
@@ -144,7 +144,7 @@ func (h *TaskHandler) CreateTask(c echo.Context) error {
return err
}
response, err := h.taskService.CreateTask(&req, user.ID, userNow)
response, err := h.taskService.CreateTask(c.Request().Context(), &req, user.ID, userNow)
if err != nil {
return err
}
@@ -169,7 +169,7 @@ func (h *TaskHandler) BulkCreateTasks(c echo.Context) error {
return err
}
response, err := h.taskService.BulkCreateTasks(&req, user.ID, userNow)
response, err := h.taskService.BulkCreateTasks(c.Request().Context(), &req, user.ID, userNow)
if err != nil {
return err
}
@@ -197,7 +197,7 @@ func (h *TaskHandler) UpdateTask(c echo.Context) error {
return err
}
response, err := h.taskService.UpdateTask(uint(taskID), user.ID, &req, userNow)
response, err := h.taskService.UpdateTask(c.Request().Context(), uint(taskID), user.ID, &req, userNow)
if err != nil {
return err
}
@@ -215,7 +215,7 @@ func (h *TaskHandler) DeleteTask(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
response, err := h.taskService.DeleteTask(uint(taskID), user.ID)
response, err := h.taskService.DeleteTask(c.Request().Context(), uint(taskID), user.ID)
if err != nil {
return err
}
@@ -235,7 +235,7 @@ func (h *TaskHandler) MarkInProgress(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
response, err := h.taskService.MarkInProgress(uint(taskID), user.ID, userNow)
response, err := h.taskService.MarkInProgress(c.Request().Context(), uint(taskID), user.ID, userNow)
if err != nil {
return err
}
@@ -255,7 +255,7 @@ func (h *TaskHandler) CancelTask(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
response, err := h.taskService.CancelTask(uint(taskID), user.ID, userNow)
response, err := h.taskService.CancelTask(c.Request().Context(), uint(taskID), user.ID, userNow)
if err != nil {
return err
}
@@ -275,7 +275,7 @@ func (h *TaskHandler) UncancelTask(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
response, err := h.taskService.UncancelTask(uint(taskID), user.ID, userNow)
response, err := h.taskService.UncancelTask(c.Request().Context(), uint(taskID), user.ID, userNow)
if err != nil {
return err
}
@@ -295,7 +295,7 @@ func (h *TaskHandler) ArchiveTask(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
response, err := h.taskService.ArchiveTask(uint(taskID), user.ID, userNow)
response, err := h.taskService.ArchiveTask(c.Request().Context(), uint(taskID), user.ID, userNow)
if err != nil {
return err
}
@@ -315,7 +315,7 @@ func (h *TaskHandler) UnarchiveTask(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
response, err := h.taskService.UnarchiveTask(uint(taskID), user.ID, userNow)
response, err := h.taskService.UnarchiveTask(c.Request().Context(), uint(taskID), user.ID, userNow)
if err != nil {
return err
}
@@ -334,7 +334,7 @@ func (h *TaskHandler) QuickComplete(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
err = h.taskService.QuickComplete(uint(taskID), user.ID)
err = h.taskService.QuickComplete(c.Request().Context(), uint(taskID), user.ID)
if err != nil {
return err
}
@@ -354,7 +354,7 @@ func (h *TaskHandler) GetTaskCompletions(c echo.Context) error {
return apperrors.BadRequest("error.invalid_task_id")
}
response, err := h.taskService.GetCompletionsByTask(uint(taskID), user.ID)
response, err := h.taskService.GetCompletionsByTask(c.Request().Context(), uint(taskID), user.ID)
if err != nil {
return err
}
@@ -367,7 +367,7 @@ func (h *TaskHandler) ListCompletions(c echo.Context) error {
if err != nil {
return err
}
response, err := h.taskService.ListCompletions(user.ID)
response, err := h.taskService.ListCompletions(c.Request().Context(), user.ID)
if err != nil {
return err
}
@@ -385,7 +385,7 @@ func (h *TaskHandler) GetCompletion(c echo.Context) error {
return apperrors.BadRequest("error.invalid_completion_id")
}
response, err := h.taskService.GetCompletion(uint(completionID), user.ID)
response, err := h.taskService.GetCompletion(c.Request().Context(), uint(completionID), user.ID)
if err != nil {
return err
}
@@ -465,7 +465,7 @@ func (h *TaskHandler) CreateCompletion(c echo.Context) error {
return err
}
response, err := h.taskService.CreateCompletion(&req, user.ID, userNow)
response, err := h.taskService.CreateCompletion(c.Request().Context(), &req, user.ID, userNow)
if err != nil {
return err
}
@@ -491,7 +491,7 @@ func (h *TaskHandler) UpdateCompletion(c echo.Context) error {
return err
}
response, err := h.taskService.UpdateCompletion(uint(completionID), user.ID, &req)
response, err := h.taskService.UpdateCompletion(c.Request().Context(), uint(completionID), user.ID, &req)
if err != nil {
return err
}
@@ -509,7 +509,7 @@ func (h *TaskHandler) DeleteCompletion(c echo.Context) error {
return apperrors.BadRequest("error.invalid_completion_id")
}
response, err := h.taskService.DeleteCompletion(uint(completionID), user.ID)
response, err := h.taskService.DeleteCompletion(c.Request().Context(), uint(completionID), user.ID)
if err != nil {
return err
}
@@ -520,7 +520,7 @@ func (h *TaskHandler) DeleteCompletion(c echo.Context) error {
// GetCategories handles GET /api/tasks/categories/
func (h *TaskHandler) GetCategories(c echo.Context) error {
categories, err := h.taskService.GetCategories()
categories, err := h.taskService.GetCategories(c.Request().Context())
if err != nil {
return err
}
@@ -529,7 +529,7 @@ func (h *TaskHandler) GetCategories(c echo.Context) error {
// GetPriorities handles GET /api/tasks/priorities/
func (h *TaskHandler) GetPriorities(c echo.Context) error {
priorities, err := h.taskService.GetPriorities()
priorities, err := h.taskService.GetPriorities(c.Request().Context())
if err != nil {
return err
}
@@ -538,7 +538,7 @@ func (h *TaskHandler) GetPriorities(c echo.Context) error {
// GetFrequencies handles GET /api/tasks/frequencies/
func (h *TaskHandler) GetFrequencies(c echo.Context) error {
frequencies, err := h.taskService.GetFrequencies()
frequencies, err := h.taskService.GetFrequencies(c.Request().Context())
if err != nil {
return err
}