Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
a338eda
feat: 카카오 일정 조회 구현 중
RohDamin Jul 8, 2025
f85c2e9
fix: import 임시 주석 처리
RohDamin Jul 8, 2025
638ec23
feat: 일정 등록시 카카오 API 조회
RohDamin Jul 12, 2025
993b9f6
Merge pull request #6 from T-BluePot/dev
RohDamin Jul 12, 2025
b4dc913
feat: 카카오 장소 조회 기능 추가
RohDamin Aug 25, 2025
e37a786
feat: 네이버 블로그 조회 기능 추가
RohDamin Aug 25, 2025
052fcc6
feat: 태그번호로 태그명 조회 기능
RohDamin Aug 25, 2025
602da28
feat: ai 추천 로직 진행중
RohDamin Aug 25, 2025
ac931b2
feat: ai 일정 추천 기능 진행중
RohDamin Aug 25, 2025
fdf4c5a
feat: ai 일정 추천 결과 리턴하도록 작업
RohDamin Aug 26, 2025
922a345
chore: 필요 없는 로그 주석처리
RohDamin Aug 26, 2025
ec27791
fix: tag 조회 쿼리 테이블 명 대문자로 수정(소문자 사용 시 에러)
RohDamin Aug 26, 2025
29f7a9c
chore: AIClient 필요없는 주석 제거
RohDamin Aug 26, 2025
cfb71f1
feat: 주소를 x,y 좌표로 변환하는 api 추가
RohDamin Sep 20, 2025
dfe9f5c
feat: ApiResponse에 success/error 정적팩토리 메서드 추가
RohDamin Sep 20, 2025
4065e21
feat: 주소 목록 검색 api 추가
RohDamin Sep 20, 2025
dc98ee1
fix: naverBlog 패키지 이름 수정
RohDamin Sep 20, 2025
20da55d
fix: tagList를 int 배열이 아니라 map 형태로 보내주도록 수정
RohDamin Oct 6, 2025
a51e153
fix: 일정 생성 기능 수정
RohDamin Oct 9, 2025
5333d21
feat: 생성된 일정을 DB에 저장하는 API 작업
RohDamin Oct 11, 2025
eb5249a
update: 일정 상세 조회 API의 태그 조회 쿼리 수정
RohDamin Oct 11, 2025
95159f3
feat: 내 일정 목록 조회 API 작업
RohDamin Oct 11, 2025
6fac71b
update: Plan, Schedule 엔티티에 등록일, 수정일, 삭제여부 컬럼 추가
RohDamin Oct 12, 2025
24efcdb
update: Plan, Schedule 저장시 삭제여부 함께 저장, 일정 저장 API 메서드명 수정
RohDamin Oct 12, 2025
11266ef
feat: 전체 일정 삭제 API 작업
RohDamin Nov 3, 2025
a61fcdc
Merge pull request #14 from T-BluePot/dev
RohDamin Nov 22, 2025
6c1ba0c
feat: 일정 수정, 부분삭제 API 작업
RohDamin Nov 23, 2025
36f4100
feat: 카카오 장소 키워드 검색 API 추가
RohDamin Nov 23, 2025
9d017d2
fix: 일정 수정 시 soft-delete 하도록 변경
RohDamin Nov 23, 2025
a342697
feat: 사용자가 직접 추가한 일정, 카카오 API로 검색한 일정 생성할 수 있도록 수정
RohDamin Nov 23, 2025
aaf4c1b
[FEAT] 메인 화면에 필요한 API 작업 (#15)
dksgyrud1349 Nov 25, 2025
1b48b9d
feat: 백엔드 deploy 설정파일 수정
RohDamin Nov 25, 2025
8a8d04b
Merge pull request #16 from T-BluePot/feat/deploy-update
RohDamin Nov 25, 2025
633be18
Merge pull request #17 from T-BluePot/dev
RohDamin Nov 25, 2025
a300dbe
fix: 충돌 해결
RohDamin Nov 25, 2025
04ec3e2
Merge pull request #18 from T-BluePot/feat/create-schedule
RohDamin Nov 25, 2025
1855da0
[FEAT] 일정 관련 API 작업 (#19)
RohDamin Nov 25, 2025
5c4cc07
fix: 빌드 에러 해결
RohDamin Nov 25, 2025
00624e7
Merge branch 'main' into dev
RohDamin Nov 25, 2025
576c7cd
[FIX] 빌드 에러 수정 (#20)
RohDamin Nov 25, 2025
8b7daf9
Fix/member api (#21)
dksgyrud1349 Nov 29, 2025
bc2435d
[FIX] 인기 태그 조회 API 수정 (#22)
dksgyrud1349 Dec 1, 2025
5486521
[FIX] 회원 정보 관련 API 수정 (#23)
dksgyrud1349 Dec 1, 2025
2f78f7b
[FIX] 회원 탈퇴 코드 수정 (#24)
dksgyrud1349 Dec 3, 2025
3a0e934
feat: 일정 생성 시 랜덤 카테고리를 선택할 수 있도록 수정 (#25)
RohDamin Dec 7, 2025
8246770
[INFRA] main 브랜치로 merge (#26)
RohDamin Dec 7, 2025
29d3cc2
[FIX] openjdk:17이 deprecated 되어 도커파일 변경 (#27)
RohDamin Dec 7, 2025
c1026f5
[INFRA] Dockerfile 변경 main으로 merge (#28)
RohDamin Dec 7, 2025
918197e
[FEAT] 랜덤 카테고리 지정 가능하도록 수정, scheduleTag 저장 안되는 문제 수정 (#29)
RohDamin Dec 13, 2025
7ad081a
[INFRA] main 브랜치로 merge (#30)
RohDamin Dec 13, 2025
a17cf20
[FEAT] membershipNo 조회 코드 공통화 (#31)
dksgyrud1349 Dec 15, 2025
1213c74
[FEAT] 서비스명 수정 (#32)
dksgyrud1349 Dec 15, 2025
a714a5c
[STYLE] API URL 수정 & 코드 수정 (#33)
dksgyrud1349 Dec 15, 2025
bcc113d
Merge branch 'main' into dev
RohDamin Dec 19, 2025
713bf0c
[INFRA] main 브랜치로 merge (#34)
RohDamin Dec 19, 2025
4d02684
style: api url 변경 (#35)
RohDamin Dec 19, 2025
f4f2173
Merge pull request #36 from T-BluePot/dev
RohDamin Dec 19, 2025
2957734
chore: 쓰지 않는 import 삭제
RohDamin Dec 21, 2025
5fd0d4e
feat: 에러 코드 정의
RohDamin Dec 21, 2025
dde73d4
feat: swagger에 AccessToken, ApiKey 세팅할 수 있도록 config 수정
RohDamin Dec 21, 2025
ac7bb56
feat: membershipNo 조회 추가, api 에러 수정
RohDamin Dec 21, 2025
55cb084
feat: 에러 throw 수정
RohDamin Dec 21, 2025
e9280a5
feat: AI 생성 일정과 사용자 생성 일정 구분값 추가
RohDamin Dec 21, 2025
92f8cc3
Merge pull request #37 from T-BluePot/feat/schedule-membership
RohDamin Dec 21, 2025
ccec09c
Merge pull request #38 from T-BluePot/dev
RohDamin Dec 21, 2025
59dff93
FEAT : 로그 공통화 & 코드 리팩토링 (#39)
dksgyrud1349 Dec 22, 2025
396b75f
FEAT : 로그 공통화 & 코드 리팩토링 (#39) (#40)
dksgyrud1349 Dec 22, 2025
e9564c1
[FIX] : 에러 코드 형식 변경 (#41)
dksgyrud1349 Dec 29, 2025
395f8f1
Merge branch 'main' into dev
dksgyrud1349 Dec 29, 2025
f0f290b
[FIX] 에러 코드 형식 변경 (#44)
dksgyrud1349 Dec 29, 2025
dfa656c
[FIX] : 아이디 찾기 api 수정 (#45)
dksgyrud1349 Dec 29, 2025
215c775
[FIX] 아이디 찾기 api 수정 (#46)
dksgyrud1349 Dec 29, 2025
808884a
[FIX] : 아이디 찾기 api 수정 (#47)
dksgyrud1349 Dec 29, 2025
d4c3513
Merge branch 'main' into dev
dksgyrud1349 Dec 29, 2025
bc3447e
[FIX] 토큰 재생성 api 수정 (#48)
dksgyrud1349 Dec 29, 2025
b4bb19a
[FIX] : 토큰을 이용하여 회원번호 조회 시 return 되는 resultCode 수정 (#49)
dksgyrud1349 Dec 29, 2025
b613c81
[FIX] : 토큰을 이용하여 회원번호 조회 시 return 되는 resultCode 수정 (#50)
dksgyrud1349 Dec 29, 2025
18ad7db
[FIX] 메인 페이지 api 쿼리 수정 (#51)
dksgyrud1349 Jan 1, 2026
d7cdb39
[FIX] 메인 페이지 api 쿼리 수정 (#52)
dksgyrud1349 Jan 1, 2026
25a6ce6
[FIX] 인증번호 발송 api 수정 (#53)
dksgyrud1349 Jan 1, 2026
a8f5fa7
[FIX] : 인증번호 발송 api 수정 (#54)
dksgyrud1349 Jan 1, 2026
adfe2e2
[FIX] : 인증번호 일치 여부 api 수정 (#55)
dksgyrud1349 Jan 1, 2026
7fb82cf
[FIX] : 인증번호 일치 여부 api 수정 (#56)
dksgyrud1349 Jan 1, 2026
a5c32b6
[FIX] : 인증번호 발송 api (#57)
dksgyrud1349 Jan 1, 2026
7ee0a58
[FIX] : 인증번호 발송 api (#58)
dksgyrud1349 Jan 1, 2026
30be9b9
[FIX] : 인증번호 발송 api (#59)
dksgyrud1349 Jan 1, 2026
4e343ba
[FIX] : 인증번호 발송 api (#60)
dksgyrud1349 Jan 1, 2026
989c73d
[FIX] : 인증번호 발송 api 수정 (#61)
dksgyrud1349 Jan 1, 2026
0c15733
Merge branch 'main' into dev
dksgyrud1349 Jan 1, 2026
580b481
[FIX] : 인증번호 발송 api 수정 (#62)
dksgyrud1349 Jan 1, 2026
d9c418d
[UPDATE] : api 명세서 수정 (#63)
dksgyrud1349 Jan 1, 2026
f66bbf6
[UPDATE] api 명세서 수정 (#64)
dksgyrud1349 Jan 1, 2026
b1d3091
update: 실서버 blue/green 배포할 수 있도록 deploy-backend.yml 수정
RohDamin Jan 10, 2026
8cdb207
Merge pull request #65 from T-BluePot/infra/cicd-release-setting
RohDamin Jan 10, 2026
b76052c
Merge pull request #66 from T-BluePot/dev
RohDamin Jan 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Chacnged
## Changed
> 간단한 설명 (예: 로그인 완료 후 세션 동기화 누락 문제 해결)
수정 내용
- 예) 로그인 성공 시 `store.setSession()` 호출 추가
Expand Down
33 changes: 30 additions & 3 deletions .github/workflows/deploy-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
else
echo "HOST=${{ secrets.TEST_HOST }}" >> $GITHUB_ENV
echo "TARGET_DIR=${{ secrets.TEST_TARGET_DIR }}" >> $GITHUB_ENV
echo "${{ secrets.APP_PROPS_MAIN }}" > ./src/main/resources/application.properties
echo "${{ secrets.APP_PROPS_MAIN_BASE64 }}" | base64 --decode > ./src/main/resources/application.properties
fi

- name: Build jar file
Expand All @@ -44,12 +44,39 @@ jobs:
./Dockerfile \
${{ secrets.USERNAME }}@${{ env.HOST }}:${{ env.TARGET_DIR }}

- name: SSH into EC2 and run Docker
- name: SSH into EC2 and run Docker (main
if: github.ref == 'refs/heads/main'
run: |
ssh -o ServerAliveInterval=30 -i key.pem -o StrictHostKeyChecking=no ${{ secrets.USERNAME }}@${{ env.HOST }} << EOF
cd $TARGET_DIR
sudo docker stop backend || true
sudo docker rm backend || true
sudo docker build -t backend .
sudo docker run -d -p 8080:8080 --name backend backend
EOF
EOF
- name: SSH into server and deploy (release - blue/green)
if: github.ref == 'refs/heads/release'
run: |
ssh -o ServerAliveInterval=30 -i key.pem -o StrictHostKeyChecking=no \
${{ secrets.USERNAME }}@${{ env.HOST }} << 'EOF'

cd $TARGET_DIR

# 현재 active 확인 (nginx 기준)
if grep -q "8081" /etc/nginx/sites-available/barogagi.xyz; then
TARGET="blue"
else
TARGET="green"
fi

echo "Deploy target: $TARGET"

# 이미지 빌드
docker build -t barogagi-backend:single .

# inactive 컨테이너만 재기동
docker compose up -d backend-$TARGET

# 트래픽 전환
/srv/barogagi/backend/scripts/switch.sh
EOF
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM openjdk:17
FROM eclipse-temurin:17-jdk
WORKDIR /app
COPY *.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
16 changes: 15 additions & 1 deletion src/main/java/com/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
package com;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import org.springframework.context.annotation.Configuration;

@OpenAPIDefinition(
info = @Info(title = "[PROJECT] barogagi API", version = "v1", description = "프로젝트 바로가기 API 명세서")
)

@SecurityScheme(
name = "bearerAuth",
type = SecuritySchemeType.HTTP,
scheme = "bearer",
bearerFormat = "JWT"
)
@SecurityScheme(
name = "apiKeyAuth",
type = SecuritySchemeType.APIKEY,
in = SecuritySchemeIn.HEADER,
paramName = "API-KEY"
)
@Configuration
public class SwaggerConfig {
}
113 changes: 113 additions & 0 deletions src/main/java/com/barogagi/ai/client/AIClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.barogagi.ai.client;

import com.barogagi.ai.dto.AIReqWrapper;
import com.barogagi.ai.dto.AIResDTO;
import com.barogagi.ai.dto.ChatMessage;
import com.barogagi.ai.dto.ChatRequest;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.stream.Collectors;

import static com.barogagi.util.HtmlUtils.stripCodeFence;

@Service
public class AIClient {
private static final Logger logger = LoggerFactory.getLogger(AIClient.class);

@Value("${ai.api.base-url}")
private String aiBaseUrl;

@Value("${ai.api.path}")
private String aiPath;

@Value("${ai.api.key}")
private String aiApiKey;

@Value("${ai.prompt.system}")
private String aiPrompt;

@Value("${ai.model}")
private String aiModel;

private final RestTemplate restTemplate = new RestTemplate();
private static final ObjectMapper OM = new ObjectMapper();

public AIResDTO recommandPlace(AIReqWrapper aiReqWrapper) {
String url = aiBaseUrl + aiPath;

HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(aiApiKey);
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));

ChatRequest chatRequest = buildChatRequest(aiReqWrapper);
HttpEntity<ChatRequest> entity = new HttpEntity<>(chatRequest, headers);

ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.POST,
entity,
String.class
);

String body = response.getBody();

ObjectMapper om = new ObjectMapper();
try {
// 1) content 추출
JsonNode root = om.readTree(body);
JsonNode contentNode = root.path("choices").get(0).path("message").path("content");
String content = contentNode.asText();

// 2) 코드펜스/여분 공백 제거
content = stripCodeFence(content);

// 3) content(JSON 문자열) -> DTO
AIResDTO dto = om.readValue(content, AIResDTO.class);
return dto;

} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
// JsonMappingException 포함해서 모두 여기서 처리됨
return null; // 혹은 throw new IllegalStateException("AI 응답 파싱 실패", e);
}
}

// ai에게 요청 가능한 형태로 변경
private ChatRequest buildChatRequest(AIReqWrapper wrapper) {
// system 메시지
ChatMessage systemMsg = ChatMessage.builder()
.role("system")
.content(aiPrompt)
.build();

// user 메시지: AIReqWrapper → 문자열 변환
StringBuilder sb = new StringBuilder();
sb.append("comment: ").append(wrapper.getComment()).append("\n");
sb.append("tags: ").append(String.join(", ", wrapper.getTags())).append("\n\n");

sb.append("places:\n");
String placesText = wrapper.getPlaceList().stream()
.map(p -> "- title: " + p.getTitle() + "\n description: " + p.getDescription())
.collect(Collectors.joining("\n"));
sb.append(placesText);

ChatMessage userMsg = ChatMessage.builder()
.role("user")
.content(sb.toString())
.build();

return ChatRequest.builder()
.model(aiModel)
.messages(List.of(systemMsg, userMsg))
.max_tokens(500)
.build();
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/barogagi/ai/dto/AIReqDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.barogagi.ai.dto;

import lombok.*;

@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 무분별한 객체 생성 방지
@AllArgsConstructor
@Builder(toBuilder = true)
public class AIReqDTO {
private String title;
private String description;
}
15 changes: 15 additions & 0 deletions src/main/java/com/barogagi/ai/dto/AIReqWrapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.barogagi.ai.dto;
import lombok.*;

import java.util.List;

@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 무분별한 객체 생성 방지
@AllArgsConstructor
@Builder(toBuilder = true)
public class AIReqWrapper {
private List<String> tags;
private String comment;
private List<AIReqDTO> placeList;
}
13 changes: 13 additions & 0 deletions src/main/java/com/barogagi/ai/dto/AIResDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.barogagi.ai.dto;

import lombok.*;

@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 무분별한 객체 생성 방지
@AllArgsConstructor
@Builder(toBuilder = true)
public class AIResDTO {
private Integer recommandPlaceIndex;
private String aiDescription;
}
13 changes: 13 additions & 0 deletions src/main/java/com/barogagi/ai/dto/ChatMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.barogagi.ai.dto;

import lombok.*;

@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 무분별한 객체 생성 방지
@AllArgsConstructor
@Builder(toBuilder = true)
public class ChatMessage {
private String role; // "system" | "user" | "assistant"
private String content; // 메시지 내용
}
16 changes: 16 additions & 0 deletions src/main/java/com/barogagi/ai/dto/ChatRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.barogagi.ai.dto;

import lombok.*;

import java.util.List;

@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 무분별한 객체 생성 방지
@AllArgsConstructor
@Builder(toBuilder = true)
public class ChatRequest {
private String model;
private List<ChatMessage> messages;
private int max_tokens;
}
Loading