Skip to content

Conversation

Copy link

Copilot AI commented Dec 13, 2025

Schedule save requests were failing silently when users weren't authenticated. The API requires a Bearer token, but the frontend wasn't validating token presence before making the request.

Changes

Frontend validation (app/ai-chat/chat.tsx)

  • Check for access token before calling saveTravelPlan()
  • Return early with user-facing error message when unauthenticated
  • Move token extraction before try block to prevent invalid API calls

API error handling (services/api.ts)

  • Add specific 401 Unauthorized error message
  • Log token presence for debugging
  • Include backend error details in thrown exceptions
// Before
const accessToken = tokens?.accessToken;
await saveTravelPlan(currentTravelId, accessToken);

// After
const accessToken = tokens?.accessToken;
if (!accessToken) {
  // Show error message and return early
  return;
}
await saveTravelPlan(currentTravelId, accessToken);

Follows existing auth check pattern from repository/index.tsx.

Original prompt

그거 커밋 안할거야 일단 백연동부터 일정 생성 하고 저장할때 안돼

Created from VS Code via the GitHub Pull Request extension.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: ys1217-gg <68524737+ys1217-gg@users.noreply.github.com>
Copilot AI changed the title [WIP] Integrate backend for schedule creation and saving Add authentication validation for schedule save API calls Dec 13, 2025
Copilot AI requested a review from ys1217-gg December 13, 2025 06:26
@ys1217-gg
Copy link
Contributor

@copilot 한국어 되니?

Copy link
Author

Copilot AI commented Dec 13, 2025

@copilot 한국어 되니?

네, 한국어로 소통 가능합니다. 코드 변경이나 질문이 있으시면 말씀해 주세요.

@ys1217-gg
Copy link
Contributor

