← 홈으로 돌아가기

Rankly API 변경 이력 (Changelog)

이 문서는 사람이 읽는 요약입니다. 스키마·요청·응답 필드의 기계-readable 1차 명세Swagger UIOpenAPI JSON을 기준으로 합니다.


2026-09-01

관리자 행동 분석 세션 지표

UserLog 민감정보 마스킹

2026-08-31

스토어 목록 순위 이력 HTTP 캐시

네이버 순위 프록시 기본값 Flashproxy

2026-08-25

스토어 목록 순위 이력 부착·캐시

2026-08-24

네이버 쇼핑 순위 조회 — plus_slot HTTP/2·HTTP/1.1 하이브리드

2026-08-21

로그인 실시간 조회는 400위까지 정확 순위

운영 테스트 계정은 무료 휴면 제외

2026-08-20

비로그인 공개 조회 한도 5→2

무료 한도 축소·삭제 미복구·7일 휴면

슬롯 그룹 — platform_name_en · 슬롯 수/slot_ids · 이동 실패 400


2026-08-13

유료 전환 상담 퍼널·Place 공유 URL 정합


2026-08-10

무료 플랜: 슬롯 재수집 일 2회 · /slots/{id}/run 쿼터 적용


2026-08-06

관리자 활동 로그: SlotRankLog 배치가 목록을 잠식하던 문제 수정

API 무응답 장애 대응: 순위 스케줄러 분리·공유 캐시·gthread

17:00 KST 전체 슬롯 순위 배치가 gunicorn 워커를 모두 점유해 API가 무응답이 된 장애의 후속 조치입니다.

공개 순위조회: 모바일 스마트스토어 URL·빈 키워드·플레이스 예산

2026-08-05

플레이스 순위 로그: 스캔완료 vs 통신실패 구분 (f1 정렬)

공개 순위조회: 검증·통신 실패 시 일일 한도 미소모

로그인 시 공개 실시간 순위조회 일 40회

슬롯 생성 URL 검증 오류를 JSON으로 통일

2026-08-04

관리자 사용자별 슬롯·활동 데이터 격리

네이버 쇼핑 400위 페이징 누락 수정

네이버 가격비교 상품 매칭 정보 공개

GA4 Measurement ID + 관리자 성장 지표

구분 내용
env GA_MEASUREMENT_ID (기본 G-V6TZ8H8KRG). FE는 NEXT_PUBLIC_GA_MEASUREMENT_ID
GET /api/v1/admin/analytics/growth 가입 전환·재방문·순위조회→가입·가입→슬롯 + GA4 콘솔 링크·이탈 페이지
하위호환 신규 엔드포인트. summary/funnel 유지
테스트 commons.tests.test_analytics_api.AdminAnalyticsAPITest.test_growth_200

신뢰 정합: 무료 10슬롯·공개 요금제·플레이스/쿠팡 공개 조회

구분 내용
무료 플랜 FREE_PLAN_BASE_SLOTS=10 (utils·한도 헬퍼·가입 카피 통일). migration 0008_align_public_slot_plans
공개 요금제 Free(기본 slot)·Basic(150/15,900)·Pro(500/35,900) visible=True upsert — FE 폴백 허위 노출 방지
POST .../check_public place 45초 전체 예산. 초과·예외 시 result_status=transport_failed + 안내 (FE hang 완화)
POST .../check_public coupang 준비중 고정 응답 (크롤 시도하지 않음)
preview_url / 상품 메타 __PRELOADED_STATE__ 없을 때 og:title / title 폴백으로 name 채움
하위호환 응답 필드 추가만. breaking 없음

공개 네이버 순위: 40위 정확 + 41~400 구간 안내

구분 내용
POST /api/v1/slots/rank/check_public (naver) msearch로 최대 400위까지 탐색. 40위 이내result_status=ranked + 정확한 rank
41~400 result_status=ranked_band, found=true, rank=null, rank_range_low/high(50단위, 예: 250~300), signup_required=true
미발견 out_of_range + 회원가입 유도 (정확한 깊은 순위는 가입 후)
하위호환 rank_range_*는 optional 추가. 기존 serp_top40 유지
테스트 test_public_rank_check_naver, test_public_rank_check_http
FE ranked_band / rank_range_low / rank_range_high UI 동기 권장

2026-08-03

공개 네이버 순위 40위 한도 + 쇼핑 OpenAPI 종료

구분 내용
POST /api/v1/slots/rank/check_public (naver) cert 1페이지(오가닉 최대 40위). 미발견 시 result_status=out_of_range, signup_required=true, 회원가입·슬롯 등록 유도 메시지
serp_top40 동일 응답에 상위 목록 {rank,title,image_url,mall_name,price,is_matched}[] (신뢰 UI용, 내부 ID 미노출)
로그인·슬롯 cert 기본 최대 400위 (AUTH_MAX_PAGE=10)
쇼핑 OpenAPI openapi.naver.com/v1/search/shop 사용 중단(네이버 서비스 종료). 폴백 제거 — 상세 docs/ai/naver-shopping-openapi-retired.md
테스트 test_public_rank_check_*, test_cert_rank_day_cache (40위 초과 시 순위 미노출)
FE signup_required / serp_top40로 목록·가입 유도 UI 동기 (rankly_FE)

공개 순위체크 cert 고정 + 키워드 일 캐시 + 활동로그 outcome

구분 내용
POST /api/v1/slots/rank/check_public (naver) cert SERP 경로. 응답에 product_name, result_status(ranked|out_of_range|transport_failed), 미발견 시 rank=-1
SERP 캐시 cert_rank — 프로세스 캐시 + Redis 일자 키 naver_serp:day:{YYYY-MM-DD}:{kw} (TTL NAVER_CERT_SERP_DAY_TTL_SEC, 기본 36h)
커맨드 python manage.py warm_public_rank_cache --days 3 — Analytics 공개 조회를 cert로 재측정·캐시 워밍 (--dry-run 지원)
Analytics rank_check_activity.params.outcome (ranked|out_of_range|failed|rate_limited). 관리자 activity API에 outcome 노출
cert producer Google Chrome + FlashProxy 한국 sticky 세션을 사용하는 독립 cert-minter 컨테이너 추가. 캡챠 완료 후 WTM 쿠키와 딥페이지 요청 헤더를 캡처
테스트 slots.tests.test_cert_rank_day_cache, slots.tests.test_public_rank_check_naver, slots.tests.test_public_rank_check_http, slots.tests.test_naver_cert_minter

2026-07-20

Billing Phase 1 — iOS 슬롯 구독 MVP

구분 내용
신규 앱 독립 billing 앱 및 신규 테이블(기존 subscriptions 변경 없음)
GET /api/v1/billing/entitlements/me JWT 사용자의 IAP 구독 상태, 플랜, 활성 슬롯 한도 조회
POST /api/v1/billing/purchases/verify iOS transaction_id를 Apple App Store Server API로 재조회·검증 후 entitlement 갱신
운영 Django Admin에서 Plan, StoreProduct, Subscription, 거래, 수기 권한, entitlement 조회·수기 권한 철회
설정 APPLE_APP_STORE_ISSUER_ID, APPLE_APP_STORE_KEY_ID, APPLE_APP_STORE_PRIVATE_KEY, APPLE_APP_STORE_BUNDLE_ID — 모두 서버 환경변수
제외 기존 웹/계좌이체 구독 통합은 후속 SPEC

초기 월간 상품은 Basic(150 슬롯, com.rankly.sub.slot.3.monthly)과 Pro(500 슬롯, com.rankly.sub.slot.10.monthly)이며, iOS bundle ID는 dev.tuist.RankLog다. 활성 또는 grace 상태의 IAP 구독이 있으면 슬롯 생성 검증에서 해당 플랜의 고정 한도를 우선 적용한다.

