Files
shop-server/.opencode/plans/2026-05-15-image-processing-refactor-design.md
T
2026-05-19 11:25:23 +05:00

3.8 KiB

Spec: Image Processing Refactor

Context

Current image handling uses on-demand resize via /uploads-resized/ route. Admin uploads save originals as-is (jpg/png/webp), and resize happens on first request. User uploads (reviews, 2MB limit) also use on-demand resize.

Goals

  1. User images (reviews, ≤2MB): Improve size error messages to be user-friendly
  2. Admin images (products, ≤20MB): Eager processing at upload time
    • Generate all resize widths (320, 640, 1024, 1600) in AVIF + WebP
    • Convert original to WebP (delete source file)
    • Full-screen viewer shows original in WebP (no width limit)
    • Thumbnails use resized versions from cache

Architecture

Server Changes

1. server/src/lib/upload-images.js

  • Add eager parameter to persistMultipartImages
  • When eager: true, after saving each file:
    1. Call generateAllSizes(uuid, subdir, fullPath) — generates all sizes from original
    2. Call convertOriginalToWebp(uuid, subdir) — converts original to WebP, deletes source
    3. Update URL to use .webp extension (replace original extension)

2. server/src/lib/image-resize.js

  • Add generateAllSizes(uuid, subdir, originalPath):
    • For each width in [320, 640, 1024, 1600]:
      • Generate AVIF and WebP in .cache/<subdir>/
    • Uses original file path (before conversion to WebP)
  • Add convertOriginalToWebp(uuid, subdir):
    • Find original file (jpg/png)
    • Convert to WebP (quality 80) at same location with .webp extension
    • Delete original jpg/png file
    • Return new .webp path

3. server/src/routes/api/admin-products.js

  • Pass eager: true to persistMultipartImages

4. server/src/routes/api/public-reviews.js

  • Improve error message for file too large (413)

Client Changes

1. client/src/entities/product/api/product-api.ts

  • Add pre-upload size check for review images
  • Clear error message: "Файл «» слишком большой (максимум 2 МБ)"

2. client/src/shared/ui/OptimizedImage.tsx

  • Update buildSrcSet to use cached AVIF/WebP directly
  • Full-screen viewer: use original .webp URL (no ?w=)
  • Remove fallback to original format for upload URLs

3. client/src/features/product-review/ui/ReviewDialog.tsx

  • Show user-friendly error message for oversized files

Data Flow

Admin Upload (Eager)

  1. Client sends FormData to POST /api/admin/uploads
  2. Server saves original (e.g., uuid.jpg)
  3. Server generates all sizes in .cache/ from original
  4. Server converts original to WebP (uuid.webp), deletes uuid.jpg
  5. Returns URLs with .webp extension (e.g., /uploads/<uuid>.webp)
  6. Client displays using OptimizedImage with srcset from cache

User Upload (Reviews)

  1. Client validates file size ≤2MB before upload
  2. Server validates and saves original
  3. On-demand resize still works (existing flow)
  4. Clear error messages at both client and server

Error Handling

User Upload Size Error

  • Client: Pre-upload check with message "Файл «» слишком большой (максимум 2 МБ)"
  • Server: 413 with "Файл слишком большой (максимум 2 МБ)"

Admin Upload Processing Error

  • If sharp fails: return 500 with "Ошибка обработки изображения"
  • If file not found after save: return 500 with "Внутренняя ошибка сервера"

Testing

Server Tests

  • Test generateAllSizes creates all width+format combinations
  • Test convertOriginalToWebp converts and deletes original
  • Test persistMultipartImages with eager: true
  • Test error messages for oversized files

Client Tests

  • Test pre-upload size validation for reviews
  • Test OptimizedImage srcset generation for WebP originals
  • Test error message display in ReviewDialog