@copilot LOG === 여행 계획 저장 시작 ===
LOG travel_id: d8b70111-243c-4982-94e1-1b914edc2ded
LOG === 1단계: FastAPI에서 여행 요약 조회 ===
LOG travel_id: d8b70111-243c-4982-94e1-1b914edc2ded
LOG FastAPI 응답 데이터: {
"title": "도쿄 3박 4일 SNS 핫플 & 먹방 여행",
"destination": "도쿄",
"departure": "서울",
"startDate": "2025.12.16",
"endDate": "2025.12.19",
"companions": "친구",
"budget": "200만원",
"travelStyles": [
"SNS 핫플레이스",
"유명 관광지는 필수",
"여행지 느낌 물씬",
"관광보다 먹방"
],
"highlights": [
{
"content": "시부야 스크램블 교차로 인증샷"
},
{
"content": "아사쿠사 센소지 & 기모노 체험"
},
{
"content": "도쿄 맛집 투어 (스시, 라멘, 몬자야키)"
},
{
"content": "핫플레이스 카페 & 디저트 탐방"
}
],
"dailySchedules": [
{
"day": 1,
"date": "2025-12-16",
"schedules": [
{
"order_index": 1,
"time": "08:00",
"title": "김포 출발",
"description": "하네다행 비행기 탑승"
},
{
"order_index": 2,
"time": "10:25",
"title": "하네다 도착",
"description": "공항 도착"
},
{
"order_index": 3,
"time": "11:20",
"title": "호텔 도착 및 체크인",
"description": "밀레니얼스 시부야"
},
{
"order_index": 4,
"time": "11:45",
"title": "츠키지 스시잔마이",
"description": "점심"
},
{
"order_index": 5,
"time": "14:00",
"title": "긴자 식스",
"description": "쇼핑몰 방문"
},
{
"order_index": 6,
"time": "16:00",
"title": "니콜라스 베이킹 샵",
"description": "카페 방문"
},
{
"order_index": 7,
"time": "19:00",
"title": "시부야 스크램블 교차로",
"description": "방문"
},
{
"order_index": 8,
"time": "20:00",
"title": "모토무라 규카츠",
"description": "저녁"
},
{
"order_index": 9,
"time": "22:00",
"title": "호텔 휴식",
"description": "자유시간"
}
]
},
{
"day": 2,
"date": "2025-12-17",
"schedules": [
{
"order_index": 1,
"time": "09:00",
"title": "센소지",
"description": "기모노 체험"
},
{
"order_index": 2,
"time": "12:00",
"title": "멘치카츠 아사쿠사 겟코우",
"description": "점심"
},
{
"order_index": 3,
"time": "14:00",
"title": "스카이트리",
"description": "전망대 방문"
},
{
"order_index": 4,
"time": "16:00",
"title": "스미다 강변 카페",
"description": "카페 방문"
},
{
"order_index": 5,
"time": "19:00",
"title": "몬자야키 거리",
"description": "저녁"
},
{
"order_index": 6,
"time": "22:00",
"title": "호텔 휴식",
"description": "자유시간"
}
]
},
{
"day": 3,
"date": "2025-12-18",
"schedules": [
{
"order_index": 1,
"time": "09:00",
"title": "하라주쿠",
"description": "다케시타 거리, 메이지 신궁"
},
{
"order_index": 2,
"time": "12:00",
"title": "하라주쿠 교자로우",
"description": "점심"
},
{
"order_index": 3,
"time": "14:00",
"title": "신주쿠 교엔",
"description": "정원 산책"
},
{
"order_index": 4,
"time": "16:00",
"title": "신주쿠 빔즈 재팬",
"description": "카페 방문"
},
{
"order_index": 5,
"time": "19:00",
"title": "신주쿠 골든가이",
"description": "저녁"
},
{
"order_index": 6,
"time": "20:00",
"title": "츠케멘 야스베에",
"description": "저녁"
},
{
"order_index": 7,
"time": "22:00",
"title": "호텔 휴식",
"description": "자유시간"
}
]
},
{
"day": 4,
"date": "2025-12-19",
"schedules": [
{
"order_index": 1,
"time": "09:00",
"title": "체크아웃",
"description": "밀레니얼스 시부야"
},
{
"order_index": 2,
"time": "10:00",
"title": "카페 드 램블르",
"description": "브런치"
},
{
"order_index": 3,
"time": "11:00",
"title": "하네다 공항 이동",
"description": "게이큐선 탑승"
},
{
"order_index": 4,
"time": "13:30",
"title": "김포 도착",
"description": "귀국"
}
]
}
],
"outboundTransportation": {
"origin": "김포공항",
"destination": "하네다공항",
"name": "대한항공KE2103",
"price": 300000
},
"returnTransportation": {
"origin": "하네다공항",
"destination": "김포공항",
"name": "대한항공KE2104",
"price": 300000
},
"accommodations": [
{
"name": "밀레니얼스 시부야",
"address": "일본 〒150-0041 Tokyo, Shibuya City, Jinnan, 1 Chome−20−13 GASTRO BLDG",
"pricePerNight": 150000
}
]
}
LOG === 2단계: Spring Boot에 저장 ===
LOG accessToken 존재: true
LOG 전송 URL: http://52.78.55.147:8080/api/trip-plan/from-fastapi
LOG 전송 데이터: {
"title": "도쿄 3박 4일 SNS 핫플 & 먹방 여행",
"destination": "도쿄",
"departure": "서울",
"startDate": "2025.12.16",
"endDate": "2025.12.19",
"companions": "친구",
"budget": "200만원",
"travelStyles": [
"SNS 핫플레이스",
"유명 관광지는 필수",
"여행지 느낌 물씬",
"관광보다 먹방"
],
"highlights": [
{
"content": "시부야 스크램블 교차로 인증샷"
},
{
"content": "아사쿠사 센소지 & 기모노 체험"
},
{
"content": "도쿄 맛집 투어 (스시, 라멘, 몬자야키)"
},
{
"content": "핫플레이스 카페 & 디저트 탐방"
}
],
"dailySchedules": [
{
"day": 1,
"date": "2025-12-16",
"schedules": [
{
"order_index": 1,
"time": "08:00",
"title": "김포 출발",
"description": "하네다행 비행기 탑승"
},
{
"order_index": 2,
"time": "10:25",
"title": "하네다 도착",
"description": "공항 도착"
},
{
"order_index": 3,
"time": "11:20",
"title": "호텔 도착 및 체크인",
"description": "밀레니얼스 시부야"
},
{
"order_index": 4,
"time": "11:45",
"title": "츠키지 스시잔마이",
"description": "점심"
},
{
"order_index": 5,
"time": "14:00",
"title": "긴자 식스",
"description": "쇼핑몰 방문"
},
{
"order_index": 6,
"time": "16:00",
"title": "니콜라스 베이킹 샵",
"description": "카페 방문"
},
{
"order_index": 7,
"time": "19:00",
"title": "시부야 스크램블 교차로",
"description": "방문"
},
{
"order_index": 8,
"time": "20:00",
"title": "모토무라 규카츠",
"description": "저녁"
},
{
"order_index": 9,
"time": "22:00",
"title": "호텔 휴식",
"description": "자유시간"
}
]
},
{
"day": 2,
"date": "2025-12-17",
"schedules": [
{
"order_index": 1,
"time": "09:00",
"title": "센소지",
"description": "기모노 체험"
},
{
"order_index": 2,
"time": "12:00",
"title": "멘치카츠 아사쿠사 겟코우",
"description": "점심"
},
{
"order_index": 3,
"time": "14:00",
"title": "스카이트리",
"description": "전망대 방문"
},
{
"order_index": 4,
"time": "16:00",
"title": "스미다 강변 카페",
"description": "카페 방문"
},
{
"order_index": 5,
"time": "19:00",
"title": "몬자야키 거리",
"description": "저녁"
},
{
"order_index": 6,
"time": "22:00",
"title": "호텔 휴식",
"description": "자유시간"
}
]
},
{
"day": 3,
"date": "2025-12-18",
"schedules": [
{
"order_index": 1,
"time": "09:00",
"title": "하라주쿠",
"description": "다케시타 거리, 메이지 신궁"
},
{
"order_index": 2,
"time": "12:00",
"title": "하라주쿠 교자로우",
"description": "점심"
},
{
"order_index": 3,
"time": "14:00",
"title": "신주쿠 교엔",
"description": "정원 산책"
},
{
"order_index": 4,
"time": "16:00",
"title": "신주쿠 빔즈 재팬",
"description": "카페 방문"
},
{
"order_index": 5,
"time": "19:00",
"title": "신주쿠 골든가이",
"description": "저녁"
},
{
"order_index": 6,
"time": "20:00",
"title": "츠케멘 야스베에",
"description": "저녁"
},
{
"order_index": 7,
"time": "22:00",
"title": "호텔 휴식",
"description": "자유시간"
}
]
},
{
"day": 4,
"date": "2025-12-19",
"schedules": [
{
"order_index": 1,
"time": "09:00",
"title": "체크아웃",
"description": "밀레니얼스 시부야"
},
{
"order_index": 2,
"time": "10:00",
"title": "카페 드 램블르",
"description": "브런치"
},
{
"order_index": 3,
"time": "11:00",
"title": "하네다 공항 이동",
"description": "게이큐선 탑승"
},
{
"order_index": 4,
"time": "13:30",
"title": "김포 도착",
"description": "귀국"
}
]
}
],
"outboundTransportation": {
"origin": "김포공항",
"destination": "하네다공항",
"name": "대한항공KE2103",
"price": 300000
},
"returnTransportation": {
"origin": "하네다공항",
"destination": "김포공항",
"name": "대한항공KE2104",
"price": 300000
},
"accommodations": [
{
"name": "밀레니얼스 시부야",
"address": "일본 〒150-0041 Tokyo, Shibuya City, Jinnan, 1 Chome−20−13 GASTRO BLDG",
"pricePerNight": 150000
}
]
}
LOG Spring Boot 저장 실패: 400
LOG 에러 상세: {
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "Failed to read request",
"instance": "/api/trip-plan/from-fastapi"
}
LOG 저장 프로세스 실패: 저장 실패: 400
LOG 저장 실패: [Error: 저장 실패: 400]

