본문으로 건너뛰기

BFF API 경계

클라이언트 컴포넌트에서 백엔드를 직접 호출하지 않습니다. 모든 백엔드 통신은 apps/web/src/app/api/**/route.ts BFF 경계를 통합니다.

이유

  • 백엔드 서버 주소·secret이 브라우저에 노출되지 않도록
  • HttpOnly 쿠키로 access/refresh token을 안전하게 관리
  • 토큰 갱신, CORS, Origin 검증을 한 곳에서 처리

인증 요청 구조

클라이언트 → BFF route.ts → authenticatedBackendFetch → 백엔드

쿠키에서 access token 읽기
401 시 refresh 자동 처리

authenticatedBackendFetch를 사용하면 토큰 갱신과 로그인 리다이렉트가 자동으로 처리됩니다.

Guard 패턴

상태 변경 보호와 Turnstile 검증은 각 route.ts 안에서 직접 반복하지 않고 공용 래퍼로 선언합니다.

export const POST = withApiGuards(
{ requireCsrf: true, requireTurnstile: true },
async (request) => {
// route 본문
},
);
  • requireCsrfrejectCrossOriginRequest 실행
  • requireTurnstilerejectUnverifiedTurnstile 실행
  • 보호 조건을 통과한 뒤에만 실제 route handler가 실행됩니다.

Turnstile 응답 규약

  • 보호 API는 Turnstile 검증 쿠키가 없으면 403TURNSTILE_REQUIRED 에러 코드를 반환합니다.
  • 이 응답은 로그인 필요(401)와 구분해야 합니다.
  • 클라이언트는 이 코드를 받았을 때 로그인 화면이 아니라 /verify?returnTo=... 복구 흐름으로 보내야 합니다.

주요 BFF 엔드포인트

메서드경로설명
GET/POST/api/saju사주 조회·생성
POST/api/saju/draft미로그인 임시저장
POST/api/saju/result결과 조회
GET/PUT/api/saju/me내 사주 프로필 조회·수정
GET/api/saju/traditional정통사주
GET/api/saju/traditional-fortune정통사주 풀이
GET/api/saju/me/year신년운세
GET/api/saju/me/compatibility/[partnerId]파트너 궁합 풀이
GET/api/saju/zodiac-compatibility띠별 궁합 점수
GET/POST/api/partners파트너 목록·생성
GET/PUT/DELETE/api/partners/[partnerId]파트너 상세·수정·삭제
GET/POST/api/compatibility궁합 결과
GET/POST/api/location위치 추천
GET/api/location/search위치 검색
GET/POST/api/food/recommend음식 추천
POST/api/payment/verify결제 검증
POST/api/inquiries문의 등록
GET/DELETE/api/users/me내 정보 조회·탈퇴
GET/api/auth/kakao카카오 로그인 시작
GET/api/auth/kakao/callback카카오 OAuth 콜백
POST/api/auth/logout로그아웃
GET/api/auth/refresh토큰 갱신
GET/POST/api/auth/restore탈퇴 복구
GET/api/notifications알림 목록
GET/api/notifications/unread-count미읽음 수
POST/api/notifications/[notificationId]/read알림 읽음 처리

규칙

// ✅ route.ts 내에서
const res = await authenticatedBackendFetch('/saju/me', { method: 'GET' }, request);

// ❌ 클라이언트 컴포넌트에서 백엔드 직접 호출 금지
const res = await fetch(process.env.BACKEND_URL + '/saju/me');
  • route.ts는 HTTP 입출력·쿠키 처리에 집중, 비즈니스 로직은 entities/*/server로 위임
  • 쿠키 인증을 사용하는 상태 변경 요청은 rejectCrossOriginRequest로 Origin 검증
  • 문의 등록(POST /api/inquiries)은 로그인 필요 BFF이며 CSRF Origin 검증만 적용하고 Turnstile은 적용하지 않음
  • Turnstile이 필요한 보호 API는 withApiGuards({ requireTurnstile: true }) 또는 withApiGuards({ requireCsrf: true, requireTurnstile: true })를 우선 사용
  • 토큰 쿠키 키는 shared/config/authToken.ts 상수 사용 (문자열 하드코딩 금지)
  • 백엔드 응답 파싱은 parseBackendApiResponse로 통일