feat(cafe24): 읽기 지연 보정("마지막 쓰기가 권위") + 상품 정보 패널

증상: 상세페이지를 적용해도 편집기에 수정 전 소스가 보이고 한참 뒤에야
반영됨. 원인은 우리 캐시가 아니라(전부 no-store) 카페24 관리자 API 가 PUT
뒤 한동안 GET 에서 예전 값을 돌려주는 읽기 지연. 예전 코드는 2.4초만
기다린 뒤 GET 값을 그대로 믿어 예전 소스 표시·지문 충돌 오판·예전 값
백업이 생겼다.

- 상세설명: 쓰기 성공 시 MANUAL/SCHEDULED revision 을 기준으로, 카페24 값이
  유예시간 안의 revision 중 하나와 같으면 지연(pending)으로 보고 마지막
  쓰기를 표시·지문 기준으로 쓴다. 모르는 값이면 외부 변경(external).
  store.resolve_description / db.revision_digests(md5) / 배너 2종.
- 적용(apply)은 유효 현재값으로 BACKUP·지문 대조·변경없음 판정. 재조회
  확인 결과는 감사로그에만 남긴다.
- 스칼라(상품명·가격·이미지·진열/판매): PUT 응답을 cafe24_products.
  last_write_snapshot(JSONB, 마이그레이션 004)에 남기고 GET 의 updated_date
  가 그보다 이전이면 스냅샷으로 덮어씀. 옵션/품목도 섹션별 스냅샷.
- 3분할 화면: 목록 | 편집기 | 상품 정보 패널(_side.html, /pane 이 두 조각을
  한 응답으로). routes_product_info.py JSON API — 상품명/판매가/공급가/
  소비자가, 대표이미지 업로드(POST /admin/products/images → PUT detail_image
  + image_upload_type=A), 옵션 생성/이름·썸네일·표시방식 수정/삭제, 품목
  자체코드·추가금액·진열·판매 일괄 수정. 화면은 PUT 응답으로 그린다.
- client.delete/timeout, products.upload_images·options·variants 래퍼.
- 유닛테스트 21건 추가(88 통과), 문서(CAFE24_MODULE 3-3/3-4, DATABASES,
  .env.example CAFE24_READ_LAG_GRACE_MIN) 갱신.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 18:07:42 +09:00
parent 8ea0db9245
commit 40766d805d
21 changed files with 2782 additions and 99 deletions
+17 -1
View File
@@ -80,7 +80,7 @@ def _apply(store_db: Any, api: Any, row: dict[str, Any]) -> str:
# PC/모바일은 구분하지 않는다 — mobile_description 은 보내지 않고
# separated_mobile_description="F" 로 "PC 상세설명과 동일"을 강제한다.
# (mobile_description 을 직접 보내면 카페24가 그 설정을 "직접 등록"으로 바꿔버린다.)
products.update_product(
updated = products.update_product(
api.client,
product_no,
description=html,
@@ -88,10 +88,26 @@ def _apply(store_db: Any, api: Any, row: dict[str, Any]) -> str:
display=set_display,
selling=set_selling,
)
# PUT 응답은 쓰기 직후의 실제 값이다 — 스냅샷으로 남겨 화면이 GET 의 읽기 지연에
# 흔들리지 않게 한다(routes_products._load_product 가 덮어씌운다).
if isinstance(updated, dict) and updated.get("product_no"):
try:
store_db.save_write_snapshot(product_no, "product", store.product_snapshot(updated))
except Exception: # noqa: BLE001 — 스냅샷 실패가 예약 결과를 바꾸면 안 된다.
logger.exception("예약 #%s 상품 %s 스냅샷 저장 실패", schedule_id, product_no)
if html is not None:
# 화면 편집(apply)과 동일 — 카페24 관리자 API 의 쓰기 직후 읽기 지연을
# 여기서 짧게 흡수한다(쇼핑몰에는 바로 반영되지만 관리자 조회만 뒤쳐질 때가 있다).
# 확인이 안 돼도 실패가 아니다 — 화면은 마지막 쓰기(SCHEDULED revision)를 기준으로
# 그린다. 여기서 SCHEDULED revision 을 남겨야 그 기준이 생긴다.
products.wait_for_description(api.client, product_no, html)
store_db.add_revision(
product_no=product_no,
html_content=html,
revision_type=store.REVISION_SCHEDULED,
memo=f"예약 #{schedule_id} 적용",
created_by=ACTOR,
)
summary = store.describe_schedule_action(
has_html=html is not None, set_display=set_display, set_selling=set_selling