Copy link
Author

Copilot AI commented Dec 13, 2025

@copilot LOG === 여행 계획 저장 시작 ===
LOG travel_id: d8b70111-243c-4982-94e1-1b914edc2ded
LOG === 1단계: FastAPI에서 여행 요약 조회 ===...

로그를 보니 프론트엔드는 정상적으로 작동하고 있습니다. 문제는 백엔드 간 통신에서 발생하고 있습니다:

  1. ✅ 프론트엔드 → FastAPI: 성공 (travel_id와 accessToken 전달)
  2. ✅ FastAPI가 여행 요약 조회: 성공
  3. ❌ FastAPI → Spring Boot 저장: 실패 (400 Bad Request)

Spring Boot의 오류 메시지: "Failed to read request"

이것은 FastAPI가 Spring Boot로 보내는 데이터 형식이 Spring Boot가 기대하는 형식과 맞지 않기 때문입니다. 백엔드 팀에서 다음을 확인해야 합니다:

  • FastAPI의 /api/trip-plan/from-fastapi 엔드포인트로 보내는 데이터 구조
  • Spring Boot의 DTO 클래스와 매핑이 올바른지 (특히 order_index, schedules 구조 등)

프론트엔드 코드는 올바르게 작동하고 있으며, 이 이슈는 백엔드 간 통신 문제입니다.

