Skip to content

[FRONTEND] Replace screenshots on Cloudflare when updating design #372

@JosAhl

Description

@JosAhl

What needs to be done?

Currently, when a user updates an existing design and saves, we upload NEW screenshots to Cloudflare R2 but don't delete the old ones. This means each design update creates 2 additional files (full-size + thumbnail), leading to orphaned screenshots accumulating in storage.

Example scenario:

  • User creates design ID 15 → design-15-1234567-full.jpg, design-15-1234567-thumb.jpg (2 files)
  • User edits and saves design 15 → design-15-1234568-full.jpg, design-15-1234568-thumb.jpg (2 NEW files)
  • User edits and saves again → design-15-1234569-full.jpg, design-15-1234569-thumb.jpg (2 MORE files)
  • Result: 6 files in storage, but only the last 2 are actually used

Goal: Automatically delete old screenshots when uploading new ones during design updates, so each design only has 2 files in storage at any time.

Priority: LOW - Cloudflare R2 free tier is 10 GB/month. Current usage is minimal (~1.75 MB), but this prevents long-term storage bloat. At current scale (~500KB per design), we can store ~20,000 designs before hitting 10GB.

Which page/component?

Files involved:

  • src/features/designs/useDesign.ts - saveDesign() function
  • src/lib/uploadScreenshots.ts - Upload logic
  • src/lib/downloadScreenshot.ts - Delete helper function (already exists but unused)
  • Backend: DesignController.cs, R2Service.cs

Tasks

Backend

  • Add DeleteFile() method to IR2Service.cs and R2Service.cs
  • Add DELETE /api/Design/screenshots/{fileName} endpoint to DesignController.cs

Frontend

  • In useDesign.ts saveDesign(), fetch current design's screenshot URLs BEFORE uploading new ones
  • After successfully uploading new screenshots and updating database, call deleteScreenshotFromR2() for old URLs
  • Ensure deletion failures don't block the save operation (use try-catch, best-effort cleanup)
  • Test edge cases: no existing screenshots, upload fails, delete fails, multiple rapid saves

Key principle: Delete happens AFTER successful upload. If upload fails, old screenshots remain.

Notes

Current implementation status:

  • New screenshots upload successfully
  • Database updates with new URLs
  • Backend delete endpoint exists (DELETE /api/Design/screenshots/{fileName})
  • Delete helper function exists (deleteScreenshotFromR2() in lib/downloadScreenshot.ts)
  • Delete logic NOT called in useDesign.ts - old screenshots accumulate

Solution location:
Update src/features/designs/useDesign.ts saveDesign() function to:

  1. Fetch current design before upload (to get old URLs)
  2. Upload new screenshots
  3. Update database
  4. Delete old screenshots

Error handling: Screenshot deletion should NEVER block a save - it's cleanup, not critical path.

Alternative approach: Batch cleanup job (weekly) to find orphaned files (files in R2 not in database).

Related endpoints:

  • GET /api/Design/{id} - Fetch current design
  • POST /api/Design/screenshots/upload-urls - Get presigned URLs
  • PUT /api/Design/{id} - Update design
  • DELETE /api/Design/screenshots/{fileName} - Delete old screenshot

Estimated effort: 1-2 hours
Risk: Low. Deletion failure doesn't break saves.
Testing: Verify in Cloudflare R2 dashboard that old files are actually deleted after updates.

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions