Run the business
File storage
Tenant-scoped uploads with the receipts in your own database and the bytes behind an adapter you own — files your product can reason about, not a bucket nobody can.
The problem
A file whose only record is the storage vendor's dashboard is a file your product can't list, authorize, bill, or delete by.
How it works
Every stored file is a row in your own database — the receipt your product lists, scopes to a tenant, and deletes by. The bytes live behind a two-method adapter you own: Vercel Blob, S3, or a directory on disk in tests, swapped without re-auditing a single caller.
Reads and deletes are tenant-scoped in the query itself, so a guessed id belonging to another tenant touches nothing. The upload is a plain route handler, because a file has no business being serialized through a typed RPC layer.
- A database row per file; tenant-scoped list, get, and delete
- Vendor-neutral adapter — no storage SDK baked into the package
- A blob with a row is a file; a blob without one is a leak — so the bytes go down first, the receipt second, and the bytes are reclaimed if the receipt fails
- Deleting a file removes the bytes by their storage handle, which the row keeps separately from the public URL — conflating the two is how 'deleted' files keep serving
npm install @adminigloo/storageBook a callAll features