Billing Phase 2 — Apple 알림 동기화

구분 내용
POST /internal/billing/webhooks/apple 인증 없음. Apple Notifications V2의 JWS 및 x5c 인증서 체인 검증 후 동기 처리
멱등성 notificationUUIDWebhookEvent의 외부 이벤트 키로 사용해 중복 수신은 2xx 종료
운영 실패 이벤트는 Admin 재처리 가능. revalidate_billing_subscriptions는 운영자 수동 진단용
설정 APPLE_APP_STORE_ROOT_CERTIFICATE(PEM), 선택 BILLING_ALERT_DISCORD_WEBHOOK_URL

2026-07-15

카카오 로그인 — client_secret + 오류 코드 세분화

구분 내용
env KAKAO_CLIENT_SECRET (선택·콘솔 ON 시 필수). settings 기본값 없음 — env만
POST /api/v1/accounts/social/kakao/code 토큰 교환 시 시크릿이 설정돼 있으면 client_secret 포함
400 error KAKAO_CLIENT_SECRET · KAKAO_REDIRECT_URI · KAKAO_INVALID_GRANT · KAKAO_INVALID_CLIENT · KAKAO_CONFIG 등
400 추가 필드 provider_error, provider_error_code (카카오 원문, optional) — 하위호환
테스트 ccounts.tests.test_kakao_oauth
운영 docker-compose web에 KAKAO_CLIENT_SECRET 설정. FE public env에 넣지 않음

2026-07-14

공개 URL 미리보기 + 플레이스 모바일 크롤

구분 내용
POST /api/v1/slots/rank/preview_url auth=None. body { url }. 플랫폼 자동 판별 후 미리보기(name/image/category/address) + recommended_keywords. 성공 시 IP 일 5회 한도 −1 (check_publicpub_rank:{ip}:{date} 공유)
POST /api/v1/slots/rank/check_public 한도 로직을 공유 헬퍼로 통합. place 분기는 place_rank_utils.get_place_ranking(기본 mobile SSR)
플레이스 크롤 place_mobile_client.py / place_rank_utils.py 추가 (f1_slot_BE8 정합). 쇼핑 크롤 변경 없음
플레이스 추천 칩 상호·업종 + 지역(동/역/권역)×업종 (예: 운정 네일샵)
쇼핑 미리보기 기존 get_product_info_async + related_tags
테스트 slots.tests.test_place_preview_keywords

2026-07-13

제품 웹 분석 (AnalyticsEvent + 관리자 집계)

구분 내용
모델 commons.AnalyticsEvent — session/UTM/dwell/exit (migration commons/0005_analyticsevent)
POST /api/v1/analytics/track 필드 확장: session_id, anonymous_id, dwell_ms, is_exit, utm_*, landing_path. 하위호환 (기존 필드 유지). 전환 이벤트만 AdminEvent에도 요약
GET /api/v1/admin/analytics/summary JWT admin — 방문·체류·Top pages/exits·일별
GET /api/v1/admin/analytics/funnel 방문→순위조회→가입→슬롯→구독 퍼널
GET /api/v1/admin/analytics/sources UTM·리퍼러 + GSC top queries 힌트
GET /api/v1/admin/analytics/alerts 병목 감지 (emit=true 시 AdminEvent)
Rate limit /api/v1/analytics/track 120/분 (폴백)
테스트 commons.tests.test_analytics_api
SPEC docs/specs/product-analytics-insights.md

쿠팡 슬롯 등록·공개 조회 일시 중단

구분 내용
POST /slots/.../create (user create) 플랫폼이 쿠팡이면 503 PLATFORM_UNAVAILABLE — 「쿠팡 슬롯 등록은 현재 준비중입니다.」
POST /slots/rank/check_public platform=coupang이면 503 동일 정책 (공개 체험 차단)
유지 기존 쿠팡 슬롯 cron(_task_coupang)은 변경 없음

