What This Template Is For
Image handling looks simple on the surface. Users upload a photo, the system stores it, the frontend displays it. But between upload and display sit format detection, virus scanning, dimension validation, EXIF stripping, format conversion, responsive variant generation, CDN distribution, and possibly AI-powered moderation and tagging. Each step introduces edge cases that, if unspecified, produce bugs that are painful to fix after launch.
This template helps PMs define image processing requirements with the right level of detail. It is designed for any feature that accepts, transforms, stores, or delivers images: profile photos, product galleries, document uploads, marketing asset management, or user-generated content. The goal is a spec that engineering can implement without back-and-forth questions about supported formats, size limits, or failure behavior.
For the broader context on writing technical specifications that engineering teams trust, see the Technical PM Handbook. If your feature also handles video or audio, spec those media types in separate documents to keep each spec focused.
How to Use This Template
- Define supported formats and limits before anything else. The first question engineering will ask is "what formats and what size limits?" Have answers ready. If you are unsure about format support, check what your target users typically upload (screenshot tools produce PNG, cameras produce JPEG/HEIC, designers send WebP or SVG).
- Specify every output variant. If the product needs thumbnails, hero images, OG cards, and mobile-optimized versions, list each variant with exact dimensions and quality settings. Missing variants mid-sprint cause scope creep.
- Address moderation early. If users upload images, some will upload inappropriate content. Define your moderation strategy (AI pre-screening, manual review queue, or both) before the feature ships, not after the first abuse report.
- Plan for CDN and caching. Image delivery performance directly impacts page speed and SEO. Specify cache headers, CDN requirements, and cache invalidation strategy.
- Score the feature's priority first. Use the RICE Calculator to validate investment before writing the full spec.
Image Processing Feature Specification
Feature Overview
| Field | Details |
|---|---|
| Feature Name | [Image feature name] |
| PRD Link | [Link to parent PRD] |
| Design Link | [Link to Figma file] |
| Owner (PM) | [Name] |
| Owner (Engineering) | [Name] |
| Target Release | [Sprint or date] |
| Priority | [P0 / P1 / P2] |
| Status | [Draft / In Review / Approved / In Development] |
One-line summary: [What this image feature does in plain language.]
Context: [Why this feature exists. User research data, current pain points, business impact.]
Upload Requirements
Supported input formats:
| Format | Extension | MIME Type | Max File Size | Notes |
|---|---|---|---|---|
| JPEG | .jpg, .jpeg | image/jpeg | [10 MB] | Most common photo format |
| PNG | .png | image/png | [15 MB] | Screenshots, graphics with transparency |
| WebP | .webp | image/webp | [10 MB] | Modern format, smaller file sizes |
| GIF | .gif | image/gif | [5 MB] | Animated images, limit frame count |
| HEIC/HEIF | .heic, .heif | image/heic | [15 MB] | iPhone default format |
| SVG | .svg | image/svg+xml | [2 MB] | Vector graphics (sanitize for XSS) |
| AVIF | .avif | image/avif | [10 MB] | Next-gen format, high compression |
Upload constraints:
| Constraint | Value | Error Behavior |
|---|---|---|
| Max file size | [10 MB per file] | Show inline error before upload starts |
| Max dimensions | [8000 x 8000 px] | Reject with "Image too large" message |
| Min dimensions | [100 x 100 px] | Reject with "Image too small" message |
| Max batch upload | [20 images] | Disable add button, show "Maximum reached" |
| Max total upload size | [100 MB per batch] | Show remaining capacity in upload UI |
Upload UX:
- ☐ Drag-and-drop zone
- ☐ File picker button (click to browse)
- ☐ Paste from clipboard (Ctrl+V / Cmd+V)
- ☐ Upload progress bar per file
- ☐ Cancel individual upload mid-progress
- ☐ Preview thumbnail before upload completes
- ☐ Batch upload with individual status indicators
Processing Pipeline
Define the transformations applied to uploaded images.
Step 1: Validation
- ☐ Verify file header matches declared MIME type (prevent extension spoofing)
- ☐ Check dimensions against min/max constraints
- ☐ Check file size against limits
- ☐ Scan for malware (ClamAV or equivalent)
- ☐ Validate SVG for embedded scripts (XSS prevention)
Step 2: Metadata Extraction and Stripping
| Metadata | Action | Reason |
|---|---|---|
| EXIF (camera, GPS, device) | Strip on upload | Privacy protection |
| IPTC (copyright, caption) | Preserve optionally | Attribution tracking |
| Color profile (ICC) | Convert to sRGB | Consistent display |
| Orientation (EXIF rotation) | Apply rotation, strip tag | Correct display orientation |
| Creation date | Extract and store in DB | Sort by capture date |
Step 3: Format Conversion and Optimization
| Output Format | When Used | Quality | Notes |
|---|---|---|---|
| WebP | Default serving format | [80%] | 25-35% smaller than JPEG at equivalent quality |
| AVIF | Modern browsers | [75%] | 50% smaller than JPEG, slower encoding |
| JPEG | Fallback for older browsers | [85%] | Universal support |
| PNG | Images with transparency | [Lossless] | Used only when transparency is needed |
Step 4: Variant Generation
Define the image sizes your application needs. Each variant is generated once on upload and served from CDN.
| Variant Name | Max Width | Max Height | Fit Mode | Use Case |
|---|---|---|---|---|
thumbnail | 150 px | 150 px | Cover (crop to square) | Grid view, avatars |
small | 400 px | 300 px | Contain (preserve aspect) | Card previews |
medium | 800 px | 600 px | Contain | Article inline images |
large | 1200 px | 900 px | Contain | Hero images |
og | 1200 px | 630 px | Cover (crop to ratio) | Open Graph / social sharing |
original | [Max constraint] | [Max constraint] | Contain | Download, full-resolution view |
Storage and Delivery
| Requirement | Details |
|---|---|
| Storage backend | [S3 / GCS / Azure Blob / Cloudflare R2] |
| Path pattern | [/images/{user_id}/{year}/{month}/{uuid}.{ext}] |
| CDN | [CloudFront / Cloudflare / Fastly] |
| Cache TTL | [1 year for immutable URLs with content hash] |
| Cache invalidation | [New URL on re-upload, not purge] |
| Signed URLs | [Required for private images / Not needed for public] |
| Hot-linking protection | [Referer check / Signed URLs / None] |
Image Editor (Optional)
If your feature includes in-browser image editing, define the capabilities.
- ☐ Crop (free, fixed ratios: 1:1, 4:3, 16:9)
- ☐ Rotate (90 degree increments, free rotation)
- ☐ Flip (horizontal, vertical)
- ☐ Brightness and contrast adjustment
- ☐ Filters (predefined set, no custom)
- ☐ Text overlay
- ☐ Drawing / annotation
- ☐ Undo / redo (10-step minimum)
AI-Powered Features (Optional)
| Feature | Model/Service | Accuracy Target | Fallback |
|---|---|---|---|
| Auto-tagging | [AWS Rekognition / Google Vision / Custom] | [>90% precision] | [Manual tagging] |
| Alt text generation | [GPT-4V / Claude / Custom] | [Review queue for generated text] | [Manual alt text input] |
| Content moderation | [AWS Rekognition / Google SafeSearch / Custom] | [<1% false negatives] | [Manual review queue] |
| Face detection | [Service] | [Detect, not identify] | [Manual crop] |
| OCR / text extraction | [Service] | [>95% accuracy] | [Manual transcription] |
| Background removal | [Service] | [Clean edges on simple backgrounds] | [Manual editing] |
Accessibility Requirements
Images affect accessibility directly. Specify requirements for assistive technology.
- ☐ Alt text field required for all uploaded images (unless marked decorative)
- ☐ Alt text max length: 125 characters
- ☐ Decorative image toggle (sets
alt=""in HTML) - ☐ Long description field for complex images (charts, diagrams)
- ☐ Color contrast check for text overlay on images
- ☐ Focus indicator on interactive image elements
Analytics Events
| Event Name | Trigger | Parameters | Purpose |
|---|---|---|---|
image_uploaded | Upload completes | format, file_size, dimensions, source | Track upload patterns |
image_upload_failed | Upload fails | error_type, format, file_size | Monitor failure rates |
image_processed | Processing completes | processing_time, variants_generated | Monitor pipeline performance |
image_moderation_flagged | AI flags content | confidence, category, action_taken | Track moderation accuracy |
image_viewed | Image loaded in browser | variant, load_time, cache_hit | Monitor delivery performance |
Edge Cases
| # | Edge Case | Expected Behavior |
|---|---|---|
| 1 | User uploads HEIC from iPhone (not supported by all browsers) | Server converts to WebP/JPEG. Original HEIC stored for download. |
| 2 | Animated GIF exceeds frame limit | Reject with message: "Animated images limited to [N] frames." |
| 3 | SVG contains embedded JavaScript | Sanitizer strips all script elements. Log the attempt. |
| 4 | Image EXIF says landscape but displays portrait | Apply EXIF orientation correction during processing. |
| 5 | User uploads same image twice | Detect duplicate via content hash. Reuse existing processed variants. |
| 6 | Processing pipeline fails mid-variant generation | Retry 3x with exponential backoff. If all retries fail, mark as processing_failed, notify user. |
| 7 | Very large image (50+ megapixels) | Downsample to max constraint before variant generation to prevent memory exhaustion. |
Error States
| Error Condition | User-Facing Message | Technical Response | Recovery Action |
|---|---|---|---|
| File too large | "This image exceeds the [X] MB limit. Try compressing it first." | 413 | Show file size and limit |
| Unsupported format | "This file type is not supported. Upload a JPG, PNG, or WebP." | 415 | List supported formats |
| Processing failed | "We could not process this image. Please try uploading again." | 500 | Retry button |
| Moderation rejected | "This image does not meet our content guidelines." | 403 | Link to content policy |
| Storage quota exceeded | "You have reached your image storage limit." | 507 | Link to upgrade or delete existing images |
Performance Requirements
| Metric | Target | Measurement |
|---|---|---|
| Upload speed | [Progress visible within 500ms of drop/select] | Client-side |
| Processing time | [All variants generated within 10s for <5MB images] | Server-side |
| CDN delivery | [<100ms TTFB for cached images] | Synthetic monitoring |
| Page load impact | [<200KB total image weight per page (above the fold)] | Lighthouse |
Dependencies
| Dependency | Team / Service | Status | Risk |
|---|---|---|---|
| [Image processing library (Sharp/ImageMagick)] | [Backend] | [Status] | [Risk level] |
| [Object storage (S3/GCS)] | [Infrastructure] | [Status] | [Risk level] |
| [CDN configuration] | [DevOps] | [Status] | [Risk level] |
| [AI moderation service] | [ML/AI team] | [Status] | [Risk level] |
Out of Scope
- [Features explicitly excluded]
- [Future iterations]
- [Adjacent features in separate specs]
Filled Example: User Profile Photo Upload
Feature Overview
One-line summary: Users can upload, crop, and set a profile photo that displays across the application.
Context: 62% of user profiles have no photo. Internal research shows profiles with photos get 3x more engagement in team collaboration features. Current upload flow is a raw file picker with no cropping, producing poorly framed photos.
Upload Requirements
Supported formats: JPEG, PNG, WebP, HEIC. Max file size: 5 MB. Min dimensions: 200x200px.
Processing Pipeline
- Validate format, size, dimensions
- Strip EXIF data (privacy)
- Apply user crop selection (1:1 ratio enforced)
- Generate variants:
avatar_sm(48px),avatar_md(96px),avatar_lg(200px),avatar_xl(400px) - Convert to WebP (primary) + JPEG (fallback)
- Upload variants to S3, serve via CloudFront
Out of Scope
- Animated avatar support (GIF/APNG)
- Avatar customization (filters, frames, stickers)
- AI-generated avatar option (future V2)
