# Digest 9: services (remaining), task package, testutil, validator, worker, pkg ### services/storage_service.go (184 lines) - Line 75: UUID truncated to 8 chars — increased collision risk - **SECURITY**: Line 137-138: filepath.Abs errors ignored — path traversal check could be bypassed ### services/subscription_service.go (659 lines) - **PERFORMANCE**: Line 186-204: N+1 queries in getUserUsage — 3 queries per residence - **SECURITY/BUSINESS**: Line 371: Apple validation failure grants 1-month free Pro - **SECURITY/BUSINESS**: Line 381: Apple validation not configured grants 1-year free Pro - **SECURITY/BUSINESS**: Line 429, 449: Same for Google — errors/misconfiguration grant free Pro - Line 7: Uses stdlib "log" instead of zerolog ### services/task_button_types.go (85 lines) - Clean, uses predicates correctly ### services/task_service.go (1092 lines) - **DATA INTEGRITY**: Line 601: If task update fails after completion creation, error only logged not returned — stale NextDueDate/InProgress - Line 735: Goroutine in QuickComplete (service method) — inconsistent with synchronous CreateCompletion - Line 773: Unbounded goroutine creation per user for notifications - Line 790: Fail-open email notification on error (intentional but risky) - **SECURITY**: Line 857-862: resolveImageFilePath has NO path traversal validation ### services/task_template_service.go (70 lines) - Errors returned raw (not wrapped with apperrors) ### services/user_service.go (88 lines) - Returns nil instead of empty slice (JSON null vs []) ### task/categorization/chain.go (359 lines) - Clean chain-of-responsibility ### task/predicates/predicates.go (217 lines) - Line 210: IsRecurring requires Frequency preloaded — returns false without it ### task/scopes/scopes.go (270 lines) - Line 118: ScopeOverdue doesn't exclude InProgress — differs from categorization chain ### task/task.go (261 lines) - Clean facade re-exports ### testutil/testutil.go (359 lines) - Line 86: json.Marshal error ignored in MakeRequest - Line 92: http.NewRequest error ignored ### validator/validator.go (103 lines) - Clean ### worker/jobs/email_jobs.go (118 lines) - Clean ### worker/jobs/handler.go (810 lines) - Lines 95-106, 193-204: Direct DB access bypasses repository layer - Line 627-635: Raw SQL with fmt.Sprintf (not currently user-supplied but fragile) - Line 154, 251: O(N*M) lookup instead of map ### worker/scheduler.go (240 lines) - Line 200-212: Cron schedules at fixed UTC times may conflict with smart reminder system — potential duplicate notifications ### pkg/utils/logger.go (132 lines) - Panic recovery bypasses apperrors.HTTPErrorHandler