refactor(uploads): drop legacy multipart code paths
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

The presigned-URL upload flow (POST /api/uploads/presign + direct B2 POST
+ upload_ids[] in entity creation) is now the only image upload path. The
legacy multipart routes and DTO fields used by older clients are removed:

Removed:
  - POST /api/uploads/image/        (legacy multipart upload → URL)
  - POST /api/uploads/document/     (legacy multipart upload → URL)
  - POST /api/uploads/completion/   (legacy multipart upload → URL)
  - Multipart branch in POST /api/task-completions/ (now JSON-only)
  - CreateTaskCompletionRequest.ImageURLs DTO field
  - UpdateTaskCompletionRequest.ImageURLs DTO field
  - CreateDocumentRequest.ImageURLs DTO field
  - Service-layer ImageURLs loops in task_service.CreateCompletion,
    task_service.UpdateCompletion, document_service.CreateDocument
  - Tests exercising the removed paths
  - Now-unused imports (strings/time/decimal) in task_handler.go

Kept:
  - DELETE /api/uploads/  (orphan-cleanup endpoint, still useful)
  - POST /api/uploads/presign/  (the new path)
  - POST /api/documents/:id/images/  (uses storage_service.Upload directly,
    same multipart pattern but separate code path; deferred for now)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-05-01 15:19:21 -07:00
parent 29c9014a33
commit b7f83293b8
9 changed files with 43 additions and 261 deletions
+7 -27
View File
@@ -727,23 +727,8 @@ func (s *TaskService) CreateCompletion(ctx context.Context, req *requests.Create
if err := s.taskRepo.WithContext(ctx).UpdateTx(tx, task); err != nil {
return err
}
// B-07: Create images inside the same transaction as completion.
// Two sources contribute, both produce TaskCompletionImage rows:
// 1. Legacy multipart path — client uploaded via the API and got
// back URLs in req.ImageURLs.
// 2. New presigned path — client uploaded direct to B2 and we
// claimed the pending_uploads rows above.
for _, imageURL := range req.ImageURLs {
if imageURL != "" {
img := &models.TaskCompletionImage{
CompletionID: completion.ID,
ImageURL: imageURL,
}
if err := tx.Create(img).Error; err != nil {
return fmt.Errorf("failed to create completion image: %w", err)
}
}
}
// Create completion image rows from the claimed pending_uploads.
// Bytes already live in B2; we just record the FK + URL.
for i := range claimedUploads {
pu := claimedUploads[i]
img := &models.TaskCompletionImage{
@@ -1131,16 +1116,11 @@ func (s *TaskService) UpdateCompletion(ctx context.Context, completionID, userID
return nil, apperrors.Internal(err)
}
// Add any new images
for _, imageURL := range req.ImageURLs {
image := &models.TaskCompletionImage{
CompletionID: completion.ID,
ImageURL: imageURL,
}
if err := s.taskRepo.WithContext(ctx).CreateCompletionImage(image); err != nil {
log.Error().Err(err).Uint("completion_id", completion.ID).Msg("Failed to create completion image during update")
}
}
// Image-add on update is unsupported in the new flow — clients should
// instead delete and recreate the completion if image attachments need
// to change after the fact. The presigned-URL path requires a single
// "create with attachments" handshake and there's no equivalent attach-
// to-existing pathway today. Add one here when a UI feature requires it.
// Reload to get full associations
updated, err := s.taskRepo.WithContext(ctx).FindCompletionByID(completionID)