네이버 쇼핑 SEO 진단 규칙 API (저장 없음)

구분 내용
엔진 slots/services/seo_diagnostic.py —
ules_version=naver_shopping_seo_v1, 네트워크 없음
POST /slots/diagnostic/seo/evaluate auth=None. keyword + 선택 메타(product_name, image_url, related_tags, rank, found) → 항목별 pass/warn/fail/unknown. IP당 60회/시간 (429 RATE_LIMIT_EXCEEDED)
POST /slots/diagnostic/seo/from-slot JWT. slot_id로 Slot 메타 평가. 네이버 쇼핑 외 플랫폼은 400
정책
elated_tags=null → 태그 규칙 unknown(0점 처리 금지). DiagnosticReport migration 미포함
테스트 slots.tests.test_seo_diagnostic (규칙 + evaluate HTTP 200/400/429, from-slot 권한·플랫폼·404)
SPEC docs/specs/agency-product-diagnostic.md

2026-06-02

보고서 브랜딩 — 배경색·워터마크 필드 추가

구분 내용
모델 UserReportBrandingbackground_color, watermark_enabled, watermark_text, watermark_opacity 추가 — migration accounts/0009_userreportbranding_watermark_fields
GET/PUT /accounts/user/me/report-branding 응답·요청에 배경색(#RRGGBB), 워터마크 on/off·문구·투명도(0.03~0.3) 포함
검증 background_color#RRGGBB, watermark_opacity는 0.03~0.3 범위

2026-06-01

보고서 브랜딩 (계정 단위 저장)

구분 내용
모델 UserReportBranding — migration accounts/0008_userreportbranding
GET /accounts/user/me/report-branding JWT. 회사명·로고 URL/data URL·템플릿·강조색·하단 메모 조회
PUT /accounts/user/me/report-branding JWT. 보고서 브랜딩 설정 저장 (없으면 생성)

2026-05-19

온보딩 · 공개 설정

구분 내용
모델 User.onboarding_step (welcomecompleted) — migration accounts/0007_user_onboarding_step
GET /accounts/user/me/onboarding JWT. 현재 단계·단계별 완료(가입·슬롯·순위 로그 추론 포함)
PATCH /accounts/user/me/onboarding { "step": "profile" \| "first_slot" \| ... } 완료 마킹
POST /accounts/complete-signup signup_source 저장 시 profile 온보딩 단계 자동 반영
GET /accounts/public-config auth=None. kakao_channel_id, kakao_channel_url, support_email
env KAKAO_CHANNEL_PUBLIC_ID, KAKAO_CHANNEL_CHAT_URL (미설정 시 null)

구독 플랜 노출 순서 (sort_order)

구분 내용
모델 SubscriptionPlan.sort_order (INT, default 0) — 작을수록 먼저 노출
마이그레이션 subscriptions/migrations/0006_subscriptionplan_sort_order.py (멱등)
GET /subscriptions/plans 정렬: sort_ordercategoryprice
GET /subscriptions/plans/public 응답에 sort_order 추가, 동일 정렬
POST/PATCH /subscriptions/plans 생성·수정 시 sort_order 입력 가능 (관리자)
하위호환 기존 플랜은 sort_order=0 — 기존 category·price 정렬과 동일하게 동작

2026-04-28

플레이스 N1/N2/N3 지수 통합 (네이버 PlaceSummary.gdid 기반)

구분 내용
모델 SlotRankLog, PlaceSnapshotnaver_index1(Float, nullable), naver_index2, naver_index3 필드 추가
마이그레이션 slots/migrations/0015_add_naver_n123_indexes.py
유틸 rank_utils.fetch_naver_n123(keyword, target_place_id, target_place_name) — 네이버 통합검색 SSR HTML → __APOLLO_STATE__PlaceSummary.gdid 파싱으로 N1/N2/N3 추출. RestaurantListSummary 키워드(맛집/카페 등)는 "{지역} 주변 음식" fallback으로 PlaceSummary 유도
배치 기록 process_slot_item() (slot_rank_api.py), _handle_place() (slot_updater.py) — place 순위 업데이트 시 N1/N2/N3 자동 기록
POST /check_rank place 플랫폼 응답 infonaver_index1, naver_index2, naver_index3 추가
POST /check place 플랫폼 raw 응답에 naver_index1, naver_index2, naver_index3 추가
GET /slots/ranks 히스토리 응답 항목에 naver_index1, naver_index2, naver_index3 추가 (SlotRankMainItemOut)
슬롯 목록 rank_history 각 히스토리 항목에 naver_index1, naver_index2, naver_index3 추가 (SlotRankHistoryItem)
SlotRankLogSchemaOut naver_index1, naver_index2, naver_index3 (Optional[float]) 추가

N1/N2/N3 의미: - N1: 키워드 유사도 지수 (카테고리 기반, 동일 키워드 내 거의 고정) - N2: 관련성/인기도 지수 (장소 고유, fallback에서도 동일 값 유지) - N3: 랭킹 지수 (순위와 강한 상관관계)

fallback 전략: PlaceSummary 미반환 키워드(강남역 맛집, 홍대 카페 등 RestaurantListSummary)의 경우 "{지역} 주변 음식" 검색으로 PlaceSummary를 유도하여 N1/N2/N3 추출. fallback N1/N3는 원본 키워드와 다른 컨텍스트값이지만 N2는 동일.

구독 · 공개 플랜 API

구분 내용
GET /api/v1/subscriptions/plans/public auth=None. 비로그인 가격·랜딩 페이지용 공개 플랜 목록. visible=True · is_active=True 플랜만 반환 (기존 GET /subscriptions/plans 와 동일 필터). 응답 스키마는 SubscriptionPlanPublicOut (created_at 등 운영 메타 제외). 응답 헤더 Cache-Control: public, max-age=300.

2026-04-14

계정 · OTP · 탈퇴

구분 내용
POST /api/v1/accounts/otp/send Celery(delay)가 Redis에서 지연·hang 될 때 약 5초 타임아웃SMTP 스레드 폴백으로 발송. HTTP 응답이 수 초 걸릴 수 있음(정상 범위). 브로커 타임아웃 설정(CELERY_BROKER_*) 보강.
POST /api/v1/accounts/otp/verify (동작 동일) Swagger 설명 보강.
POST /api/v1/accounts/login 탈퇴 유예 중(pending_delete_at 미래, is_active=False) 로그인 허용 — 탈퇴 취소·안내용.
POST /api/v1/accounts/withdraw 유료(플랜 가격이 0보다 큰) 활성 구독만 탈퇴 차단. 무료 구독 자동 해지, 활성 슬롯 INACTIVE 처리. JWT 필수.
POST /api/v1/accounts/withdraw/cancel auth=None. 본문 email + password 권장(JWT 없이 취소). 유예 기간 내 복구, 구독 없으면 기본 무료 구독 재생성. 슬롯은 자동 복구 없음(정책).
JWT ninja_jwt USER_AUTHENTICATION_RULE 커스텀(탈퇴 유예 사용자 인증 허용).
문서 Swagger accounts 태그 엔드포인트 description 대폭 보강. 루트 /docs/accounts-otp-withdraw/ 가이드 추가.

배포 · 인프라

구분 내용
GitHub Actions / Docker docker compose vs docker-compose 분기 명확화.
docker-compose (web) Healthcheck start_period 300s, retries 증가. collectstatic에서 --clear 제거(기동 시간 단축).
discord-bot depends_on.web: service_healthyservice_started (웹 헬스 대기로 배포 전체가 막히지 않도록).

기타 (동일 기간 커밋 로그에 포함된 변경)

운영 메모


2025-12-18 (참고)


이전 이력

세부 커밋은 저장소에서 확인하세요.

git log --oneline -30