o2o-site-AEO/solution/backend/router/v1/site/showcase.py
Mina Choi e8cda02a4b [feat] solution/backend,postgres-init: 발행 썸네일 저장 + 공개 쇼케이스 목록 — 랜딩이 실물을 걸 자리
랜딩의 "이렇게 나옵니다" 섹션이 걸 그림이 없었다. 발행은 되는데 그 사이트가
어떻게 생겼는지 밖에서 알 방법이 payload 안에만 있었다.

★ 스크린샷이 아니라 그 사이트의 대표 사진(og:image)이다. 헤드리스 브라우저는
  봇 탐지 우회 우려로 영구 금지돼 있고(DECISIONS 1-1), 워커(python:slim)·
  프리렌더(node:alpine) 어디에도 Chromium 이 없다.

- site_thumbnail: 대표 사진을 받아 <prefix>/thumbs/<slug>.<ext> 로 올린다.
  s/<slug>/ 안에 두지 않는 이유 — _remove_stale_site_files 가 매 발행마다
  그 경로를 프리렌더 산출물로 통째로 교체해 조용히 지운다
- site_payload: primary_media()·publish_origin()·region_label() 공개.
  isPrimary 계산을 한 곳으로 모아 og:image 와 썸네일이 갈릴 수 없게 했다
- build_service: azure publish 직후·IndexNow 전에 저장. 실패해도 발행은 그대로
  (payload 와 같은 원칙). thumbnail_url 은 발행 상태 전이 UPDATE 에 합쳐 1회
- GET /v1/showcase: 인증 없음. 발행된 사이트만, place_id·전화·상세주소는 안 나간다
- conftest: fake_renderer 가 늘 ok=True 라 NO_UNIQUE_CONTENT 되짚기 경로가
  통째로 안 돌고 있었다(기존에 깨져 있던 테스트 4건 포함 수정)

전체 562 passed
2026-09-03 09:41:10 +09:00

25 lines
1.2 KiB
Python

from fastapi import APIRouter, Depends, Query
from router.v1.validator.dependencies import RemoveNoneResponse
from services.showcase_service import ShowcaseService
from .protocol import Res_Showcase
# 발행 사이트 쇼케이스. ★ 인증이 없다 — 랜딩(비로그인)이 부른다.
# ★ :9801(어드민 진입점)에는 마운트하지 않는다. 내부 화면이 쓸 목록이 아니다.
router = APIRouter(prefix="/v1/showcase", tags=["Showcase"], responses={404: {"description": "Not found"}})
@router.get(
path="",
response_model=Res_Showcase,
summary="발행 사이트 쇼케이스(공개)",
description="실제로 발행된 사이트를 최신순으로 준다. 상호명·업종·지역(시·군·구까지)·발행 주소·썸네일뿐이다 — "
"로그인 없이 나가므로 사업장 식별자·전화번호·상세 주소는 싣지 않는다. "
"썸네일은 그 사이트의 대표 사진이고, 만들지 못한 사이트는 키가 없다.",
)
async def list_showcase(
service: ShowcaseService = Depends(),
limit: int = Query(12, ge=1, le=48, description="가져올 개수"),
):
return RemoveNoneResponse(await service.list(limit))