Saleor Core 분석: GraphQL / Settings / Dependencies

분석 대상: saleor v3.24.0-a.0 (/tmp/saleor-core/) 작성일: 2026-03-27


1. GraphQL Layer Architecture

1.1 전체 구조

saleor/graphql/
├── api.py                  # Root schema 정의 (Query, Mutation, Subscription 조합)
├── views.py                # Django View → GraphQL 실행 엔드포인트
├── middleware.py            # Django middleware (GraphQLView 감지)
├── context.py               # SaleorContext 생성 (dataloaders, auth, replica 설정)
├── decorators.py            # permission_required, account_passes_test 등
├── query_cost_map.py        # 필드별 cost map
├── metrics.py               # OTel 기반 메트릭 수집
├── promise.py               # graphql-core-legacy Promise 패치
├── core/                    # 공용 인프라
│   ├── mutations.py         # BaseMutation, DeprecatedModelMutation, ModelDeleteMutation
│   ├── types/               # ModelObjectType, NonNullList, File, Upload 등
│   ├── fields.py            # BaseField, ConnectionField, FilterConnectionField
│   ├── connection.py        # Relay connection 유틸
│   ├── enums.py             # 공통 enum (LanguageCodeEnum 등)
│   ├── scalars.py           # PositiveDecimal, UUID 등 커스텀 스칼라
│   ├── validators/          # query_cost.py (CostValidator), file.py
│   ├── federation/          # Apollo Federation v1 지원 (_Entity, _Service, _Any)
│   ├── dataloaders.py       # 기본 dataloader 패턴
│   ├── filters/             # django-filter 기반 GraphQL 필터
│   └── doc_category.py      # @doc directive 카테고리 매핑
├── account/                 # 도메인별 schema 모듈
├── checkout/
├── order/
├── product/
├── payment/
├── shipping/
├── warehouse/
├── webhook/
├── ... (app, attribute, channel, csv, discount, giftcard, invoice, menu, meta, page, plugins, shop, tax, translations)
└── tests/

1.2 Schema 빌드 흐름

api.py
  ├── Query(AccountQueries, AppQueries, ..., WebhookQueries)    # 22개 도메인 Queries mixin
  ├── Mutation(AccountMutations, ..., WebhookMutations)          # 23개 도메인 Mutations mixin
  ├── Subscription                                                # webhook subscription types
  └── build_federated_schema(Query, Mutation, types, subscription, directives)
        └── Apollo Federation v1 래핑 (_Entity union, _Service SDL)

schema = build_federated_schema(...)
backend = GraphQLCachedBackend(SaleorGraphQLBackend(), cache_map=CacheDict(1000))

핵심 포인트:

  • graphql-core v2 (legacy) + graphene v2 기반. graphql-core v3 / graphene v3 아님.
  • GraphQLCachedBackend로 파싱/검증 결과를 LRU 캐시 (1000 entries)
  • Apollo Federation v1 프로토콜 내장 (_entities, _service { sdl })

1.3 Request 처리 파이프라인

HTTP POST /graphql/
  │
  ├─ Django Middleware Chain
  │   ├── SecurityMiddleware
  │   ├── CommonMiddleware
  │   └── jwt_refresh_token_middleware
  │
  ├─ GraphQLView.dispatch()
  │   ├── handle_query() — OTel span + 메트릭 계측
  │   ├── parse_body() — orjson 파싱 (multipart file upload 지원)
  │   ├── execute_graphql_request()
  │   │   ├── parse_query() — backend.document_from_string() (캐시 히트 여부)
  │   │   ├── validate_query_cost() — CostValidator (max: GRAPHQL_QUERY_MAX_COMPLEXITY)
  │   │   ├── get_context_value() — SaleorContext 구성
  │   │   │   ├── dataloaders = {}
  │   │   │   ├── set_app_on_context()
  │   │   │   ├── set_auth_on_context()
  │   │   │   └── set_decoded_auth_token()
  │   │   └── document.execute(context, middleware=[...])
  │   │       └── GraphQL Middleware (GRAPHQL_MIDDLEWARE 설정, 기본값 빈 리스트)
  │   └── clear_context() — dataloader 캐시 / reference cycle 정리
  │
  └─ JsonResponse (orjson 직렬화, UTC_Z 옵션)

