-
Notifications
You must be signed in to change notification settings - Fork 0
Backend
trz-21 edited this page Jun 13, 2026
·
1 revision
📌 이 페이지는 이 프로젝트의 살아있는 스펙(최종 현황) 이며 canonical 문서입니다. 코드/설계 변경 시 PR 머지 후 이 페이지를 갱신합니다. (작업 흐름: 개발-워크플로우)
위치:
backend/(monorepo). Cargo 패키지명coupang-review-ai-backend, lib 이름coupang_review_ai_backend.
아래는 v1 목표 구조다. 초기 스캐폴드는 health 엔드포인트 + 빈 모듈로 시작하며, 기능 구현 시
.claude/code-rules.md의 "새 API 엔드포인트 추가 순서"를 따라 채운다.
backend/src/
├── lib.rs
├── config.rs
├── error.rs
│
├── domain/ # Zero external deps
│ ├── mod.rs
│ ├── models/ # 핵심 엔티티
│ │ ├── mod.rs
│ │ ├── user.rs
│ │ └── analysis.rs
│ └── ports/ # trait (port) 정의
│ ├── mod.rs
│ ├── user_repository.rs
│ ├── analysis_repository.rs
│ ├── crawler.rs
│ └── ai_analyzer.rs
│
├── application/ # 비즈니스 로직
│ ├── mod.rs
│ ├── auth_service.rs
│ └── analysis_service.rs
│
├── adapters/ # 외부 의존성 구현체
│ ├── mod.rs
│ ├── postgres/
│ │ ├── mod.rs
│ │ ├── user_repo.rs
│ │ └── analysis_repo.rs
│ ├── coupang/ # 쿠팡 리뷰 크롤러
│ │ ├── mod.rs
│ │ └── crawler.rs
│ └── gemini/ # Gemini AI 분석
│ ├── mod.rs
│ └── analyzer.rs
│
└── http/ # Axum 진입점
├── mod.rs
├── macros.rs
├── state.rs
├── router.rs
└── handlers/
├── mod.rs
├── health.rs
├── auth.rs
└── analysis.rs
| 레이어 | 역할 | 외부 의존성 |
|---|---|---|
domain/ |
엔티티 + Port trait 정의 | 없음 |
application/ |
비즈니스 로직, Port 사용 | domain만 |
adapters/ |
Port 구현체 (DB, 크롤러, AI) | sqlx, reqwest, Gemini API |
http/ |
Axum 핸들러, AppState, 라우터 | axum, application |
#[derive(Clone)]
pub struct AppState {
pub db_pool: PgPool,
pub config: Config,
pub user_service: Arc<dyn UserService>,
pub analysis_service: Arc<dyn AnalysisService>,
}- 앱 시작 시 한 번 초기화
-
Arc<dyn Trait>로 서비스 보관 → 테스트 시 Mock 주입 가능 - Axum이 매 요청마다 Clone
#[derive(Debug, Error)]
pub enum AppError {
NotFound,
Unauthorized,
Forbidden(String), // 플랜 초과 등
BadRequest(String),
Database(#[from] sqlx::Error),
Internal(#[from] anyhow::Error),
}
impl IntoResponse for AppError { ... }
pub type AppResult<T> = Result<T, AppError>;-- 사용자
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
plan TEXT NOT NULL DEFAULT 'free', -- free | starter | pro
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 분석 작업
CREATE TABLE analyses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
urls TEXT[] NOT NULL,
review_limit INT NOT NULL DEFAULT 100,
status TEXT NOT NULL DEFAULT 'pending', -- pending|crawling|analyzing|completed|failed
result JSONB,
error TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
completed_at TIMESTAMPTZ
);POST /analyses
└─ analysis_service.create_analysis()
└─ DB에 status=pending으로 저장
└─ tokio::spawn() → 백그라운드 태스크
├─ status=crawling
├─ crawler.fetch_reviews(urls) → Vec<Review>
├─ status=analyzing
├─ ai_analyzer.analyze(reviews) → AnalysisResult
├─ status=completed, result 저장
└─ (실패 시) status=failed, error 저장
GET /analyses/:id (프론트엔드 폴링)
└─ status 확인 → completed이면 result 반환
- 쿠팡 리뷰 JSON API:
https://www.coupang.com/next-api/review?productId=...&page=1&size=N&sortBy=ORDER_SCORE_ASC&ratingSummary=true - 실제 브라우저 헤더(User-Agent, Referer, Accept, Accept-Language, sec-fetch-*) 설정
- 응답 status 검사 → 실패 시 상태코드+본문 스니펫을 에러로 전파(진단 가능)
- 파싱: 알려진 키 + 재귀 탐색으로 리뷰 배열/상품명 발견(스키마 변경 방어)
- Port trait
CoupangCrawler로 격리 → 테스트/데모 시 Mock 데이터 사용
- 쿠팡은 Akamai Bot Manager 로 보호됨. 데이터센터 IP 는 IP 단에서 403(Access Denied) → 헤더/쿠키 트릭으로 우회 불가(검증됨).
- sensor 스푸핑/프록시 로테이션 자체 구현은 하지 않음(취약 + ToS/법적 리스크).
- 안정적 수집 경로(택1):
-
COUPANG_PROXY_URL: 스크래핑 API(ScraperAPI/ZenRows 등) 경유.{url}치환, anti-bot/IP 로테이션을 벤더가 처리. - 가정용 IP/헤드리스 환경에서 실행.
-
- 로컬 전체 플로우 데모:
CRAWLER_MODE=mock(픽스처 리뷰) + 실제 Gemini 분석. - 실패 원인은 DB
analyses.error(AppError::detail())와 서버 로그(tracing::error!)로 노출.
- 엔드포인트:
POST generativelanguage.googleapis.com/v1beta/models/{model}:generateContent(인증:x-goog-api-key헤더) - 리뷰 배치 처리 (100개씩 분할)
- 한국어 프롬프트
- 구조화된 JSON 출력 요청 (
generationConfig.responseMimeType = application/json) - 모델: gemini-2.5-flash (free tier 호출 가능, env
GEMINI_MODEL로 override,GEMINI_API_KEY미설정 시 MockAiAnalyzer 폴백)
-
testcontainers:cargo test실행 시 PostgreSQL 컨테이너 자동 관리 -
TestApp: 격리된 test_<uuid> DB + 랜덤 포트 서버 - 크롤러/Gemini API: Mock Adapter 주입
- 상세:
specification/dev/harness.md
📚 스펙 네비게이션: Home · Service-Overview · Tech-Stack · API · Backend · Frontend · Harness · 개발-워크플로우