위딩 (With-ing)
팀 프로젝트

위딩 (With-ing)

2025.10 ~ 2025.11
PM, 프론트엔드, AI 추천 기능, 서버 관리
Next.jsReact QueryFastAPIOpenAIDALL-ESpring BootMySQLDocker

스위프(SWYP) 11기에서 진행한 사이드 프로젝트입니다. 예비부부들이 웨딩 준비 과정에서 겪는 정보 탐색의 어려움을 해결하고자 기획했습니다. 웨딩홀, 스튜디오, 드레스샵, 메이크업샵 정보를 한 곳에서 검색하고 비교할 수 있으며, AI가 체형을 분석하여 드레스를 추천하고 DALL-E로 착용 이미지를 생성해주는 기능을 제공합니다. GPT-4 기반 드레스 추천과 SQL 동적 쿼리 기반 웨딩홀 추천을 결합한 하이브리드 AI 구조가 이 프로젝트의 핵심입니다.

프로젝트 방문하기

* 현재 백엔드 서버가 중단되어 MSW(Mock)로 동작 중입니다.

역할별 수행 내용

PM

  • WBS 일정 관리 및 프로젝트 진행 총괄
  • IA(정보 구조) 설계
  • 와이어프레임 및 디자인 작업

프론트엔드

  • Claude Code + Figma MCP 활용 퍼블리싱 (31개 컴포넌트 구현)
  • Next.js App Router + React Query(TanStack Query) 기반 서버 상태 관리
  • Next.js API Route를 프록시로 활용 — CORS 우회 및 Authorization 헤더 중앙화
  • MSW(Mock Service Worker)로 백엔드 독립적인 개발 환경 구성

AI 추천 기능

  • FastAPI + GPT-4 기반 드레스 추천 서버 개발 (swyp-llm-main)
  • 체형·스타일 조합 540가지를 SHA256 해시 키로 MySQL 캐싱 — API 비용 절감 및 응답 속도 개선
  • SQL 동적 쿼리 빌더로 웨딩홀 필터 조건 조합 → 조건 완화 폴백 전략으로 결과 0건 방지
  • DALL-E 2 기반 드레스 착용 이미지 생성 및 Paramiko SSH 업로드 파이프라인 구현 (swyp-createImg-main)

서버 관리

  • Docker Compose + GitHub Actions CI/CD 구축
  • K8s + Jenkins 기반 MSA 구조로 전환 (도메인별 서비스 분리)

주요 성과

  • 6주 내 MVP 출시 (기획 → 배포)
  • 540가지 체형 조합 SHA256 해시 캐싱으로 GPT-4 API 반복 호출 비용 절감
  • Next.js API Route 프록시 패턴으로 CORS 문제 해결 및 인증 헤더 중앙화
  • 조건 완화 폴백 전략으로 웨딩홀 추천 결과 0건 방지

프로젝트 회고

Next.js API Route — 프록시로 쓰다

프론트엔드에서 백엔드와 AI 서버를 직접 호출하면 두 가지 문제가 생깁니다. 하나는 CORS이고, 다른 하나는 Authorization 헤더 관리입니다. 서버가 여러 개면 각 fetch마다 토큰을 직접 추가해야 하고, 클라이언트 코드에 백엔드 URL이 직접 노출됩니다.

이 프로젝트에서는 Next.js API Route를 프록시 레이어로 두어 이 문제를 해결했습니다. 브라우저는 항상 같은 도메인의 /api/...로 요청하고, API Route가 실제 백엔드나 AI 서버로 요청을 전달하면서 Authorization 헤더를 추가합니다.

// pages/api/recommend/dress.ts (API Route)
export default async function handler(req, res) {
  const token = req.headers.authorization;

  const response = await fetch(process.env.LLM_SERVER_URL + "/recommend", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: token,        // 서버에서 토큰 추가
    },
    body: JSON.stringify(req.body),
  });

  const data = await response.json();
  res.status(response.status).json(data);
}

// 클라이언트에서는 /api/recommend/dress 만 알면 됨
fetch("/api/recommend/dress", { method: "POST", body: ... })

클라이언트 코드에서 AI 서버 URL이 사라지고, 토큰 처리 로직이 한 곳에 모입니다. 환경 변수도 서버 사이드에서만 읽히므로 외부에 노출되지 않습니다.

SHA256 해시 캐싱 — 540가지 조합을 미리 쌓다