1.4 Mutation 구조 패턴

계층:

graphene.Mutation
  └── BaseMutation                    # 권한 체크, 에러 핸들링, 메타데이터 지원
        └── DeprecatedModelMutation   # Django Model 바인딩 (return_field_name, object_type)
              └── ModelDeleteMutation # 삭제 전용

Mutation 작성 패턴 (CheckoutCreate 예시):

class CheckoutCreate(DeprecatedModelMutation, I18nMixin):
    # 1. 반환 필드
    created = graphene.Field(graphene.Boolean, ...)
 
    # 2. Arguments — Input Type으로 래핑
    class Arguments:
        input = CheckoutCreateInput(required=True, ...)
 
    # 3. Meta — 모든 mutation에 필수
    class Meta:
        description = "Create a new checkout."
        doc_category = DOC_CATEGORY_CHECKOUT
        model = models.Checkout               # Django 모델
        object_type = Checkout                 # GraphQL 타입
        return_field_name = "checkout"         # 응답 필드명
        error_type_class = CheckoutError       # 에러 타입
        error_type_field = "checkout_errors"   # deprecated 에러 필드
        webhook_events_info = [...]            # 트리거되는 webhook 이벤트
        # permissions = (...)                  # 필요시 튜플로 지정
 
    # 4. 비즈니스 로직
    @classmethod
    def perform_mutation(cls, root, info, **data):
        # clean → validate → save → trigger webhook
        ...

핵심 규칙:

  • permissions 튜플이 있으면 mutate() 진입 시 자동 체크 → PermissionDenied 발생
  • perform_mutation() 내에서 ValidationError 발생 시 → handle_errors()가 에러 타입 변환
  • webhook_events_info가 description에 자동 추가됨 (Webhooks 참조)
  • doc_category@doc directive에 매핑

1.5 Resolver 패턴

Query 정의 (schema.py):

class CheckoutQueries(graphene.ObjectType):
    checkout = BaseField(
        Checkout,
        id=graphene.Argument(graphene.ID),
        permissions=[CheckoutPermissions.MANAGE_CHECKOUTS, ...],
        doc_category=DOC_CATEGORY_CHECKOUT,
    )
    checkouts = FilterConnectionField(
        CheckoutCountableConnection,
        sort_by=..., filter=..., channel=...,
        permissions=[CheckoutPermissions.MANAGE_CHECKOUTS],
    )

Resolver 구현 (resolvers.py):

@traced_resolver
def resolve_checkout(info, token, id):
    validate_one_of_args_is_in_query("id", id, "token", token)
    # DataLoader 사용 → Promise chain
    return CheckoutByTokenLoader(info.context).load(token).then(with_checkout)

특징:

  • DataLoader 패턴이 핵심. 모든 관계 필드는 dataloader로 해결 (N+1 방지)
  • SyncWebhookControlContext로 노드를 래핑하여 sync webhook 호출 여부 제어
  • get_database_connection_name()으로 replica DB 라우팅
  • @traced_resolver 데코레이터로 OTel tracing

1.6 Permission 체크 패턴

# Mutation level — Meta.permissions 튜플
class Meta:
    permissions = (OrderPermissions.MANAGE_ORDERS,)
 
# BaseMutation.mutate() 내부:
if not cls.check_permissions(info.context, data=data):
    raise PermissionDenied(permissions=cls._meta.permissions)
 
# check_permissions() 기본 동작:
# - permissions가 없으면 True (공개 mutation)
# - one_of_permissions_or_auth_filter_required() — OR 로직 (하나만 만족하면 OK)
# - require_all_permissions=True면 AND 로직
 
# Query level — BaseField / FilterConnectionField의 permissions 인자
checkout = BaseField(Checkout, permissions=[...])
 
