Shop
개요
쇼핑몰 생성, 관리, 커스텀 도메인, 버전 관리를 담당하는 핵심 도메인. 사용자(Seller)가 만드는 쇼핑몰의 메타데이터, 브랜딩, 현지화, SEO, 커스텀 도메인 등을 관리합니다.
서버 패키지: com.makitt.core.domain.shop
DynamoDB Entity
Shop
Single Table Design 기반의 메인 Shop 엔티티. 2개의 레코드로 구성됩니다:
- METADATA 레코드 (PK=
SHOP#{shopId}, SK=METADATA) — Shop의 모든 상세 정보
- User Shop List 레코드 (PK=
USER#{userId}, SK=SHOP#{shopId}) — 사용자의 Shop 목록 조회용
키 구조 (METADATA):
| 키 | 패턴 | 예시 |
|---|
| PK | SHOP#{shopId} | SHOP#shop123 |
| SK | METADATA | METADATA |
키 구조 (User Shop List):
| 키 | 패턴 | 예시 |
|---|
| PK | USER#{userId} | USER#abc123 |
| SK | SHOP#{shopId} | SHOP#shop123 |
필드:
| 필드 | DynamoDB Attribute | 타입 | 필수 | 설명 |
|---|
| pk | PK | String | O | Partition Key |
| sk | SK | String | O | Sort Key |
| entityType | entity_type | String | O | "SHOP" 고정 |
| shopId | shop_id | String | O | Shop 고유 ID |
| userId | user_id | String | O | 소유자 User ID |
| organizationId | organization_id | String | O | 소속 Organization ID |
| shopName | shop_name | String | O | 상점 이름 |
| shopUrl | shop_url | String | O | MAKITT 서브도메인 (예: fashion-store) |
| status | status | ShopStatus | O | 상점 상태 |
| markets | markets | List<String> | X | 대상 마켓 코드 (예: ["KR", "US", "JP"]) |
| primaryMarketCode | primary_market_code | String | X | 기본 마켓 코드 |
| branding | branding | ShopBranding | X | 브랜딩 정보 (nested) |
| localization | localization | ShopLocalization | X | 현지화 설정 (nested) |
| seo | seo | ShopSeo | X | SEO 설정 (nested) |
| customDomain | custom_domain | CustomDomain | X | 커스텀 도메인 (nested) |
| createdAt | created_at | Instant | O | 생성 시각 |
| updatedAt | updated_at | Instant | O | 수정 시각 |
Factory Methods:
Shop.create(shopId, userId, organizationId, shopName, shopUrl, markets, primaryMarketCode) — METADATA 레코드 생성. branding/localization/seo는 기본값으로 초기화.
Shop.createUserShopListRecord(userId, organizationId, shopId, shopName, shopUrl, markets, primaryMarketCode) — User Shop List 레코드 생성 (목록 조회용 최소 정보).
Nested Objects
ShopBranding
| 필드 | DynamoDB Attribute | 타입 | 설명 |
|---|
| description | description | String | 상점 설명 |
| logoUrl | logo_url | String | 로고 이미지 URL |
| bannerImageUrl | banner_image_url | String | 배너 이미지 URL |
ShopLocalization
| 필드 | DynamoDB Attribute | 타입 | 설명 |
|---|
| language | language | String | 기본 언어 (예: ko) |
| timezone | timezone | String | 타임존 (예: Asia/Seoul) |
| currency | currency | String | 기본 통화 (예: KRW) |
| localizationConfirmed | localization_confirmed | Boolean | 국제화 기본값 확정 여부 (1회 확정 후 변경 불가) |
비즈니스 규칙:
confirm(language, timezone, currency) — 1회 확정. 이미 확정된 경우 IllegalStateException 발생.
- 확정 시 ShopOnboarding의
SHOP_PROFILE_SET.LOCALIZATION_CONFIRMED sub-step 자동 완료.
defaults() — 기본값 생성 (en, UTC, USD, localizationConfirmed=false).
주의 (DynamoDB Enhanced Client): @DynamoDbBean nested 클래스에서 Boolean 필드에 isXxx() 메서드를 정의하면 JavaBeans getter 충돌로 직렬화 실패. 반드시 Boolean.TRUE.equals(field) 인라인으로 사용할 것.
ShopSeo
| 필드 | DynamoDB Attribute | 타입 | 설명 |
|---|
| title | title | String | SEO 제목 |
| description | description | String | SEO 설명 |
| imageUrl | image_url | String | OG 이미지 URL |
CustomDomain
커스텀 도메인 설정 및 SSL 인증서 상태 관리.
| 필드 | DynamoDB Attribute | 타입 | 설명 |
|---|
| domain | domain | String | 도메인 주소 (예: www.myshop.com) |
| status | status | CustomDomainStatus | 도메인 상태 |
| requestedAt | requested_at | Instant | 등록 요청 시각 |
| updatedAt | updated_at | Instant | 상태 변경 시각 |
| verifiedAt | verified_at | Instant | DNS 인증 완료 시각 (ACTIVE 시) |
| currentIps | current_ips | List<String> | 현재 A 레코드 IP (FAILED 시) |
| failureReason | failure_reason | String | 실패 사유 (FAILED 시) |
상태 전이:
REGISTERED → PENDING → ACTIVE
↓
FAILED → REGISTERED (retry)
Enums
ShopStatus
| 값 | 설명 |
|---|
DRAFT | 생성 중 (아직 발행 안 됨) |
ACTIVE | 운영 중 (고객 접근 가능) |
INACTIVE | 비활성화 (소유자에 의해 일시 중지 / 삭제) |
SUSPENDED | 정책 위반으로 정지 |
CustomDomainStatus
| 값 | 설명 |
|---|
REGISTERED | 도메인 등록됨 — DNS A 레코드 확인 대기 |
PENDING | DNS 확인 완료 — SSL 인증서 발급 대기 |
ACTIVE | 인증서 발급 완료 — HTTPS 정상 동작 |
FAILED | DNS 확인 실패 — 사용자가 DNS 설정 수정 후 재시도 필요 |
GSI 키 구조
| GSI | 용도 | PK 패턴 | SK 패턴 |
|---|
| GSI1 (EntityLookupIndex) | Organization의 Shop 목록 | ORGANIZATION#{organizationId} | SHOP#{shopId} |
| GSI2 (UniqueLookupIndex) | shopUrl 유니크 조회 | {shopUrl} | SHOP#{shopId} |
| GSI3 (SecondaryIdIndex) | 커스텀 도메인 상태별 조회 (sparse) | CUSTOM_DOMAIN_STATUS#{status} | SHOP#{shopId} |
| GSI4 (FilterIndex) | 커스텀 도메인 이름 조회 (sparse) | CUSTOM_DOMAIN#{domain} | SHOP#{shopId} |
Shop Onboarding
Shop별 온보딩 진행 상태. MAKITT HAPPEN (9 steps) + MAKITT EXPLODE (6 steps)를 추적합니다. Shop과 동일 파티션에 저장됩니다.
키 구조:
| 키 | 패턴 | 예시 |
|---|
| PK | SHOP#{shopId} | SHOP#shop123 |
| SK | ONBOARDING | ONBOARDING |
상세 문서: ShopOnboarding
ShopOnboardingStep (HAPPEN)
| Step | 설명 | 필수 | Per-Market |
|---|
SHOP_PROFILE_SET | 상점 프로필 설정 | O | O |
MARKET_SET | 마켓 설정 | O | X |
POLICIES_SET | 정책 설정 | O | O |
SHOP_DESIGN_SET | 상점 디자인 | O | X |
LOGISTICS_SET | 물류 설정 | X | O |
SHIPPING_SET | 배송 설정 | O | O |
PAYMENT_SET | 결제 설정 | O | O |
PRODUCT_REGISTERED | 상품 등록 | O | X |
PRICING_SET | 가격/세금 설정 | O | O |
BUSINESS_INFO_SET는 legacy (SHOP_PROFILE_SET sub-step으로 통합됨, happenSteps()에서 제외)
ShopOnboardingStep (EXPLODE)
| Step | 설명 | 필수 | Per-Market |
|---|
PROMOTIONS | 프로모션 | X | O |
MEMBER_TIERS | 회원 등급 | X | X |
REWARDS | 리워드 | X | X |
COUPONS | 쿠폰 | X | O |
SOCIAL_LOGIN | 소셜 로그인 | X | O |
CRM | CRM/세그먼트 | X | X |
ShopProfileSubStep (SHOP_PROFILE_SET의 하위)
| Sub-Step | 설명 | 필수 | Per-Market |
|---|
LOCALIZATION_CONFIRMED | 국제화 기본값 확정 | O | X |
BASIC_INFO_SET | 기본 정보 설정 | O | O |
BRAND_ASSET_SET | 브랜드 에셋 설정 | O | O |
BUSINESS_INFO_SET | 사업자 정보 설정 | O | O |
주요 비즈니스 메서드
Shop 정보 수정
updateInfo(shopName, description, logoUrl, bannerImageUrl, language, timezone, currency, seoTitle, seoDescription, seoImageUrl) — 전체 정보 일괄 수정
updateBranding(description, logoUrl, bannerImageUrl) — 브랜딩만 수정
updateLocalization(language, timezone, currency) — 현지화만 수정
updateSeo(title, description, imageUrl) — SEO만 수정
updateMarkets(markets, primaryMarketCode) — 마켓 설정 수정
updateStatus(ShopStatus status) — 상태 변경
국제화 기본값 확정
ShopLocalization.confirm(language, timezone, currency) — 1회 확정 (되돌리기 불가). 이미 확정된 경우 예외 발생.
ShopApplication.confirmLocalization(shopId, language, timezone, currency) — 소유권 확인 → 확정 → DB 저장 → 온보딩 sub-step 완료
커스텀 도메인 관리
requestCustomDomain(domain) — 도메인 등록 요청 (REGISTERED), GSI3/GSI4 업데이트
activateCustomDomain() — 도메인 활성화 (SSL 인증서 발급 완료), GSI4 설정
failCustomDomain(currentIps, reason) — 도메인 발급 실패 (IP/사유 기록), GSI4 제거
retryCustomDomain() — 실패 후 재시도 (FAILED → REGISTERED)
removeCustomDomain() — 도메인 제거, GSI3/GSI4 제거
hasActiveCustomDomain() — 활성 도메인 여부
getCustomDomainName() — 도메인 주소 반환
API
Shop CRUD
| 메서드 | 엔드포인트 | 설명 |
|---|
| POST | /api/v1/shops | Shop 생성 (초기 버전 자동 생성) |
| GET | /api/v1/shops | 내 Shop 목록 조회 |
| GET | /api/v1/shops/{shopId} | Shop 상세 조회 |
| PUT | /api/v1/shops/{shopId} | Shop 메타데이터 수정 |
| DELETE | /api/v1/shops/{shopId} | Shop 삭제 (soft-delete → INACTIVE) |
Localization
| 메서드 | 엔드포인트 | 설명 |
|---|
| POST | /api/v1/shops/{shopId}/localization/confirm | 국제화 기본값 확정 (1회, 비가역) |
Shop Onboarding
| 메서드 | 엔드포인트 | 설명 |
|---|
| GET | /api/v1/shops/{shopId}/onboarding | Shop 온보딩 상태 조회 (HAPPEN + EXPLODE) |
| POST | /api/v1/shops/{shopId}/onboarding/steps/{stepId}/complete | 온보딩 step 완료 (?marketCode=KR) |
| POST | /api/v1/shops/{shopId}/onboarding/steps/{stepId}/sub-steps/{subStepId}/complete | 온보딩 sub-step 완료 (?marketCode=KR) |
Custom Domain
| 메서드 | 엔드포인트 | 설명 |
|---|
| POST | /api/v1/shops/{shopId}/custom-domain | 커스텀 도메인 등록 요청 |
| DELETE | /api/v1/shops/{shopId}/custom-domain | 커스텀 도메인 제거 |
| POST | /api/v1/shops/{shopId}/custom-domain/retry | 실패한 도메인 재시도 |
| GET | /api/v1/shops/{shopId}/custom-domain/status | 도메인 상태 상세 조회 |
Market Profile
| 메서드 | 엔드포인트 | 설명 |
|---|
| GET | /api/v1/shops/{shopId}/market-profiles | 전체 마켓 프로필 목록 조회 |
| GET | /api/v1/shops/{shopId}/market-profiles/{marketCode} | 마켓별 프로필 단건 조회 |
| PUT | /api/v1/shops/{shopId}/market-profiles/{marketCode} | 마켓 프로필 생성/수정 (upsert) |
Shop Version
| 메서드 | 엔드포인트 | 설명 |
|---|
| POST | /api/v1/shops/{shopId}/versions | 버전 생성 (DRAFT) |
| GET | /api/v1/shops/{shopId}/versions | 버전 목록 조회 |
| PUT | /api/v1/shops/{shopId}/versions/{versionId} | DRAFT 버전 수정 |
| PUT | /api/v1/shops/{shopId}/versions/{versionId}/compiled | Compiled URL 업데이트 (내부용) |
| POST | /api/v1/shops/{shopId}/versions/{versionId}/publish | 버전 발행 |
| GET | /api/v1/shops/{shopId}/versions/{versionId}/detail | Shop + Version 상세 조회 |
HCS / System Defaults
| 메서드 | 엔드포인트 | 설명 |
|---|
| POST | /api/v1/shops/hcs-json/presigned-url | HCS JSON 업로드 Presigned URL 생성 |
| POST | /api/v1/shops/{shopId}/compiled/presigned-url | Compiled 파일 업로드 Presigned URL 생성 |
| GET | /api/v1/shops/system-defaults/urls | System default HCS 파일 URL 조회 |
| POST | /api/v1/shops/system-defaults/presigned-url | System default 업로드 Presigned URL 생성 |
Public API
| 메서드 | 엔드포인트 | 설명 |
|---|
| GET | /api/v1/public/shops/url/{shopUrl} | shopUrl로 발행된 Shop 조회 (인증 불필요) |
Key Builder
클래스: com.makitt.core.common.dynamodb.key.ShopKey
// METADATA 레코드
ShopKey.pk(shopId) → "SHOP#{shopId}"
ShopKey.sk() → "METADATA"
// User Shop List 레코드
ShopKey.userShopListPk(userId) → "USER#{userId}"
ShopKey.userShopListSk(shopId) → "SHOP#{shopId}"
// GSI1: Organization의 Shop 목록
ShopKey.gsi1Pk(organizationId) → "ORGANIZATION#{organizationId}"
ShopKey.gsi1Sk(shopId) → "SHOP#{shopId}"
// GSI2: shopUrl 유니크 조회
ShopKey.gsi2Pk(shopUrl) → "{shopUrl}"
ShopKey.gsi2Sk(shopId) → "SHOP#{shopId}"
// GSI3: 커스텀 도메인 상태별 (sparse)
ShopKey.gsi3Pk(status) → "CUSTOM_DOMAIN_STATUS#{status}"
ShopKey.gsi3Sk(shopId) → "SHOP#{shopId}"
// GSI4: 커스텀 도메인 이름 조회 (sparse)
ShopKey.gsi4Pk(customDomain) → "CUSTOM_DOMAIN#{customDomain}"
ShopKey.gsi4Sk(shopId) → "SHOP#{shopId}"
// ShopMarketProfile
ShopKey.marketProfileSk(marketCode) → "MARKET_PROFILE#{marketCode}"
ShopKey.marketProfileSkPrefix() → "MARKET_PROFILE#"
// ShopOnboarding
ShopKey.onboardingSk() → "ONBOARDING"
// ShopVersion
ShopKey.versionSk(timestamp, versionId) → "VERSION#{timestamp}#{versionId}"
ShopKey.versionSkPrefix() → "VERSION#"
// Helper
ShopKey.extractShopId(pk) → "shop123" (from "SHOP#shop123")
서버 아키텍처
ShopController / CustomDomainController / ShopMarketProfileController (makitt-api)
|
v (DTO <-> VO)
ShopApplication / ShopMarketProfileApplication (makitt-application)
|
v (VO)
ShopService / ShopOnboardingService / ShopMarketProfileService (makitt-core/service)
|
v (DynamoDB 조작)
ShopRepository / ShopOnboardingRepository / ShopMarketProfileRepository (makitt-core/repository)
|
v
Shop / ShopOnboarding / ShopMarketProfile (makitt-core/entity)
패키지 구조:
makitt-core/
com.makitt.core.domain.shop/
entity/
Shop.java # DynamoDB Entity
ShopStatus.java # 상태 Enum
ShopStatusConverter.java # DynamoDB Converter
ShopBranding.java # 브랜딩 Nested Object
ShopLocalization.java # 현지화 Nested Object
ShopSeo.java # SEO Nested Object
CustomDomain.java # 커스텀 도메인 Nested Object
CustomDomainStatus.java # 도메인 상태 Enum
CustomDomainStatusConverter.java
ShopVersion.java # 버전 Entity (같은 파티션)
VersionStatus.java # 버전 상태 Enum
VersionStatusConverter.java
ShopOnboarding.java # Shop 온보딩 Entity (같은 파티션)
ShopOnboardingStep.java # HAPPEN/EXPLODE step Enum
ShopProfileSubStep.java # SHOP_PROFILE_SET sub-step Enum
ShopHcs.java # HCS 관련 Nested Object
ShopMarketProfile.java # 마켓별 프로필 Entity
MarketBusinessInfo.java # 사업자 정보 Nested Object
MarketSeo.java # 마켓별 SEO Nested Object
PlatformLink.java # 소셜/플랫폼 링크 Nested Object
PredefinedPlatform.java # 사전정의 플랫폼 Enum
service/
ShopService.java
ShopOnboardingService.java
ShopAuthSettingsService.java
ShopPaymentSettingsService.java
ShopMarketProfileService.java
repository/
ShopRepository.java
ShopOnboardingRepository.java
ShopAuthSettingsRepository.java
ShopPaymentSettingsRepository.java
ShopMarketProfileRepository.java
vo/
CreateShopRequestVo.java
UpdateShopRequestVo.java
ShopResponseVo.java
ShopOnboardingResponseVo.java
ShopVersionResponseVo.java
CreateShopVersionRequestVo.java
UpdateShopVersionRequestVo.java
ShopWithVersionResponseVo.java
PublishedShopResponseVo.java
HcsJsonUploadRequestVo.java
HcsJsonUploadResponseVo.java
CompiledUploadRequestVo.java
CompiledUploadResponseVo.java
SystemDefaultUrlsVo.java
InitialVersionVo.java
ShopMarketProfileResponseVo.java
UpdateMarketProfileRequestVo.java
makitt-application/
com.makitt.application.shop/
ShopApplication.java
ShopMarketProfileApplication.java
makitt-api/
com.makitt.api.controller.shop/
ShopController.java
CustomDomainController.java
PublicShopController.java
ShopAuthSettingsController.java
ShopPaymentSettingsController.java
ShopMarketProfileController.java
com.makitt.api.dto.shop/
CreateShopRequest.java
UpdateShopRequest.java
ShopResponse.java
ShopListResponse.java
ShopOnboardingResponse.java
ConfirmLocalizationRequest.java
RegisterCustomDomainRequest.java
CustomDomainResponse.java
CustomDomainStatusResponse.java
CreateShopVersionRequest.java
UpdateShopVersionRequest.java
ShopVersionResponse.java
ShopVersionListResponse.java
ShopWithVersionResponse.java
PublishedShopResponse.java
HcsJsonUploadRequest.java
HcsJsonUploadResponse.java
CompiledUploadResponse.java
SystemDefaultUrlsResponse.java
MarketProfileResponse.java
UpdateMarketProfileRequest.java
ShopMarketProfile
마켓별 상점 프로필 엔티티. Shop과 동일 파티션에 저장됩니다.
키 구조:
| 키 | 패턴 | 예시 |
|---|
| PK | SHOP#{shopId} | SHOP#shop123 |
| SK | MARKET_PROFILE#{marketCode} | MARKET_PROFILE#KR |
필드:
| 필드 | DynamoDB Attribute | 타입 | 필수 | 설명 |
|---|
| pk | PK | String | O | Partition Key |
| sk | SK | String | O | Sort Key |
| entityType | entity_type | String | O | "SHOP_MARKET_PROFILE" 고정 |
| shopId | shop_id | String | O | Shop ID |
| marketCode | market_code | String | O | 마켓 코드 (예: KR, US, JP) |
| displayName | display_name | String | X | 마켓별 상점 표시 이름 |
| description | description | String | X | 마켓별 상점 설명 |
| representativeImageUrl | representative_image_url | String | X | 대표 이미지 URL |
| logos | logos | Map<String, String> | X | 브랜드 로고 맵 (예: {"main": "url", "monochrome": "url"}) |
| faviconUrl | favicon_url | String | X | 파비콘 URL |
| platformLinks | platform_links | List<PlatformLink> | X | 소셜/마켓플레이스 링크 (nested list) |
| businessInfo | business_info | MarketBusinessInfo | X | 마켓별 사업자 정보 (nested) |
| seo | seo | MarketSeo | X | 마켓별 SEO 설정 (nested) |
| createdAt | created_at | Instant | O | 생성 시각 |
| updatedAt | updated_at | Instant | O | 수정 시각 |
Factory Methods:
ShopMarketProfile.create(shopId, marketCode) — PK/SK/entityType/timestamps 초기화
updateProfile(...) — 전체 프로필 일괄 수정, updatedAt 갱신
Nested: MarketBusinessInfo
마켓별 사업자/법인 정보. 마켓마다 요구 필드가 다르며, MarketMeta.businessInfoFields에서 어떤 필드를 표시할지 정의.
| 필드 | DynamoDB Attribute | 대상 마켓 | 설명 |
|---|
| businessNumber | business_number | KR | 사업자등록번호 |
| onlineBusinessNumber | online_business_number | KR | 통신판매업 신고번호 |
| companyName | company_name | All | 상호(법인명) |
| representativeName | representative_name | All | 대표자명 |
| businessAddress | business_address | All | 사업장 주소 |
| businessAddressDetail | business_address_detail | All | 상세 주소 |
| postalCode | postal_code | All | 우편번호 |
| customerServicePhone | customer_service_phone | All | CS 전화번호 |
| customerServiceEmail | customer_service_email | All | CS 이메일 |
| customerServiceKakao | customer_service_kakao | KR | 카카오톡 채널 |
| operatingHours | operating_hours | All | 영업시간 |
| lunchBreak | lunch_break | All | 점심시간 |
| closedDays | closed_days | All | 휴무일 |
| corporateNumber | corporate_number | JP | 法人番号 |
| tokushohoRepresentative | tokushoho_representative | JP | 特定商取引法 대표자 |
| ein | ein | US | Employer Identification Number |
| stateTaxId | state_tax_id | US | State Tax ID |
| vatNumber | vat_number | EU | VAT 번호 |
Nested: MarketSeo
마켓별 SEO 메타데이터.
| 필드 | DynamoDB Attribute | 타입 | 설명 |
|---|
| title | title | String | SEO 제목 |
| description | description | String | SEO 설명 |
| imageUrl | image_url | String | OG 이미지 URL |
Nested: PlatformLink
소셜 미디어 / 마켓플레이스 링크. platform_links 리스트의 각 항목.
| 필드 | DynamoDB Attribute | 타입 | 설명 |
|---|
| platform | platform | String | PredefinedPlatform enum name 또는 "CUSTOM" |
| label | label | String | 커스텀 링크일 때만 사용 (predefined는 null) |
| url | url | String | 플랫폼 URL |
Enum: PredefinedPlatform
| 값 | 설명 |
|---|
INSTAGRAM | Instagram |
FACEBOOK | Facebook |
YOUTUBE | YouTube |
TIKTOK | TikTok |
TWITTER | Twitter / X |
BLOG | Blog |
KAKAO_CHANNEL | Kakao Channel |
AMAZON | Amazon |
SHOPEE | Shopee |
NAVER_SMARTSTORE | Naver Smartstore |
COUPANG | Coupang |
관련 엔티티
| 엔티티 | 관계 | 설명 |
|---|
| User | USER#{userId} PK로 Shop List 레코드 저장 | 소유자 관계 |
| Organization | GSI1으로 Organization별 Shop 조회 | 소속 관계 |
| ShopMarketProfile | 동일 파티션 (SHOP#{shopId}, SK=MARKET_PROFILE#{marketCode}) | 마켓별 프로필 (표시 이름, 사업자 정보, SEO, 로고 등) |
| ShopOnboarding | 동일 파티션 (SHOP#{shopId}, SK=ONBOARDING) | HAPPEN/EXPLODE 온보딩 추적 |
| ShopVersion | 동일 파티션 (SHOP#{shopId}, SK=VERSION#...) | HCS 디자인 버전 관리 |
| UserOnboarding | FIRST_SHOP_CREATED 트리거 | Shop 생성 시 BEGIN 온보딩 완료 |
미구현 (계획)
ShopBranding (Deprecated)
ShopBranding (description, logoUrl, bannerImageUrl)은 deprecated. 브랜딩 데이터는 마켓별 ShopMarketProfile이 canonical source:
description → ShopMarketProfile.description
logoUrl → ShopMarketProfile.logos
bannerImageUrl → ShopMarketProfile.representativeImageUrl
faviconUrl → ShopMarketProfile.faviconUrl
신규 코드는 ShopMarketProfile만 참조할 것. 기존 소비처 마이그레이션 완료 후 Shop entity에서 branding 필드 제거 예정.
참조