Media Intelligence & Processing
The Ngwenya platform handles media with extreme care, ensuring high performance, zero redundancy, and native support for rich media across all Malets. The Media Service acts as the core ingest point, but delegates CPU-heavy workloads offline.
This document details the three core pillars of our "Media Intelligence" infrastructure: EXIF Extraction, SHA-256 Deduplication, and Asynchronous Video Transcoding.
1. SHA-256 Deduplication & Ref-Counted Storage
To prevent storage bloat and ensure fast uploads for Malet Owners, every incoming media file is hashed using SHA-256 before it touches Cloudflare R2 / S3.
The Upload Flow
When a file is uploaded, the Media Service:
- Calculates the SHA-256 hash of the raw buffer.
- Queries the database for an existing
MediaFilewhere:hashmatches.maletIdmatches (deduplication is intentionally isolated to a single Malet for privacy).statusisCOMPLETE.
Fast-Path Cloning
If an identical file exists, the service skips all processing and S3 uploads. Instead, it generates a new database record that shares the exact same key, url, and thumbnailUrl as the original, returning instantly.
Safe Deletion (Reference Counting)
Because multiple database records may point to the same physical S3 object, deletion must be careful.
When a MediaFile is deleted, the service uses countDocuments({ key: file.key }):
- If
count > 1: Only the database record is removed. The S3 object remains. - If
count === 1: The database record AND the physical S3 object are permanently deleted.
2. EXIF Metadata Extraction
Rich media often contains valuable metadata. For images, we use the exifr library to extract data before image optimization occurs (our optimization pipeline intentionally strips EXIF data to protect the privacy of Visitors / Buyers and Malet Owners).
// Example EXIF Output stored in MediaFile.metadata.exif
{
"Make": "Apple",
"Model": "iPhone 15 Pro",
"DateTimeOriginal": "2026-04-05T12:00:00Z",
"latitude": 37.7749,
"longitude": -122.4194
}
This extracted metadata is attached to the MediaFile graph, allowing future features (like map-based discovery in the Lobby) to utilize the data without compromising the raw image file's privacy footprint.
3. Asynchronous Video Transcoding
Video processing (generating HLS streams from MP4/MOV) is incredibly CPU-intensive. To protect the core GraphQL Gateway and Media Service from latency spikes, video processing is fully decoupled.
Architecture
sequenceDiagram
participant Client as Frontend
participant Media as Media Service (Port 30012)
participant TCP as TCP Event Bus
participant Video as Video Microservice (Port 30021)
participant S3 as R2 / S3 Storage
Client->>Media: Upload raw video via REST
Media->>Media: Hash buffer, save to DB (status: PROCESSING)
Media->>S3: Upload raw chunk to R2
Media--)TCP: emit('transcode_video_hls', { id, key })
Media->>Client: Return 201 (Client shows spinner)
Note over Video: Asynchronous FFmpeg Worker
TCP-->>Video: Receive transcode job
Video->>S3: Download raw video
Video->>Video: FFmpeg -> HLS (.m3u8, .ts), Poster (.jpg)
Video->>S3: Upload HLS playlist & Poster to R2
Video->>Media: Update DB (status: COMPLETE, urls added)
Note over Client: Next poll / WebSocket shows Video ready
The `apps/video` Microservice
- Transport: NestJS TCP (Port 30021) โ no HTTP overhead.
- Engine: Wraps
fluent-ffmpegvia Alpine Linuxffmpegpackage. - Output: Generates Apple HTTP Live Streaming (HLS) standard formats (VOD playlist, 6-second
.tssegments) for adaptive streaming, plus a 1-second mark.jpgposter frame.
Media Client Adapter Strategies
The Media service interacts with the Video service via a Strategy pattern (apps/media/src/video-transcode/):
RemoteStrategy: Emits the TCP event toapps/video.NoOpStrategy: Used for local development if the video service is disabled. Skips transcoding entirely to allow local media work to continue uninterrupted.
Future Scale: The Rust Rewrite Path
While the NestJS worker processes videos flawlessly, Node.js memory overhead limits vertical scaling capacity.
Because the system is heavily decoupled via a language-agnostic TCP contract, the apps/video service is documented and primed for a future drop-in replacement using a lightweight Rust binary (ffmpeg-sys + tokio), guaranteeing massive density improvements as the platform scales.
Related
- Media Infrastructure โ Multi-size thumbnails, blur placeholders, Cloudflare R2 storage, and presigned upload flow
- Media Analytics API โ Upload volume, storage usage, type distribution, and processing health analytics