Media Library
At a glance
A per-site media library that handles images, documents and video with automatic optimization, AVIF/WebP/JPEG transcoding, hash-based deduplication, gallery composition and edge CDN delivery. A storage quota per site with real-time usage and an orphan-cleanup tool keeps costs predictable and lets the platform offer free tiers without runaway media bills, while malware scanning and tenant-isolated buckets keep uploads safe and scoped to the right federation.
How it works
Every CmsSite has its own media bucket scoped by tenant_id and site_id, isolated at the storage layer so cross-tenant access is impossible. Uploads go through a chunked multipart endpoint that computes a content hash for deduplication, runs malware scanning, and writes the original to immutable storage. An optimization pipeline triggers asynchronously: images get resized into a fixed ladder (256, 512, 1024, 2048 px wide), encoded as AVIF, WebP and JPEG, and a Lighthouse-friendly LCP variant is pre-generated.
The CMS renderer's PetanqueImage component selects the best format via `<picture>` source negotiation and serves through the platform CDN with long-cache immutable URLs. Documents (PDF, Word, Excel) are stored as-is, scanned for viruses, and served with Content-Disposition headers so browsers offer a download. Video uploads are transcoded to HLS in three bitrates for adaptive streaming; embedded YouTube and Vimeo links are stored as canonical IDs and rendered via privacy-aware iframes.
The gallery composer lets editors drag images into a grid, set alt-text per image, choose a layout (mosaic, justified, masonry) and a lightbox behavior. All gallery thumbnails reuse the optimization pipeline's smaller variants so a 30-image gallery loads under a megabyte. Storage quota is tracked per site in real time; the dashboard shows current usage versus the tier's quota, surfaces top consumers, and offers a one-click cleanup of orphaned media that no published page references.
When a site exceeds its quota, new uploads are rejected with a clear message instead of failing silently.
Key capabilities
- Per-site, tenant-scoped media bucket with hash-based deduplication
- Automatic image resize, compression and AVIF/WebP/JPEG transcoding
- Document upload (PDF, Word, Excel) with virus scanning
- Video transcoding to HLS plus YouTube and Vimeo embed support
- Gallery composer with mosaic, justified and masonry layouts and lightbox
- Edge CDN delivery with long-cache immutable URLs
- Per-site storage quota with usage dashboard and orphan cleanup
In practice
Henrik, marketing volunteer at IFK Petanque, returns from the regional final with 240 photos. He opens the media library, drags the entire folder onto the upload zone, and the chunked uploader streams them in the background while showing per-file progress. The optimization pipeline transcodes everything to AVIF and WebP within minutes; he sees storage usage rise from 1.2 GB to 1.6 GB out of his club's 5 GB quota.
He creates a new gallery, drags 60 of the best shots into a justified grid, writes alt-text in Swedish for accessibility, and embeds the gallery on the news article from F18.04. The published article loads in under two seconds on mobile because the renderer serves AVIF thumbnails from the CDN.
Features in this subsystem
8| ID | Status | Features |
|---|---|---|
| F18.06.01 | Shipped | Image upload and management per site — PL-F1806a ✅ PL-F1806a |
| F18.06.02 | Shipped | Automatic image optimization (resize, compress, WebP) — PL-F1806a ✅ PL-F1806a |
| F18.06.03 | Shipped | Document upload (PDF, Word) — PL-F1806a ✅ PL-F1806a |
| F18.06.04 | Shipped | Video embedding (YouTube, Vimeo, direct upload) — PL-F1806a ✅ PL-F1806a |
| F18.06.05 | Shipped | Photo gallery creation ✅ PL-F1806b |
| F18.06.06 | Shipped | CDN delivery for all media ✅ PL-F1806b |
| F18.06.07 | Shipped | Storage quota per site ✅ PL-F1806b |
| F18.06.08 | Shipped | Public + lösenordsskyddad media via blob storage (Azure) — PL-T234 ✅ PL-T234 |