# Resolver level — 데코레이터 or 직접 체크
@permission_required(OrderPermissions.MANAGE_ORDERS)
def resolve_orders(root, info, **kwargs): ...

1.7 에러 처리 패턴

ValidationError (Django)
  ↓ validation_error_to_error_type()
  ↓ error_dict 순회 → snake_to_camel_case 변환
GraphQL Error Type (e.g., CheckoutError)
  ├── field: String        (camelCase 필드명)
  ├── message: String      (에러 메시지)
  ├── code: ErrorCodeEnum  (예: INVALID, NOT_FOUND, REQUIRED)
  └── 추가 params (에러 타입별)

# 모든 mutation 응답에 포함:
{
  errors: [CheckoutError!]!          # 현재 표준
  checkoutErrors: [CheckoutError!]!  # deprecated (하위호환)
}

1.8 Query Cost Validation

  • CostValidator (graphql-core ValidationRule)
  • 기본 max complexity: 50,000 (GRAPHQL_QUERY_MAX_COMPLEXITY)
  • COST_MAP 딕셔너리로 타입/필드별 cost 정의
  • 응답 extensions에 { cost: { requestedQueryCost, maximumAvailable } } 포함

2. Settings 카탈로그

2.1 Environment Variables 전체 목록

변수명기본값설명
Core
DEBUGTrueDjango 디버그 모드
SECRET_KEY랜덤 (DEBUG=True 시)필수. production에서 반드시 설정
ALLOWED_HOSTSlocalhost,127.0.0.1Django ALLOWED_HOSTS
ALLOWED_CLIENT_HOSTSlocalhost,127.0.0.1CORS 허용 호스트. DEBUG=False 시 필수
ALLOWED_GRAPHQL_ORIGINS*GraphQL 요청 허용 origin
PUBLIC_URL(없음)Saleor API 공개 URL (설정 시 ENABLE_SSL 무시)
ENABLE_SSLFalseHTTPS 리다이렉트
INTERNAL_IPS127.0.0.1내부 IP 목록
DEFAULT_COUNTRYUS기본 국가 코드
DEFAULT_CHANNEL_SLUGdefault-channel기본 채널 slug
POPULATE_DEFAULTSTrue마이그레이션 시 기본 데이터 생성
REAL_IP_ENVIRONREMOTE_ADDR실제 IP 헤더 (프록시 환경)
Database
DATABASE_URLpostgres://saleor:saleor@localhost:5432/saleor기본 DB
DATABASE_URL_REPLICA(DATABASE_URL 사용)읽기 전용 replica DB
DB_CONN_MAX_AGE0DB 커넥션 유지 시간 (초)
Cache / Redis
CACHE_URL(없음)Redis 캐시 URL
REDIS_URL(없음)Redis URL (CACHE_URL 대체)
CACHE_TIMEOUT7 days캐시 TTL
Celery
CELERY_BROKER_URL(없음)Celery 브로커 URL (Redis/SQS/AMQP)
CELERY_RESULT_BACKENDNone결과 백엔드
CELERY_WORKER_PREFETCH_MULTIPLIER1워커 프리페치
Email
EMAIL_URL(없음)이메일 SMTP URL
DEFAULT_FROM_EMAILnoreply@example.com발신 이메일
SENDGRID_USERNAME / SENDGRID_PASSWORD(없음)SendGrid 인증
USER_EMAIL_URL(없음)사용자 이메일 플러그인 SMTP
JWT
RSA_PRIVATE_KEY(없음)JWT 서명용 RSA 키
RSA_PRIVATE_PASSWORD(없음)RSA 키 비밀번호
JWT_MANAGER_PATHsaleor.core.jwt_manager.JWTManagerJWT 매니저 클래스
JWT_TTL_ACCESS5 minutesAccess token TTL
JWT_TTL_APP_ACCESS5 minutesApp access token TTL
JWT_TTL_REFRESH30 daysRefresh token TTL
JWT_TTL_REQUEST_EMAIL_CHANGE1 hour이메일 변경 토큰 TTL
GraphQL
GRAPHQL_QUERY_MAX_COMPLEXITY50000쿼리 cost 상한 (0=비활성)
FEDERATED_QUERY_MAX_ENTITIES100Federation 엔터티 최대 수
GRAPHQL_CACHE_SUFFIX""스키마 캐시 무효화 접미사
PLAYGROUND_ENABLEDTrueGraphQL Playground UI
Storage (AWS)
AWS_ACCESS_KEY_ID(없음)AWS 인증
AWS_SECRET_ACCESS_KEY(없음)AWS 시크릿
AWS_MEDIA_BUCKET_NAME(없음)미디어 버킷
AWS_MEDIA_PRIVATE_BUCKET_NAME(없음)비공개 미디어 버킷
AWS_STORAGE_BUCKET_NAME(없음)정적 파일 버킷
AWS_S3_ENDPOINT_URL(없음)S3 호환 엔드포인트
AWS_S3_REGION_NAME(없음)S3 리전
AWS_QUERYSTRING_AUTHFalse서명된 URL
AWS_DEFAULT_ACLNone기본 ACL
AWS_S3_FILE_OVERWRITETrue파일 덮어쓰기
Storage (GCS)
GS_PROJECT_ID(없음)GCS 프로젝트 ID
GS_BUCKET_NAME(없음)GCS 버킷
GS_MEDIA_BUCKET_NAME(없음)미디어 버킷
GS_MEDIA_PRIVATE_BUCKET_NAME(없음)비공개 미디어 버킷
GS_EXPIRATION1 day서명 URL 만료 시간
Storage (Azure)
AZURE_ACCOUNT_NAME(없음)Azure 스토리지 계정
AZURE_ACCOUNT_KEY(없음)계정 키
AZURE_CONTAINER(없음)공개 컨테이너
AZURE_CONTAINER_PRIVATE(없음)비공개 컨테이너
Checkout
ANONYMOUS_CHECKOUTS_TIMEDELTA30 days익명 체크아웃 만료
USER_CHECKOUTS_TIMEDELTA90 days사용자 체크아웃 만료
EMPTY_CHECKOUTS_TIMEDELTA6 hours빈 체크아웃 만료
CHECKOUT_PRICES_TTL1 hour가격 캐시 TTL
CHECKOUT_DELIVERY_OPTIONS_TTL24 hours배송 옵션 캐시 TTL
CHECKOUT_TTL_BEFORE_RELEASING_FUNDS6 hours결제 해제 대기
CHECKOUT_COMPLETION_LOCK_TIME3 minutes완료 처리 lock 시간
AUTOMATIC_CHECKOUT_COMPLETION_DELAY30 (분)자동 완료 지연
CHECKOUT_SEARCH_UPDATE_PARALLEL_TASKS5검색벡터 병렬 작업 수
Webhook
WEBHOOK_CELERY_QUEUE_NAME(없음)비동기 webhook
WEBHOOK_DEFERRED_PAYLOAD_QUEUE_NAME(없음)지연 페이로드 큐
WEBHOOK_SQS_CELERY_QUEUE_NAME(WEBHOOK_CELERY_QUEUE_NAME)SQS webhook 큐
WEBHOOK_PUBSUB_CELERY_QUEUE_NAME(WEBHOOK_CELERY_QUEUE_NAME)PubSub webhook 큐
CHECKOUT_WEBHOOK_EVENTS_CELERY_QUEUE_NAME(WEBHOOK_CELERY_QUEUE_NAME)체크아웃 webhook 큐
ORDER_WEBHOOK_EVENTS_CELERY_QUEUE_NAME(WEBHOOK_CELERY_QUEUE_NAME)주문 webhook 큐
Observability
OBSERVABILITY_BROKER_URL(없음)관측성 브로커 URL
OBSERVABILITY_REPORT_ALL_API_CALLSFalse전체 API 콜 리포트
OBSERVABILITY_MAX_PAYLOAD_SIZE25000최대 페이로드 크기
OBSERVABILITY_BUFFER_SIZE_LIMIT1000버퍼 크기 제한
OBSERVABILITY_BUFFER_BATCH_SIZE100배치 크기
OBSERVABILITY_REPORT_PERIOD20 seconds리포트 주기
OBSERVABILITY_BUFFER_TIMEOUT5 minutes버퍼 타임아웃
Sentry
SENTRY_DSN(없음)Sentry DSN
Security
HTTP_IP_FILTER_ENABLEDTruewebhook 호출 시 사설 IP 차단
HTTP_IP_FILTER_ALLOW_LOOPBACK_IPSFalse루프백 IP 허용
RESET_PASSWORD_LOCK_TIME15 minutes비밀번호 초기화 lock
CONFIRMATION_EMAIL_LOCK_TIME15 minutes확인 이메일 lock
Memory
SOFT_MEMORY_LIMIT_IN_MB(없음)프로세스 힙 소프트 제한
HARD_MEMORY_LIMIT_IN_MB(없음)프로세스 힙 하드 제한
Beat schedules
BEAT_EXPIRE_ORDERS_AFTER_TIMEDELTA5 minutes주문 만료 체크 주기
BEAT_UPDATE_SEARCH_FREQUENCY20 seconds검색 인덱스 갱신 주기
BEAT_PRICE_RECALCULATION_SCHEDULE30 seconds가격 재계산 주기
EVENT_PAYLOAD_DELETE_PERIOD14 days이벤트 페이로드 보관 기간
DELETE_APP_TTL1 day삭제 앱 보관 기간
기타
MAX_USER_ADDRESSES100사용자당 최대 주소 수
EXPORT_FILES_TIMEDELTA30 days내보내기 파일 보관 기간
ORDER_RULES_LIMIT100주문 규칙 최대 수
GIFTS_LIMIT_PER_RULE500규칙당 최대 선물 수
EDITOR_JS_LISTS_MAX_DEPTH10EditorJS 중첩 리스트 최대 깊이
SEND_USAGE_TELEMETRYTrue사용 텔레메트리 전송
BREAKER_BOARD_ENABLEDFalseCircuit breaker 활성화
BREAKER_BOARD_SYNC_EVENTS(없음)모니터링 대상 sync webhook
UPLOAD_ADDITIONAL_ALLOWED_MIME_TYPES{}추가 허용 MIME 타입 (JSON)
TELEMETRY_SLOW_GRAPHQL_OPERATION_THRESHOLD1.0 (초)느린 쿼리 임계값