드레스 추천 로직은 체형스타일 선호도 조합에 따라 GPT-4에게 프롬프트를 보내고 결과를 반환하는 구조입니다. 문제는 GPT-4 호출 비용과 응답 지연이었습니다. 체형 분류 3가지, 상체 타입 3가지, 하체 타입 3가지 등을 조합하면 총 540가지 경우의 수가 나옵니다.

입력 파라미터 조합을 SHA256으로 해시하여 MySQL에 캐시 키로 저장했습니다. 같은 체형·스타일 조합이 들어오면 DB에서 즉시 반환하고, 새로운 조합일 때만 GPT-4를 호출한 뒤 결과를 저장합니다.

# SHA256 해시로 캐시 키 생성
import hashlib, json

def make_cache_key(params: dict) -> str:
    serialized = json.dumps(params, sort_keys=True)
    return hashlib.sha256(serialized.encode()).hexdigest()

# 캐시 조회
cache_key = make_cache_key({"body_type": "A", "style": "romantic", ...})
cached = db.query("SELECT result FROM dress_cache WHERE cache_key = %s", cache_key)

if cached:
    return cached["result"]          # DB에서 즉시 반환

# 캐시 미스 → GPT-4 호출 후 저장
result = await call_gpt4(prompt)
db.execute("INSERT INTO dress_cache (cache_key, result) VALUES (%s, %s)",
           cache_key, result)

서비스 초기에 미리 540가지 조합을 모두 채워두면 이후 요청은 전부 캐시 히트됩니다. GPT-4 반복 호출 비용을 줄이면서도 응답 속도를 개선할 수 있었습니다.

웨딩홀 추천 — SQL 동적 쿼리와 조건 완화 폴백

웨딩홀 추천은 GPT-4 대신 SQL 동적 쿼리 빌더로 구현했습니다. 예산, 지역, 수용 인원, 분위기 등 여러 필터 조건을 조합하여 DB에서 직접 조회하는 방식입니다.

문제는 조건이 많을수록 결과가 0건이 되는 경우입니다. 이를 방지하기 위해 조건 완화 폴백 전략을 적용했습니다. 전체 조건으로 조회 → 결과 없으면 부차적 조건 하나 제거 → 반복하여 최소한의 결과를 보장합니다.

# 조건 완화 폴백 전략
def recommend_halls(filters: dict):
    # 1차: 전체 조건으로 조회
    results = query_with_filters(filters)
    if results:
        return results

    # 2차: 분위기 조건 완화
    relaxed = {**filters}
    relaxed.pop("mood", None)
    results = query_with_filters(relaxed)
    if results:
        return results

    # 3차: 지역 조건 완화
    relaxed.pop("region", None)
    results = query_with_filters(relaxed)
    if results:
        return results

    # 최종: 예산 범위 확대
    relaxed["budget_max"] = relaxed["budget_max"] * 1.3
    return query_with_filters(relaxed)

드레스 추천(GPT-4)과 웨딩홀 추천(SQL)을 분리한 것은 의미 있는 선택이었습니다. 드레스는 체형과 스타일에 대한 자연어 해석이 필요하지만, 웨딩홀은 구조화된 필터 조건으로 충분히 처리할 수 있었습니다. LLM이 항상 정답이 아니라는 것을 직접 설계하면서 느꼈습니다.

성장과 배움

PM으로서 기획부터 IA 설계, 와이어프레임까지 직접 작업하면서 프론트엔드 개발 전에 구조를 먼저 잡는 경험을 했습니다. AI 서버를 직접 설계하면서 LLM을 쓸 곳과 쓰지 않을 곳을 구분하는 감각도 생겼습니다.

이 프로젝트를 통해 얻은 것:

  • Next.js API Route 프록시 패턴 — CORS 우회와 인증 헤더 중앙화를 동시에 해결하는 구조
  • SHA256 해시 기반 MySQL 캐싱 — 동일 조합 재호출을 DB 조회로 대체하여 LLM 비용 절감
  • SQL 동적 쿼리 + 조건 완화 폴백 — 구조화된 데이터에는 LLM보다 SQL이 적합함을 직접 확인
  • DALL-E 2 + Paramiko SSH 파이프라인 — 이미지 생성부터 서버 업로드까지 자동화
  • PM 역할 병행 — IA 설계와 WBS 관리를 직접 해보며 기획자의 시각으로 개발 우선순위 조정 경험

관련 자료