Problem Statement
Getting a public link to a file shouldn't require renting bandwidth. Most upload services proxy every byte through their own servers — which means every megabyte costs the operator twice (ingress + egress) and gets slower the bigger the file. FileSalad answers a narrower question: what if the backend only handles permissions and metadata, and the bytes flow straight from the client to S3-compatible storage?
Proposed Solution
FileSalad is one Go API with two clients on top of a shared design system:
file-salad-web— anonymous one-pager. Drop a file, get a link. No account, no friction. Capped per browser via IP + anX-Fingerprintheader.file-salad-electron— authenticated macOS menu-bar app. Email + password, JWT + rotating refresh sessions, a monthly quota, and the option of Bring-Your-Own-Bucket (BYOK) so power users can point uploads at their own R2/S3/Tigris/MinIO.backend— Go + Gin API that authenticates the request, checks quota, mints a presigned PUT URL, and records metadata. It never sees the bytes.file-salad-ui-lib— independently published React component library + design tokens used by both clients.
Every upload follows the same shape: presign → client PUTs bytes straight to storage → complete. Share codes mint short, human-shareable codes anyone can redeem for a fresh download URL. Feature flags (/features) toggle rollouts like share-codes and BYOK without a redeploy.
Full Solution Details
- Two surfaces, one API — the web app and the desktop app hit the same Go backend, with different auth modes (anonymous vs JWT) gating different endpoints.
- Zero-byte-touch backend — the server never proxies file content; it's a permission + metadata broker. Storage cost scales with the bucket bill, not the server bill.
- Anonymous upload caps — IP + fingerprint-based throttling keeps the free web client from being a credit-card-melter.
- Authenticated desktop — JWT access token with rotating refresh sessions, monthly quota tracking, and a BYOK upload path for users who want to host their own storage.
- Share codes — short, redeemable codes that issue a fresh signed download URL on demand (preserves URL expiry without breaking shared links).
- Feature flags — a
/featuresendpoint toggles share-codes, BYOK, and other rollouts at runtime. - Independent packages — four
package.json/go.mods, no monorepo, no root workspace; each ships on its own.
Technical Documentation
Backend — Go 1.25 + Gin, MongoDB (official driver) for metadata, Redis (go-redis/v9) for ephemeral state (with miniredis for tests), AWS SDK v2 (aws-sdk-go-v2/service/s3) for presigning against any S3-compatible storage, golang-jwt/v5 for auth, ULIDs (oklog/ulid/v2) for IDs, and godotenv for config. Idiomatic cmd/server + internal/... feature-package layout.
Web — React 19 + Vite + TypeScript, TanStack Query v5, React Router v6, the author's own Meemaw utility library, Lucide icons, and the shared file-salad-ui-lib consumed straight from GitHub by tag.
Desktop — Electron + electron-vite + React 19, packaged with electron-builder (mac arm64), AWS request signing via aws4 for BYOK uploads, zod for runtime validation, tailwind-merge + clsx for styling, and the same shared UI library.
UI Library — React + Vite, Storybook for docs, dual ESM/CJS exports, tailwindcss compiled to a single distributable stylesheet, with a verify-exports.mjs script that gates the build on the exports map being correct.
Tech Stack
Go 1.25, Gin, MongoDB, Redis, AWS SDK v2 (S3 presign), JWT, ULIDs (backend); React 19, TypeScript, Vite, TanStack Query v5, React Router v6, Meemaw, Lucide (web); Electron, electron-vite, electron-builder, aws4, zod (desktop); Tailwind, Storybook, dual ESM/CJS exports (UI library).
System Design
file-salad-web ──┐
├──► backend (Gin) ──presign──► S3-compatible
file-salad-electron ─┘ │ JWT + quota storage
│ share codes (Tigris / R2 /
│ feature flags MinIO / S3)
▼
MongoDB · Redis
client ──PUT bytes─► storage (backend never sees bytes)
client ──complete──► backend (metadata + share code)
Smart Architectural Decisions
- Backend is a broker, not a pipe. By only issuing presigned URLs and recording metadata, the server's cost and latency are decoupled from file size — a 10 GB upload is the same workload as a 10 KB one.
- Two clients, one contract. Anonymous web and authenticated desktop share the same API by varying which endpoints they hit, not by forking the API. Auth shape is the only diff.
- BYOK as a first-class feature. Letting users point uploads at their own bucket sidesteps the operator-cost ceiling that kills most free upload tools.
- Independent, publishable packages. No monorepo glue — the UI library is consumed by Git tag, each app builds on its own, and the four pieces version independently.
- Feature flags via API.
/featureslets share-codes, BYOK, and other behaviors flip on/off without a redeploy — useful when the same backend serves two different client surfaces. miniredisin tests + ULIDs for IDs — small choices that show backend taste: deterministic local testing without spinning up Redis, and time-sortable IDs that beat UUIDs for log-friendly debugging.
Impacts
A file-sharing service that decouples server cost from file size, ships two distinct user experiences (anonymous web + authenticated desktop) over a single zero-byte-touch API, and gives power users BYO-bucket control — all with a coherent in-house React design system underneath.
Demonstrated Skills
Go backend engineering with the AWS SDK v2 (presigning, S3-compatible abstraction); auth design (anonymous fingerprinting + JWT with refresh sessions side-by-side); cost-aware system design (broker vs proxy, BYOK); Electron app delivery (electron-vite + electron-builder, mac arm64 packaging); design-system thinking (publishable UI library with verified exports); cross-client API contract design; feature flags as a runtime control plane.