Ledger Attachments: Multiple File Upload with Per-File Queues

Part of the Sanchayam series. What The ledger is Sanchayam’s expense and income tracker. Every entry can carry supporting documents stored in S3: receipts, invoices, settlement reports. The first version of the attachment panel accepted one file per trip through the file picker. Adding five receipts to one entry meant opening the picker five times and waiting for each upload to finish before starting the next. The panel now accepts a whole batch in one pick. This post covers how that works: per-file queues, sequential uploads, up-front validation, and retryable failures. ...

June 14, 2026 · 4 min · 847 words · Sagar Nayak

Global Cross-Bucket Search

Part of the MediaBridge series. Per-Bucket Search vs Global Search The single-bucket search described in the previous post runs one WebSocket and searches one bucket from a given prefix. Global search is different: it searches every bucket the user has access to simultaneously, merging results from all of them into a single view. A user assigned to 10 buckets gets 10 WebSocket connections opened in parallel. Results from all 10 stream in at the same time. Each bucket runs its own DFS traversal independently. ...

March 9, 2026 · 4 min · 783 words · Sagar Nayak

JWT Refresh Queue Pattern

Part of the MediaBridge series. The Problem with Silent Token Refresh A 5-minute access token is short enough to be practical for security but creates a UX problem. When a page loads and fires several API calls simultaneously, the token might expire in the middle of that burst. Suddenly all five requests get a 401 TOKEN_EXPIRED at roughly the same time. The naive fix is to retry each 401 by refreshing the token. But if five requests all hit 401 and all try to refresh, you get five simultaneous calls to /auth/refresh. Refresh tokens are single-use. The first call succeeds and rotates the token. The next four present the now-used refresh token and get REFRESH_TOKEN_USED. Those requests fail and the user gets logged out, not because their session was invalid but because the client raced itself. ...

February 19, 2026 · 5 min · 934 words · Sagar Nayak

Direct-to-S3 Upload with Presigned URLs

Part of the MediaBridge series. The Upload Problem The obvious way to handle file uploads in a web app is to pipe them through the backend: browser sends the file to your server, server writes it to S3. This works. It also means every upload byte travels twice - once from the browser to your server, and again from your server to S3. Your server becomes a bottleneck, your bandwidth bill doubles, and large files tie up server connections. ...

February 7, 2026 · 6 min · 1163 words · Sagar Nayak

MediaBridge: Self-Hosted S3 File Management for Teams

What MediaBridge is a self-hosted file management layer over AWS S3. It gives teams a proper interface for uploading, browsing, and sharing files across multiple S3 buckets without AWS console access and without distributing IAM credentials to individuals. It runs in production managing 33 S3 buckets. Backend: github.com/sagarnayak/mediabridgeBackend-public Frontend: github.com/sagarnayak/mediabridgeFrontend-public Why The access problem Content teams upload files constantly: images for a web app, PDFs for client portals, videos for a dashboard. Those files need to live in S3 and they need URLs. The question is how the team gets them there. ...

February 1, 2026 · 6 min · 1079 words · Sagar Nayak