2.2 Database 설정

  • 엔진: PostgreSQL (psycopg v3, binary 모드)
  • Primary-Replica 라우팅: PrimaryReplicaRouter (saleor.core.db_routers)
    • DATABASE_URL → default (read/write)
    • DATABASE_URL_REPLICA → replica (read-only)
    • allow_replica 플래그로 context에서 제어
  • Connection pooling: DB_CONN_MAX_AGE=0 (기본값, 요청마다 새 커넥션)
    • Production에서는 반드시 증가 권장 (e.g., 600)

2.3 Celery / Redis 설정

  • Broker: Redis, SQS, AMQP 지원
  • CELERY_TASK_ALWAYS_EAGER = not CELERY_BROKER_URL — 브로커 미설정 시 동기 실행
  • Beat Schedule: 16개 이상의 정기 작업
    • 검색 인덱스 갱신 (20초), 만료 체크아웃/주문 삭제, 재고 할당 정리, 가격 재계산 등
  • 도메인별 큐 분리 가능 (webhook, checkout, order, search 등)

3. Dependencies 분석

3.1 핵심 의존성

패키지버전 제약위험도비고
django~=5.2.11낮음최신 LTS. 안정적
graphene<3.0높음v2에 잠김. graphene v3는 API 호환 안 됨
graphql-core>=2.3.2,<3높음Legacy v2. 커뮤니티 지원 사실상 종료
graphql-relay>=2.0.1,<3높음graphql-core v2 전용
psycopg[binary]>=3.2.9,<4낮음PostgreSQL 드라이버 (최신)
celery[redis,sqs]>=4.4.5,<6낮음넓은 범위, 안정적
redis>=5.0.1,<6낮음
pydantic>=2.11.0,<3낮음
sentry-sdk~=2.12낮음
opentelemetry-*>=1.32.1,<2 / >=0.53b1중간Beta 버전 의존
Rx>=1.6.3,<2높음RxPY v1, graphql-core v2 의존
promise~=2.3높음graphql-core v2 Promise 패턴
pillow>=12.1.1,<13낮음
boto3~=1.28낮음AWS SDK
stripe>=3.0.0,<4중간v3에 잠김 (현재 최신 v11+)
braintree>=4.2,<4.32낮음
requests-hardened>=1.0.0,<2낮음SSRF 방지
orjson>=3.11.4낮음고성능 JSON 직렬화
authlib>=1.6.9,<2낮음OAuth/OIDC
petl==1.7.17중간정확한 버전 pin (CSV 처리)

