Skip to content

Issue #91: Backend — File Upload Service (Cloudinary) #244

@wumibals

Description

@wumibals

Labels: backend upload cloudinary nestjs
Area: backend/src/modules/upload/upload.service.ts, backend/src/modules/upload/upload.controller.ts, backend/src/modules/upload/upload.module.ts
Difficulty: Intermediate

Description

Gallery images, menu item photos, and Instagram post images are uploaded to Cloudinary. This module provides a single POST /upload endpoint that accepts a multipart/form-data file, uploads it to Cloudinary, and returns the secure URL.

Acceptance Criteria

  • Install and configure cloudinary v2 npm package
  • Create backend/src/modules/upload/upload.service.ts with UploadService:
    • Constructor reads Cloudinary credentials from ConfigService (cloudinary.cloudName, cloudinary.apiKey, cloudinary.apiSecret) and calls v2.config()
    • uploadImage(file: Express.Multer.File, folder?: string): Promise<{ url: string; publicId: string }> — uploads the buffer using v2.uploader.upload_stream, resolves with { url: result.secure_url, publicId: result.public_id }
    • deleteImage(publicId: string): Promise<void> — calls v2.uploader.destroy(publicId)
  • Create backend/src/modules/upload/upload.controller.ts with @Controller('upload'):
    • POST /upload@UseGuards(JwtAuthGuard), @UseInterceptors(FileInterceptor("file")), validates file is an image (MIME check), max size 5 MB, calls uploadImage; returns { url, publicId }
    • DELETE /upload/:publicId@UseGuards(JwtAuthGuard), URL-decodes publicId, calls deleteImage
  • Create backend/src/modules/upload/upload.module.ts — imports MulterModule.register({ storage: memoryStorage() }), ConfigModule; exports UploadService
  • Reject non-image MIME types with BadRequestException before uploading

Technical Notes

  • Use memoryStorage (not disk storage) so the file buffer is passed directly to Cloudinary without temp files
  • Cloudinary folder defaults to "thelighted" if not provided

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions