From 2a6324eba461fd7e59b47f88cad931280d243988 Mon Sep 17 00:00:00 2001 From: chanwoo7 Date: Tue, 6 Oct 2026 07:30:28 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=83=81=ED=95=9C=205=20=E2=86=92=206=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 판매자 앱 상품 등록 시안의 이미지 드롭존이 '이미지 추가 (0/6)'로 최대 6장을 받는다. 사용자 결정(2026-10-06)으로 BE 상한을 시안에 맞춤. - MAX_PRODUCT_IMAGES 5 → 6. 이 상수를 쓰는 곳은 sellerAddProductImage 하나. 관리자 경로는 이미지 추가가 없고 조회(imageUrls)만이라 영향 없음. - PRODUCT_IMAGE_LIMIT_EXCEEDED 메시지는 { max }로 렌더되므로 '최대 6장'으로 함께 바뀜. - SDL 변경 없음 — 상한 문구가 SDL description에 없음. - 회귀 테스트 1건 교체: 6장째 추가 성공, 7장째 PRODUCT_IMAGE_LIMIT_EXCEEDED, 메시지의 max, 건수 6 유지. 시드는 리터럴이라 상수만 5로 되돌리면 6장째 추가에서 실패(반증 확인). --- .../constants/product-seller.constants.ts | 2 +- .../product-seller-image.service.spec.ts | 22 ++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/features/product/constants/product-seller.constants.ts b/src/features/product/constants/product-seller.constants.ts index 52163c4f..209e10a5 100644 --- a/src/features/product/constants/product-seller.constants.ts +++ b/src/features/product/constants/product-seller.constants.ts @@ -11,7 +11,7 @@ export const DEFAULT_PREPARATION_TIME_MINUTES = 180; export const MIN_PRODUCT_PRICE = 1; export const MIN_SALE_PRICE = 0; export const MAX_PRODUCT_PRICE = 1_000_000_000; -export const MAX_PRODUCT_IMAGES = 5; +export const MAX_PRODUCT_IMAGES = 6; export const MIN_PRODUCT_IMAGES = 1; // ── 옵션 ── diff --git a/src/features/product/services/product-seller-image.service.spec.ts b/src/features/product/services/product-seller-image.service.spec.ts index b72828fa..85ed0b1e 100644 --- a/src/features/product/services/product-seller-image.service.spec.ts +++ b/src/features/product/services/product-seller-image.service.spec.ts @@ -1,5 +1,6 @@ import { AUDIT_LOG_REPOSITORY } from '@/features/audit-log'; import { AuditLogRepository } from '@/features/audit-log/repositories/audit-log.repository'; +import { MAX_PRODUCT_IMAGES } from '@/features/product/constants/product-seller.constants'; import { ProductRepository } from '@/features/product/repositories/product.repository'; import { SellerProductImageService } from '@/features/product/services/product-seller-image.service'; import { StoreSellerRepository } from '@/features/store/repositories/store-seller.repository'; @@ -60,9 +61,10 @@ describe('SellerProductImageService (real DB)', () => { } describe('sellerAddProductImage', () => { - it('이미지가 이미 5개면 400 (PRODUCT_IMAGE_LIMIT_EXCEEDED)', async () => { + it('6장째까지 추가되고 7장째는 PRODUCT_IMAGE_LIMIT_EXCEEDED로 거절된다', async () => { const { account, store } = await setupSellerWithStore(prisma); const product = await createSellerProduct(store.id); + // 총 5장을 리터럴로 시드한다 — 상한 상수만 바뀌어도 6장째 추가에서 걸린다 for (let i = 1; i <= 4; i++) { await prisma.productImage.create({ data: { @@ -72,13 +74,21 @@ describe('SellerProductImageService (real DB)', () => { }, }); } - - await expect( + const add = (file: string) => service.sellerAddProductImage(account.id, { productId: product.id.toString(), - imageUrl: ownedUploadUrl('PRODUCT_IMAGE', account.id, '6.png'), - }), - ).rejects.toThrowDomain(400); + imageUrl: ownedUploadUrl('PRODUCT_IMAGE', account.id, file), + }); + + await add('6.png'); + const seventh = add('7.png'); + await expect(seventh).rejects.toThrowDomain( + 'PRODUCT_IMAGE_LIMIT_EXCEEDED', + ); + await expect(seventh).rejects.toThrow(`최대 ${MAX_PRODUCT_IMAGES}장까지`); + expect( + await prisma.productImage.count({ where: { product_id: product.id } }), + ).toBe(MAX_PRODUCT_IMAGES); }); it('정상 추가', async () => {