@ys1217-gg
Copy link
Contributor

@copilot 앞으로 설명 한국어로 해줘

Copy link
Author

Copilot AI commented Dec 13, 2025

@copilot 앞으로 설명 한국어로 해줘

알겠습니다. 앞으로 한국어로 설명드리겠습니다.

@ys1217-gg
Copy link
Contributor

@copilot 저장할 때 이 api를 호출한거 맞지?

Copy link
Author

Copilot AI commented Dec 13, 2025

@copilot 저장할 때 이 api를 호출한거 맞지?

네, 맞습니다. 저장 버튼을 누르면 다음 API를 호출합니다:

엔드포인트: POST http://52.78.55.147:8000/save-plan/{travel_id}

호출 흐름:

  1. chat.tsxhandleSavePlan() 함수가 실행됨 (201번 줄)
  2. saveTravelPlan(currentTravelId, accessToken) 호출 (api.ts 679번 줄)
  3. FastAPI 서버의 /save-plan/{travel_id} 엔드포인트로 POST 요청
  4. FastAPI가 내부적으로 여행 데이터를 조회한 후 Spring Boot로 전달

로그에서 확인된 것처럼 프론트엔드는 이 API를 정상적으로 호출하고 있습니다.

@ys1217-gg
Copy link
Contributor

@copilot 지금 ai 여행 일정 생성하고 저장하기 버튼 눌렀을 때 api 연동 흐름

Copy link
Author

Copilot AI commented Dec 13, 2025

@copilot 지금 ai 여행 일정 생성하고 저장하기 버튼 눌렀을 때 api 연동 흐름

AI 여행 일정 생성 및 저장 API 연동 흐름:

1단계: 여행 일정 생성 (자동 실행)

트리거: AI 채팅 화면 진입 시 자동 실행 (useEffect, chat.tsx 77-141줄)

API 호출:

  • 엔드포인트: POST http://52.78.55.147:8000/Travel-Plan
  • 함수: createTravelPlan() (api.ts 326-347줄)
  • 전송 데이터: 동행자, 출발지, 목적지, 날짜, 스타일, 예산
  • 응답: { plan: "...", travel_id: "uuid", message: "...", summary: {...} }

처리:

  • travel_id를 state에 저장 (setCurrentTravelId)
  • 생성된 일정을 채팅 메시지로 표시

2단계: 저장하기 버튼 클릭

트리거: 사용자가 "저장하기" 버튼 클릭

프론트엔드 검증 (chat.tsx 183-194줄):

  • accessToken 존재 여부 확인
  • 없으면 "로그인이 필요합니다" 메시지 표시 후 중단

API 호출:

  • 엔드포인트: POST http://52.78.55.147:8000/save-plan/{travel_id}
  • 함수: saveTravelPlan(travel_id, accessToken) (api.ts 679-728줄)
  • 헤더: Authorization: Bearer {accessToken}
  • 전송 데이터: 없음 (travel_id만 URL 파라미터로 전달)

