Quiz - Object storage
A teammate wants to add R2 to a brand-new B2B SaaS because “every file should live in object storage, it keeps the database clean.” Three of the app’s payloads are below. Which one actually crosses the threshold that puts a bucket on the table?
jsonb), and marketing images are static assets known at build time (ship them with the build, the CDN serves them). “Keeps the database clean” is the seductive non-reason the lesson warns against — separation for its own sake buys a second store, a second credential surface, and a sync problem for nothing.A read-heavy SaaS serves 50 TB of user files back to browsers every month. Why does an experienced engineer reach for R2 over S3 here?
You’re scoping the R2 token your Next.js app will authenticate with in production. Which grant is the senior default?
Your presigned upload works on a colleague’s machine but fails for a new contractor with a CORS error in the browser — the PUT is cancelled before it’s even sent, and the signature is definitely valid. Where is the fix?
content-type header the browser’s preflight asks for.content-type explicitly — the * wildcard for headers doesn’t reliably admit it.You sign a presigned PUT with ContentLength set to the client’s claimed size, and a content-type allow-list check before signing. A malicious client streams a 2 GB body through the valid URL anyway. Which check is the one that actually stops the oversized file from being accepted?
HeadObjectCommand that reads the real stored size from R2 and refuses to write the metadata row if it exceeds the cap.ContentLength — R2 rejects any PUT whose body exceeds the value baked into the signature.ContentLength (unlike S3’s POST-policy content-length-range), so the signed length is not a boundary. The client pre-check is UX and the server cap trusts a typed number; only the post-upload HEAD reads the actual stored size and rejects before the row is written. That HEAD turns the metadata row into the function’s assertion that it verified the object. The content-type allow-list defends type, not size.An export feature emails users a download link. A teammate sets the presigned GET’s expiry to 24 hours “so the link works all day.” What’s the senior objection?
file_metadata.url column so the link can be reused without re-signing.url column precisely because a stored signed URL ages into a lie.In the safe direct-to-R2 upload flow, why is the file_metadata row inserted after the byte transfer completes rather than before?
You’re choosing the uniqueness constraint for the objectKey column on file_metadata, which uses soft delete. Which is correct?
.unique() with no where — the key stays unique even after the row is soft-deleted.where soft_deleted_at is null — only live rows compete for uniqueness, matching the slug pattern from earlier work.A user in org A pastes a fileId that really belongs to org B and hits the download route, which calls getFile('A', thatId) through tenantDb('A'). What comes back?
null — the org B row was never in the candidate set, so the lookup finds nothing and the route returns an ordinary 404.row.organizationId against 'A' before trusting it.tenantDb('A') welds organizationId = 'A' into the SQL where before the query runs, so a foreign row is never in the result set — the lookup resolves to null and the route 404s, indistinguishable from a file that never existed. The whole point is that there’s no post-load if for a developer to forget; the scope makes the cross-tenant leak impossible to write, rather than relying on a remembered check.The chapter drilled “the function is never a byte pipe,” yet the CSV export’s Trigger.dev worker streams the whole file through itself with a server-side PutObjectCommand. Why isn’t that a violation?
PutObjectCommand is the simplest correct shape. It’s not about which credential is used or the file’s size — it’s about whether there’s a synchronous request in the path at all.User uploads get a file_metadata row; the CSV export output deliberately doesn’t. Which property of the export is the reason it skips the row?
file_metadata.file_metadata only tracks binary payloads.Quiz complete
Score by topic