feat(backend): 업체 링크별 신청·구매 추적 API 추가

상품마다 업체에 단축 링크를 발급하고, 그 링크로 들어온 회원의 신청·구매를
업체별로 세기 위해서다. 아임웹은 주문 완료를 알려주지 않으므로 구매는
주문 API 를 주기적으로 훑어 찾는다.

- 아임웹 상품 동기화(imweb_products) — 회원 동기화와 같은 주기, 실패해도 회원 동기화는 계속
- 단축 링크 /r/{코드}: 사람의 클릭만 기록하고 클릭 ID(mg_ref)를 붙여 상품 페이지로 이동
  (이동 주소는 아임웹 사이트 안만 허용 — open redirect 방지)
- 회원 ↔ 클릭 연결(POST /api/partner-touches), 신청 기록에 클릭 ID 추가
- 마지막 클릭·30일 귀속, 결제완료 주문만 구매로 집계하고 환불·취소는 제외 (금액은 관리하지 않음)
- 관리자 API: 업체·링크 관리, 링크별 실적 상세, 구매 집계 새로고침
- 권한 요청에 product:read·order:read 추가, 토큰 권한 부족은 IMWEB_006
- 에러 코드 IMWEB_006, PARTNER_001~004 추가 및 클라이언트 사전 동기화

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 23:47:10 +09:00
parent 2f01bea6ef
commit 7bef853664
50 changed files with 3746 additions and 10 deletions
@@ -16,7 +16,12 @@ export const ERROR_CODE_MESSAGES = {
IMWEB_003: '아임웹 연결 요청이 만료되었거나 올바르지 않습니다. 처음부터 다시 연결해 주세요.',
IMWEB_004: '회원 동기화가 이미 진행 중입니다. 잠시 후 다시 확인해 주세요.',
IMWEB_005: '아임웹 연동 설정이 완료되지 않았습니다. 관리자에게 문의해 주세요.',
IMWEB_006: '아임웹 권한이 부족합니다. 연동 관리에서 아임웹 연결을 다시 해 주세요.',
APPLY_001: '회원 정보를 확인할 수 없어 신청을 기록하지 못했습니다.',
PARTNER_001: '이 업체에는 같은 상품의 링크가 이미 있습니다.',
PARTNER_002: '링크가 발급된 업체는 삭제할 수 없습니다. 실적 기록을 지키기 위해 링크를 중지해 주세요.',
PARTNER_003: '이동 주소는 우리 아임웹 사이트 안의 주소여야 합니다.',
PARTNER_004: '같은 이름의 업체가 이미 있습니다.',
} as const
export type ErrorCode = keyof typeof ERROR_CODE_MESSAGES