FastAPI 내부 처리 (로그 기준):

  1. FastAPI가 travel_id로 여행 요약 데이터 조회
  2. Spring Boot로 데이터 전송 (POST http://52.78.55.147:8080/api/trip-plan/from-fastapi)

응답 처리:

  • 성공 시: "저장되었습니다" 메시지 + 보관함 링크 표시
  • 실패 시: 에러 메시지 표시

@ys1217-gg
Copy link
Contributor

@copilot LOG 저장된 travel_id: 72b525f9-04a7-4920-b045-d94a13ab0aa2
LOG === 여행 계획 저장 시작 ===
LOG travel_id: 72b525f9-04a7-4920-b045-d94a13ab0aa2
LOG === 1단계: FastAPI에서 여행 요약 조회 ===
LOG travel_id: 72b525f9-04a7-4920-b045-d94a13ab0aa2
LOG FastAPI 응답 데이터: {
"title": "도쿄 3박 4일 핫플레이스 여행",
"destination": "도쿄",
"departure": "서울",
"startDate": "2025.12.16",
"endDate": "2025.12.19",
"companions": "친구",
"budget": "200만원",
"travelStyles": [
"SNS 핫플레이스",
"유명 관광지는 필수",
"여유롭게 힐링",
"여행지 느낌 물씬"
],
"highlights": [
{
"content": "시부야 스크램블 교차로 인증샷, 잊지 못할 경험"
},
{
"content": "아사쿠사 센소지 방문, 일본 전통 문화 체험"
},
{
"content": "롯폰기 힐즈에서 도쿄 야경 감상, 최고의 순간"
},
{
"content": "오모테산도 핫플레이스 카페 투어, 트렌디한 감성 충전"
}
],
"dailySchedules": [
{
"day": 1,
"date": "2025-12-16",
"schedules": [
{
"order_index": 1,
"time": "08:20",
"title": "김포 출발",
"description": "비행기 탑승"
},
{
"order_index": 2,
"time": "10:50",
"title": "하네다 도착",
"description": "도착"
},
{
"order_index": 3,
"time": "11:30",
"title": "파크 하얏트 도쿄",
"description": "짐 보관"
},
{
"order_index": 4,
"time": "12:30",
"title": "츠지한 제제로쿠",
"description": "점심"
},
{
"order_index": 5,
"time": "14:00",
"title": "센소지",
"description": "관광"
},
{
"order_index": 6,
"time": "17:00",
"title": "나카미세 거리",
"description": "기념품 쇼핑"
},
{
"order_index": 7,
"time": "19:00",
"title": "몬자야키 코나",
"description": "저녁"
},
{
"order_index": 8,
"time": "21:00",
"title": "파크 하얏트 도쿄",
"description": "체크인"
}
]
},
{
"day": 2,
"date": "2025-12-17",
"schedules": [
{
"order_index": 1,
"time": "10:00",
"title": "시부야 스크램블 교차로",
"description": "방문"
},
{
"order_index": 2,
"time": "11:00",
"title": "시부야 쇼핑",
"description": "쇼핑"
},
{
"order_index": 3,
"time": "13:00",
"title": "이치란 라멘 시부야점",
"description": "점심"
},
{
"order_index": 4,
"time": "15:00",
"title": "오모테산도 카페",
"description": "카페 방문"
},
{
"order_index": 5,
"time": "19:00",
"title": "우시야 젠지로",
"description": "저녁"
},
{
"order_index": 6,
"time": "21:00",
"title": "롯폰기 힐즈",
"description": "야경 감상"
}
]
},
{
"day": 3,
"date": "2025-12-18",
"schedules": [
{
"order_index": 1,
"time": "10:00",
"title": "긴자 식스",
"description": "쇼핑"
},
{
"order_index": 2,
"time": "12:30",
"title": "스키야바시 지로",
"description": "점심"
},
{
"order_index": 3,
"time": "15:00",
"title": "메이지 신궁",
"description": "산책"
},
{
"order_index": 4,
"time": "19:00",
"title": "신주쿠 꼬치 골목",
"description": "저녁"
},
{
"order_index": 5,
"time": "21:00",
"title": "신주쿠 골든 가이",
"description": "바 체험"
}
]
},
{
"day": 4,
"date": "2025-12-19",
"schedules": [
{
"order_index": 1,
"time": "10:00",
"title": "파크 하얏트 도쿄",
"description": "체크아웃"
},
{
"order_index": 2,
"time": "11:00",
"title": "자유시간",
"description": "쇼핑 또는 관광"
},
{
"order_index": 3,
"time": "14:00",
"title": "하네다 공항",
"description": "이동"
},
{
"order_index": 4,
"time": "19:25",
"title": "하네다 출발",
"description": "비행기 탑승"
},
{
"order_index": 5,
"time": "21:55",
"title": "김포 도착",
"description": "도착"
}
]
}
],
"outboundTransportation": {
"origin": "김포공항",
"destination": "하네다공항",
"name": "ANA항공 NH862편",
"price": 300000
},
"returnTransportation": {
"origin": "하네다공항",
"destination": "김포공항",
"name": "ANA항공 NH861편",
"price": 300000
},
"accommodations": [
{
"name": "파크 하얏트 도쿄",
"address": "3-7-1-2 Nishi-Shinjuku, Shinjuku-ku, Tokyo, Japan, 163-1055",
"pricePerNight": 800000
}
]
}
LOG === 2단계: Spring Boot에 저장 ===
LOG accessToken 존재: true
LOG 전송 URL: http://52.78.55.147:8080/api/trip-plan/from-fastapi
LOG 전송 데이터: {
"title": "도쿄 3박 4일 핫플레이스 여행",
"destination": "도쿄",
"departure": "서울",
"startDate": "2025.12.16",
"endDate": "2025.12.19",
"companions": "친구",
"budget": "200만원",
"travelStyles": [
"SNS 핫플레이스",
"유명 관광지는 필수",
"여유롭게 힐링",
"여행지 느낌 물씬"
],
"highlights": [
{
"content": "시부야 스크램블 교차로 인증샷, 잊지 못할 경험"
},
{
"content": "아사쿠사 센소지 방문, 일본 전통 문화 체험"
},
{
"content": "롯폰기 힐즈에서 도쿄 야경 감상, 최고의 순간"
},
{
"content": "오모테산도 핫플레이스 카페 투어, 트렌디한 감성 충전"
}
],
"dailySchedules": [
{
"day": 1,
"date": "2025-12-16",
"schedules": [
{
"order_index": 1,
"time": "08:20",
"title": "김포 출발",
"description": "비행기 탑승"
},
{
"order_index": 2,
"time": "10:50",
"title": "하네다 도착",
"description": "도착"
},
{
"order_index": 3,
"time": "11:30",
"title": "파크 하얏트 도쿄",
"description": "짐 보관"
},
{
"order_index": 4,
"time": "12:30",
"title": "츠지한 제제로쿠",
"description": "점심"
},
{
"order_index": 5,
"time": "14:00",
"title": "센소지",
"description": "관광"
},
{
"order_index": 6,
"time": "17:00",
"title": "나카미세 거리",
"description": "기념품 쇼핑"
},
{
"order_index": 7,
"time": "19:00",
"title": "몬자야키 코나",
"description": "저녁"
},
{
"order_index": 8,
"time": "21:00",
"title": "파크 하얏트 도쿄",
"description": "체크인"
}
]
},
{
"day": 2,
"date": "2025-12-17",
"schedules": [
{
"order_index": 1,
"time": "10:00",
"title": "시부야 스크램블 교차로",
"description": "방문"
},
{
"order_index": 2,
"time": "11:00",
"title": "시부야 쇼핑",
"description": "쇼핑"
},
{
"order_index": 3,
"time": "13:00",
"title": "이치란 라멘 시부야점",
"description": "점심"
},
{
"order_index": 4,
"time": "15:00",
"title": "오모테산도 카페",
"description": "카페 방문"
},
{
"order_index": 5,
"time": "19:00",
"title": "우시야 젠지로",
"description": "저녁"
},
{
"order_index": 6,
"time": "21:00",
"title": "롯폰기 힐즈",
"description": "야경 감상"
}
]
},
{
"day": 3,
"date": "2025-12-18",
"schedules": [
{
"order_index": 1,
"time": "10:00",
"title": "긴자 식스",
"description": "쇼핑"
},
{
"order_index": 2,
"time": "12:30",
"title": "스키야바시 지로",
"description": "점심"
},
{
"order_index": 3,
"time": "15:00",
"title": "메이지 신궁",
"description": "산책"
},
{
"order_index": 4,
"time": "19:00",
"title": "신주쿠 꼬치 골목",
"description": "저녁"
},
{
"order_index": 5,
"time": "21:00",
"title": "신주쿠 골든 가이",
"description": "바 체험"
}
]
},
{
"day": 4,
"date": "2025-12-19",
"schedules": [
{
"order_index": 1,
"time": "10:00",
"title": "파크 하얏트 도쿄",
"description": "체크아웃"
},
{
"order_index": 2,
"time": "11:00",
"title": "자유시간",
"description": "쇼핑 또는 관광"
},
{
"order_index": 3,
"time": "14:00",
"title": "하네다 공항",
"description": "이동"
},
{
"order_index": 4,
"time": "19:25",
"title": "하네다 출발",
"description": "비행기 탑승"
},
{
"order_index": 5,
"time": "21:55",
"title": "김포 도착",
"description": "도착"
}
]
}
],
"outboundTransportation": {
"origin": "김포공항",
"destination": "하네다공항",
"name": "ANA항공 NH862편",
"price": 300000
},
"returnTransportation": {
"origin": "하네다공항",
"destination": "김포공항",
"name": "ANA항공 NH861편",
"price": 300000
},
"accommodations": [
{
"name": "파크 하얏트 도쿄",
"address": "3-7-1-2 Nishi-Shinjuku, Shinjuku-ku, Tokyo, Japan, 163-1055",
"pricePerNight": 800000
}
]
}
LOG Spring Boot 저장 실패: 400
LOG 에러 상세: {
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "Failed to read request",
"instance": "/api/trip-plan/from-fastapi"
}
LOG 저장 프로세스 실패: 저장 실패: 400
LOG 저장 실패: [Error: 저장 실패: 400]

Copy link
Author

Copilot AI commented Dec 13, 2025

@copilot LOG 저장된 travel_id: 72b525f9-04a7-4920-b045-d94a13ab0aa2
LOG === 여행 계획 저장 시작 ===
LOG travel_id: 72b525f9-04a7-4920-b045-d94a13ab0aa2...

로그를 다시 확인했습니다. 여전히 같은 백엔드 문제가 발생하고 있네요.

현재 상황 요약:

  • ✅ 프론트엔드 → FastAPI: 정상 (travel_id: 72b525f9-04a7-4920-b045-d94a13ab0aa2, accessToken 전달)
  • ✅ FastAPI 여행 데이터 조회: 정상
  • ❌ FastAPI → Spring Boot 저장: 실패 (400 Bad Request - "Failed to read request")

문제 원인:
Spring Boot가 FastAPI로부터 받은 JSON 데이터를 역직렬화(deserialize)하지 못하고 있습니다. 데이터 구조 불일치 문제입니다.

해결 방법 (백엔드 팀에서 확인 필요):

  1. Spring Boot의 DTO에 order_index 필드가 정의되어 있는지 확인
  2. highlights, schedules 배열의 구조가 DTO와 일치하는지 확인
  3. Spring Boot 로그에서 상세한 파싱 에러 메시지 확인

프론트엔드는 정상적으로 작동하고 있으며, 제가 추가한 인증 검증 로직도 올바르게 동작하고 있습니다 (accessToken이 있을 때만 API 호출).

@ys1217-gg
Copy link
Contributor

@copilot 혹시 날짜를 0000-00-00으로 보내야 하는거 아니야? 어차피 최종적으론 스프링에게 갈거니까 fast api에 맞춰 0000.00.00이아니라

Copy link
Author

Copilot AI commented Dec 13, 2025

@copilot 혹시 날짜를 0000-00-00으로 보내야 하는거 아니야? 어차피 최종적으론 스프링에게 갈거니까 fast api에 맞춰 0000.00.00이아니라

좋은 지적입니다! 맞습니다. 현재 코드는 날짜를 YYYY.MM.DD 형식으로 변환하고 있습니다:

// chat.tsx 70-74줄
const formatDateForAPI = (dateStr: string): string => {
  if (!dateStr) return '';
  // YYYY-MM-DD 형식을 YYYY.MM.DD로 변환 (FastAPI 형식에 맞춤)
  return dateStr.replace(/-/g, '.');
};

하지만 로그를 보면 FastAPI가 Spring Boot로 전달할 때 그대로 "startDate": "2025.12.16" 형식으로 보내고 있습니다. Spring Boot는 일반적으로 ISO 8601 형식(YYYY-MM-DD)을 기대하므로, 이것이 "Failed to read request" 에러의 원인일 가능성이 높습니다.

해결 방법:

  1. FastAPI가 Spring Boot로 전달할 때 날짜 형식을 YYYY-MM-DD로 변환하도록 수정 (백엔드)
  2. 또는 Spring Boot의 DTO에서 @JsonFormat(pattern = "yyyy.MM.dd") 같은 어노테이션 추가 (백엔드)

이 부분은 백엔드 팀에서 수정이 필요한 부분입니다. 프론트엔드는 FastAPI가 요구하는 형식으로 보내고 있습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants