KwadMarket Docs
Product Roadmap

Media

Image compression, video support and optimization pipeline

Current state

Images upload directly to S3 via the backend — no compression, no resizing, no format optimization, no video support. (Orphaned-object cleanup and thumbnails are also launch-checklist items.)

Image optimization

Client-side compression (before upload) with browser-image-compression: resize to max 1920px width, ~80% quality, WebP — target <500KB per image (down from 3–10MB originals).

Server-side processing (after upload, V2) with Sharp: thumbnails (200×200, 400×400), WebP + AVIF variants, strip EXIF (except for verification — keep GPS/date for scam checks).

CDN: serve via CloudFront or Cloudflare; consider Cloudflare Images or imgproxy for on-the-fly resize.

Video support

Constraints: max 30 seconds (product demo clips), max 50MB after compression; accept MP4/WebM/MOV; output MP4 (H.264) for universal playback.

Client-side compression: FFmpeg.wasm (recommended over MediaRecorder — full codec control; ~3MB WASM download on first use; show a progress bar on low-end devices):

-c:v libx264 -crf 28 -preset fast
-vf scale='min(1280,iw)':'-2'
-c:a aac -b:a 128k
-movflags +faststart
-t 30

Upload flow:

User selects a video; client validates duration ≤ 30s, size ≤ 100MB pre-compression.
FFmpeg.wasm compresses → MP4 <50MB, with a progress bar.
Upload to S3 (multipart for large files).
Backend generates a thumbnail frame; video URL + thumbnail stored with the deal media.

Playback: native <video> with lazy loading, poster thumbnail, no autoplay, progressive download (HLS/DASH is overkill for 30s clips).

Data model

Short term, the deal images JSON array can hold both with a prefix convention (video:https://s3.../clip.mp4). Cleaner V2 model:

model DealMedia {
  id        Int       @id @default(autoincrement())
  dealId    Int
  deal      Deal      @relation(fields: [dealId], references: [id])
  type      MediaType // IMAGE or VIDEO
  url       String
  thumbnail String?   // video thumbnail
  order     Int       @default(0)
}

enum MediaType {
  IMAGE
  VIDEO
}

Tasks

Images (V1): browser-image-compression; compression step + progress in the ImageUpload shared component.

Video (V1): @ffmpeg/ffmpeg; compression utility; upload component with validation; multipart S3 upload; server-side thumbnail (ffmpeg); player component on the deal page; deal form accepts video.

Optimization (V2): Sharp thumbnails; WebP/AVIF variants; CDN; lazy loading in deal lists.

On this page