3.2 Legacy GraphQL Stack 위험 평가

가장 큰 기술 부채:

graphene <3.0  ←→  graphql-core >=2.3.2,<3  ←→  graphql-relay >=2.0.1,<3
                          ↕
                    promise ~=2.3
                    Rx >=1.6.3,<2
  • graphql-core v2는 2020년 이후 유지보수만 (버그픽스 수준)
  • Saleor 자체적으로 graphql_core.py, promise.py에서 monkey-patching하여 메모리 누수 대응
  • patch_executor(), patch_execution_context(), patch_execution_result(), patch_promise() 등 5개 이상의 런타임 패치
  • graphql-core v3 마이그레이션은 graphene v3 전환과 동시에 필요하며 사실상 전체 GraphQL 계층 재작성에 해당

3.3 문제성 핀 버전

패키지제약문제
petl==1.7.17정확한 버전 pin보안 패치 적용 어려움
graphene<3.0메이저 버전 상한graphene v3 전환 불가
stripe>=3.0.0,<4v3에 잠김최신 Stripe API 기능 사용 불가
opentelemetry-semantic-conventions>=0.53b1,<0.54beta 버전 마이너 범위OTel 업그레이드 시 충돌 가능

3.4 Python 버전

  • requires-python = ">=3.12,<3.13" — Python 3.12 전용
  • Docker 이미지: python:3.12 / python:3.12-slim
  • 패키지 매니저: uv (lockfile: uv.lock)

