Media & Image Uploads
Relevant source files
The following files were used as context for generating this wiki page:
The Media & Image Uploads system in SoulSeer handles the acquisition, validation, storage, and retrieval of visual assets, primarily reader profile images. It provides a secure pipeline from the client-side UI to Cloudinary cloud storage, mediated by the backend API to ensure data integrity and security.
The scope of this system includes client-side file picking, frontend validation of file types and sizes, multipart/form-data transmission, backend middleware for handling binary data, and integration with the Cloudinary service for permanent storage.
Architecture & Data Flow
The system follows a standard client-server architecture where the frontend initiates the upload process, and the backend acts as a gateway to external storage.
Data Flow Overview
- Selection: The user selects an image via the
ImageUploadFieldcomponent. - Frontend Validation: The client checks if the file meets size (≤ 5MB) and type (JPEG, PNG, WebP) requirements.
- Transmission: The file is sent as
FormDatato the/api/admin/readers/:id/imageendpoint. - Backend Processing:
multermiddleware handles the multipart request, storing the file in memory. - Cloud Storage: The
cloudinaryServiceuploads the memory buffer to Cloudinary. - Persistence: The resulting URL is returned to the client and optionally updated in the database.
Sources: client/src/components/ImageUploadField.tsx:28-56, server/src/routes/admin.ts:161-200
Upload Sequence Diagram
The following diagram illustrates the lifecycle of an image upload from the user interface to cloud storage.
Components & Implementation
Frontend: ImageUploadField
The ImageUploadField is a reusable React component that manages the file input and provides immediate feedback through toasts. It uses a hidden file input and a custom button trigger to maintain the application's aesthetic.
- Key Logic:
- Enforces
MAX_SIZE_BYTES(5,242,880 bytes). - Filters by
ACCEPTED_TYPES(image/jpeg,image/png,image/webp). - Uses
apiService.uploadto handlemultipart/form-data.
- Enforces
Sources: client/src/components/ImageUploadField.tsx:7-14, client/src/components/ImageUploadField.tsx:28-40
Backend: Admin Image Routes
The backend utilizes multer for handling file streams and a dedicated Cloudinary service for storage abstraction.
| Feature | Implementation Detail |
|---|---|
| Middleware | multer({ storage: memoryStorage() }) |
| Max File Size | 5 MB |
| Allowed MIMEs | image/jpeg, image/png, image/webp |
| Storage Folder | soulseer/readers |
Sources: server/src/routes/admin.ts:25-42, server/src/routes/admin.ts:182
Cloudinary Service
The cloudinaryService (referenced in server/src/routes/admin.ts) provides a wrapper around the Cloudinary SDK. It is responsible for taking the buffer provided by multer and uploading it to the cloud.
// server/src/routes/admin.ts:178-183
const { url } = await cloudinaryService.uploadBuffer(req.file.buffer, {
folder: "soulseer/readers",
});
Sources: server/src/routes/admin.ts:178-183
API Reference
Image Upload Endpoint
Processes profile image updates for reader accounts.
- URL:
/api/admin/readers/:id/image - Method:
POST - Authentication: Required (Admin role)
- Content-Type:
multipart/form-data
Request Body Parameters:
| Parameter | Type | Description |
|---|---|---|
file | File | The binary image data (max 5MB). |
Response (Success):
{
"url": "https://res.cloudinary.com/..."
}
Sources: server/src/routes/admin.ts:161-205, shared/src/validators.ts:114-126
Validation Constraints
The project enforces strict validation on both the shared library and the specific route implementations to prevent resource exhaustion and invalid data.
| Constraint | Value | Context |
|---|---|---|
| Max Payload Size | 2 MB | Global JSON parsing limit |
| Image File Size | 5 MB | Multer and Frontend limit |
| Profile Image URL | Max 512 chars | Database/Validator limit |
| MIME Types | jpeg, png, webp | Security/Compatibility |
Sources: server/src/index.ts:79, server/src/routes/admin.ts:33, shared/src/validators.ts:31
Conclusion
The Media & Image Uploads system provides a centralized way to handle spiritual reader profiles. By using Cloudinary for storage and multer for memory processing, the system avoids local file storage complexities while maintaining strict control over asset types and sizes. This ensures the platform remains performant and secure against malicious file uploads.