소스 검색

feat(uploader): enhance upload functionality with detailed API documentation and DTO

Dave 1 개월 전
부모
커밋
f93f3d4eaf

+ 39 - 17
apps/box-mgnt-api/src/mgnt-backend/feature/uploader/uploader.controller.ts

@@ -5,25 +5,11 @@ import {
   Post,
   Req,
 } from '@nestjs/common';
-import { ApiConsumes, ApiTags, ApiProperty } from '@nestjs/swagger';
+import { ApiConsumes, ApiTags, ApiBody, ApiOperation } from '@nestjs/swagger';
 import type { FastifyRequest } from 'fastify';
 import type { MultipartFile } from '@fastify/multipart';
-import {
-  UploaderService,
-  UploadFileType,
-  ImageStorage,
-} from './uploader.service';
-
-class UploadRequestDto {
-  @ApiProperty({ type: String })
-  folder: string;
-
-  @ApiProperty({ type: String })
-  filename: string;
-
-  @ApiProperty({ enum: ['video', 'image', 'voice', 'other'] })
-  fileType: UploadFileType;
-}
+import { UploaderService } from './uploader.service';
+import { UploadRequestDto } from './uploader.dto';
 
 @ApiTags('uploader')
 @Controller('uploader')
@@ -31,7 +17,43 @@ export class UploaderController {
   constructor(private readonly uploaderService: UploaderService) {}
 
   @Post('upload')
+  @ApiOperation({
+    summary: 'Upload a file to storage',
+    description:
+      'Generic infrastructure uploader. Accepts any file bytes and stores them based on sysConfig.imageConfig. ' +
+      'No business logic, no encryption, no URL building.',
+  })
   @ApiConsumes('multipart/form-data')
+  @ApiBody({
+    description: 'Multipart upload payload',
+    schema: {
+      type: 'object',
+      required: ['file', 'folder', 'filename', 'fileType'],
+      properties: {
+        file: {
+          type: 'string',
+          format: 'binary',
+          description: 'File binary stream',
+        },
+        folder: {
+          type: 'string',
+          description: 'Target folder path (relative, no leading slash)',
+          example: 'ads/banner',
+        },
+        filename: {
+          type: 'string',
+          description: 'Target filename including extension',
+          example: 'abc123.jpg',
+        },
+        fileType: {
+          type: 'string',
+          enum: ['video', 'image', 'voice', 'other'],
+          description: 'Logical file type used for size limit enforcement',
+          example: 'image',
+        },
+      },
+    },
+  })
   async upload(@Req() req: FastifyRequest, @Body() body: UploadRequestDto) {
     const mpFile: MultipartFile | undefined = await (req as any).file();
     if (!mpFile) {

+ 26 - 0
apps/box-mgnt-api/src/mgnt-backend/feature/uploader/uploader.dto.ts

@@ -0,0 +1,26 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { UploadFileType } from './uploader.service';
+
+export class UploadRequestDto {
+  @ApiProperty({
+    description:
+      'Target folder path (relative, no leading slash). Example: ads/banner or video/preview',
+    example: 'ads/banner',
+  })
+  folder: string;
+
+  @ApiProperty({
+    description:
+      'Target filename including extension. Uploader does not modify the name.',
+    example: 'abc123.jpg',
+  })
+  filename: string;
+
+  @ApiProperty({
+    description:
+      'Logical file type used for size limit enforcement only (no content validation).',
+    enum: ['video', 'image', 'voice', 'other'],
+    example: 'image',
+  })
+  fileType: UploadFileType;
+}

+ 1 - 1
apps/box-mgnt-api/src/mgnt-backend/feature/uploader/uploader.service.ts

@@ -145,7 +145,7 @@ export class UploaderService {
         return {
           keyPath: keyPaths.localKeyPath,
           imageStorage: 'LOCAL_ONLY',
-        };
+        } as const;
       }
       try {
         await this.uploadLocalFileToS3(