v0.1 ash_storage · a polymorphic attachment layer for Ash

Storage that knows
where things live, what they are,
and who they belong to.

One blob table. Many services. Pluggable analyzers. This demo wires a feed against S3 and local Disk so you can watch the pipeline run.

Multi-service routing
has_one_attached/has_many_attached on Post route photos & videos to S3 and documents to Disk — service is per-attachment, not per-app. Try in the feed →
Analyzers
Post-upload pipeline runs FileInfo (MIME sniffing), ImageDimensions (via :oban), Exif (writes taken_at / camera / gps_* back to the host), and DominantColor on avatars. Status pills show pending → complete / error / skipped. Try on profile →
Variants
Derived blobs in three modes: eager (avatar small/medium/large), :oban (cover_image feed_size), on-demand (photo thumbnails, PDF previews, video posters). Custom variants too — see OutlinedSticker. Try variants →
Mirroring service
Cover images use AshStorage.Service.Mirror — writes fan out to S3 + a Disk mirror, reads fall through on :not_found. Upload a cover →
Polymorphic attachments
A single PolyAttachment table points at any host — Post, Comment, or User — via Tag.has_many_attached :icons. Browse in AshAdmin →
Orphan sweeper + admin
Bytes per service, counts per content-type, blob inspector with full analyzer metadata, and a one-click purge for blob rows with no attachment in any host table (kept tidy by an AshOban recurring schedule). Open storage admin →
3 attachment surfaces
posts · users · documents
2 services
S3 · Disk
4 analyzers
FileInfo · Exif · Variants · DominantColor
Shared volume 43.4 MB / 1.00 GB · 4.2%
66 objects · updated 03:17 UTC