4. Docker / Deployment

4.1 Dockerfile 분석

빌드 스테이지: python:3.12 + uv 패키지 매니저
  → uv sync --locked (lockfile 기반 재현성)
  → collectstatic

런타임 스테이지: python:3.12-slim
  → uvicorn ASGI 서버
  → Port 8000
  → Workers: 2
  → Request 제한: 10,000 요청 후 워커 재시작
  → Keep-alive: 35초
  → Graceful shutdown: 30초

4.2 서비스 구성 요소

컴포넌트실행 명령
API 서버uvicorn saleor.asgi:application
Celery Workercelery --app saleor.celeryconf:app worker -E
Celery Beatcelery --app saleor.celeryconf:app beat --scheduler saleor.schedulers.schedulers.DatabaseScheduler

4.3 외부 서비스 의존

  • PostgreSQL — 필수
  • Redis — 캐시 + Celery 브로커 (또는 SQS/AMQP)
  • Object Storage — AWS S3 / GCS / Azure Blob (선택)
  • Sentry — 에러 트래킹 (선택)
  • SMTP — 이메일 발송 (선택)

5. 한국 로컬라이제이션 설정 가이드

5.1 언어 지원 현황

saleor/core/languages.py("ko", "Korean")("ko-kr", "Korean (South Korea)") 포함됨. Saleor의 Translation 시스템으로 제품/카테고리/페이지 등의 한국어 번역 가능.

5.2 권장 환경 변수 설정

# 기본 국가
DEFAULT_COUNTRY=KR
 
# 채널 설정 — Saleor는 통화를 채널 단위로 관리
# 채널 생성 시 currency_code="KRW" 설정
 
