File Upload System
Build real file uploads with validation, progress, storage, and display - files must survive refresh.
The route
6 steps to Done
- 01
Define upload requirements
Decide file types, limits, and storage before writing upload code.
Preview prompt + verify gate ▾ Hide ▴
Define the file upload spec. Specify: allowed file types (e.g. jpg/png/pdf) and max size; where files are stored for this MVP (server uploads directory, database, or object storage) and the tradeoff; the file record model (id, owner, filename, storedPath/url, mimetype, size, uploadedAt); unique storage naming to prevent collisions; and which users can see/delete which files.
- ✓ Allowed types and max size are set
- ✓ Storage location is decided
- ✓ File record fields include owner and unique stored name
- 02
Build the upload UI
A proper upload surface: picker, drag-drop, validation, and progress.
Preview prompt + verify gate ▾ Hide ▴
Build the upload UI. Requirements: file picker button plus drag-and-drop zone; client-side validation of type and size with inline error messages before upload; upload progress indicator per file; multiple file selection support; a clear success state per file and a retry option on failure. Do not fake completion - progress must reflect the real request.
- ✓ Wrong type is rejected before upload with a message
- ✓ Oversized file is rejected with the limit shown
- ✓ Progress reflects the actual upload request
- 03
Implement backend storage
The server must receive, validate, store, and record the file for real.
Preview prompt + verify gate ▾ Hide ▴
Implement the backend upload endpoint. Requirements: accept multipart uploads; re-validate type and size server-side (reject with 400 and a clear message); store the file with a unique generated name; create the file record with owner id and metadata; return the record including a URL/endpoint to retrieve the file; ensure retrieval actually serves the stored bytes. Uploading two files with the same original name must not collide.
- ✓ Server rejects wrong type/size independently of the client
- ✓ Same-name uploads coexist
- ✓ The returned URL serves the actual file
- 04
List and display uploaded files
Users must see their files after refresh - the proof uploads are real.
Preview prompt + verify gate ▾ Hide ▴
Implement the files list. Requirements: fetch the logged-in user's file records from the backend; render image thumbnails for images and type icons for other files; show filename, size, and upload date; clicking opens/downloads the real file; loading skeletons, an empty state for no files, and an error state; the list must be identical after a full page refresh.
- ✓ Files persist across refresh
- ✓ Images render as real thumbnails
- ✓ Another account does not see my files
- 05
Add delete with confirmation
Deletion must remove both the record and the stored file.
Preview prompt + verify gate ▾ Hide ▴
Implement file deletion. Requirements: delete button per file with a confirmation dialog; the backend verifies the requester owns the file, deletes the stored bytes and the record; the UI removes the item and shows a success toast; failures show visible errors; a deleted file's URL stops working. Only owners can delete their files.
- ✓ Deleted file is gone after refresh
- ✓ Its URL no longer serves content
- ✓ Another user cannot delete my file
- 06
Upload QA pass
Verify the full upload lifecycle including hostile inputs.
Preview prompt + verify gate ▾ Hide ▴
Run upload QA and report PASS/FAIL with evidence: upload valid image and PDF; reject .exe and oversized file (client AND direct-to-server); refresh shows persisted list; two same-name files coexist; delete removes file and kills its URL; second account isolation; mobile layout for the upload zone. Fix all failures and re-run.
- ✓ Server-side rejection tested directly
- ✓ Persistence verified via refresh
- ✓ Ownership isolation verified
- ✓ All failures fixed