trackslash
TRACK-3 P1

Make object-store deletions retryable and reconcilable

0
All issues

Description

Problem

Deletion commits the metadata soft-delete first, then deletes backend bytes (internal/server/storage_objects.go:223-230; the shared attachment path does the same in internal/server/description_attachments.go:36-43). Profile/project image replacement silently discards backend-delete failures (internal/server/profile_images.go:265-273).

If S3/GCS/local deletion fails, the API returns 500 after the database change has committed. The object is then filtered from reads, so retrying the same route returns 404 and the backend bytes have no durable retry path. TestHTTPStorageObjectDeleteBackendFailure only asserts the initial 500 and does not verify retryability or final byte removal.

Impact

Transient backend failures create permanent, inaccessible objects, causing storage cost, retention/privacy problems, and misleading client semantics.

Acceptance criteria

  • Persist pending backend deletion work transactionally in Postgres (or retain queryable deletion state) and process it idempotently from the Go binary.
  • Retry transient failures with bounded backoff and expose/log terminal failures.
  • Cover raw objects, issue/project/sprint/context attachments, and profile/project image replacement/removal.
  • Make the HTTP response accurately describe the committed logical deletion.
  • Add a failure-then-success test proving bytes are eventually removed and no orphan remains.

Sub-issues

0

Linked issues

0

GitHub

0

No branches or pull requests linked.

Comments

0
No comments.