# 타임존은 settings.py에서 UTC 고정 (Saleor 권장)
# 프론트엔드에서 KST 변환 처리
 
# 주소 검증 — google-i18n-address가 한국 주소 형식 지원
# i18n_rules_override()로 커스텀 가능

5.3 통화(KRW) 고려사항

  • DEFAULT_DECIMAL_PLACES = 3 → KRW는 소수점 없음. 채널별 currency_code 설정으로 처리됨
  • Saleor의 가격 처리채널(Channel) 단위. 원화 채널 생성 시 자동으로 KRW 통화 적용
  • Stripe, Razorpay 등 결제 게이트웨이의 KRW 지원 여부 별도 확인 필요

5.4 주소 형식

  • django-countries + google-i18n-address 조합
  • 한국 주소 형식 (도/시/구/동) 지원
  • i18n_rules_override()를 통한 한국 주소 검증 규칙 커스터마이즈 가능
  • phonenumber_field가 한국 전화번호 형식 지원 (Address 참조)

6. Fork 준비 체크리스트

6.1 즉시 변경 필요

  • SECRET_KEY 재생성 (절대 공유하지 않을 것)
  • DEFAULT_COUNTRY=KR 설정
  • 한국어 채널 생성 (currency=KRW, language=ko)
  • ALLOWED_CLIENT_HOSTS, ALLOWED_HOSTS, PUBLIC_URL 프로덕션 값 설정
  • DEBUG=False 확인
  • SEND_USAGE_TELEMETRY=False (Saleor 텔레메트리 비활성화)
  • PLAYGROUND_ENABLED=False (프로덕션)
  • RSA 키 생성 및 RSA_PRIVATE_KEY 설정

6.2 인프라 준비

  • PostgreSQL 15+ 프로비저닝 (replica 구성 권장)
  • Redis 7+ 프로비저닝 (캐시 + Celery 브로커)
  • Object Storage 선택 및 설정 (AWS S3 / GCS / Azure / MinIO)
  • Celery Worker + Beat 프로세스 배포 구성
  • DB_CONN_MAX_AGE 조정 (프로덕션: 300-600 권장)
  • Sentry DSN 설정

6.3 GraphQL 계층 커스터마이징 시 주의사항

  • 새 도메인 추가 시: saleor/graphql/{domain}/ 디렉토리 → schema.py, types.py, mutations/, resolvers.py 구조 따를 것
  • api.py의 Query/Mutation mixin에 새 도메인 추가
  • 모든 mutation은 BaseMutation 또는 DeprecatedModelMutation 상속 필수
  • doc_category 설정 (schema 문서화)
  • webhook_events_info 정의 (webhook 자동 문서화)
  • DataLoader 패턴 반드시 사용 (N+1 문제 방지)
  • graphql-core v2 제약 이해: 비동기(async) resolver 미지원

6.4 기술 부채 우선순위

우선순위항목영향도
P0graphql-core v2 → v3 마이그레이션 가능성 평가Saleor upstream에서 미착수. fork 시 독자적 진행 필요
P1stripe SDK v3 → 최신 업그레이드신규 결제 기능 제한
P1DeprecatedModelMutation 정리코드 내부에서도 deprecated로 표기됨
P2petl==1.7.17 pin 해제CSV 내보내기 관련 보안 패치
P3OTel 의존성 beta → stable 전환semantic-conventions 안정화 대기

6.5 Upstream 동기화 전략

  • Saleor는 BSD-3-Clause 라이선스 — fork 후 수정/배포 자유
  • saleor/graphql/ 하위는 변경 빈도가 높음. 커스텀 코드를 별도 앱/모듈로 분리 권장
  • saleor/settings.py 변경은 최소화하고, 환경 변수 또는 별도 settings 파일(saleor/settings_local.py)로 오버라이드
  • migration 충돌 방지: 커스텀 모델은 별도 Django 앱으로 분리

관련 문서

Index

핵심 개념

도메인

확장 및 커스터마이징

설정 및 배포

분석