본문 바로가기

ABC 부트캠프

[2026 ABC 프로젝트 멘토링 1기] 프로젝트 5주차

📌 회차 정보

  • 기간: 2026.04.30 ~ 2026.05.06 (5주차)
  • 담당 파트: 백엔드 (BE1)
  • 스택: Spring Boot 4.x / Java 21 / PostgreSQL / JPA

마감이 코앞이다 (5/10). 남은 시간 4일.

이번 주는 새 기능을 추가하기보다 지금까지 만들어둔 걸 다듬고 마무리하는 한 주였다. 그래서 글도 회고 느낌으로 써본다. 기능 진행 상황 한번 정리하고, 남은 며칠 동안 뭘 끝내야 하는지 점검하는 글.


1. 들어가기 전에

이번 회차부터는 포맷이 살짝 바뀌었다. 원래는 "기본 기능 개발 및 코드 리뷰"였는데, 이제 거의 다 만들어진 상태라서 "프로젝트 심화 작업"으로 넘어왔다.

심화 작업은 이렇게 3가지로 나눠진다.

  • 기능 개발 진행 상황 점검
  • 추가 기능 개발 및 테스트
  • 성능 최적화 및 문제 해결

이번 글은 그중에 1번, 진행 상황 점검 위주로 정리한다. 나머지 두 개는 마감 직전이라 다음 회차나 회고 글에서 다룰 예정.


2. 기능 개발 진행 상황 점검

끝난 것 (백엔드 기준)

지난 4주차 글에서도 정리했지만, 그 사이에도 몇 개 더 마무리됐다.

기능 상태

회원가입 / 로그인 (이메일 + 카카오) ✅
JWT 인증 (Access / Refresh) ✅
이메일 인증번호 비밀번호 재설정 ✅
일기 CRUD ✅
중간기록(Segment) CRUD + 순서 변경 ✅
이미지 업로드 ✅
리포트 조회 ✅
사용자 설정 CRUD ✅
글로벌 예외 처리 ✅
.env.example 템플릿 ✅
인증 시퀀스 다이어그램 ✅
user_id 타입 SERIAL로 수정 ✅
다중 이미지 저장 구조 (diary_images 분리) ✅
OpenRouter 비교 테스트 (1차) ✅

API 명세상의 기능은 사실상 다 박힌 상태다.

진행 중인 것

작업 상태

자정 기준 최종 일기 자동 생성 (@Scheduled) 🔄
OpenRouter 최종 모델 선정 🔄 (고민 중)
프롬프트 튜닝 🔄
Flyway 도입 (DB 버전 관리) 🔄

아직 안 한 것

작업 상태

알림 서비스 (FCM 푸시) ⏳
배포 ( 확정 아님)  ⏳

 


3. 이번 주 메인 — OpenRouter 모델 결정, 아직도 못 했다

지난 회차에서 "다음 주에 OpenRouter로 본격 비교 테스트"라고 호기롭게 적어놨었는데, 막상 돌려보니까 결정이 더 어려워졌다.

후보로 좁힌 모델

원래는 GPT, Claude, Gemini 다 본다고 했는데 시간 부족으로 두 개로 좁혔다.

  • GPT-4o
  • Claude 3.5 Sonnet

Gemini는 처음에 한 번 돌려봤는데 노년층 말투에서 살짝 어색해서 일단 제외. (어디서 본 보고서 같은 톤이 자꾸 나옴)

비교 결과 — 품질

같은 입력에 같은 프롬프트로 여러 번 돌려봤다.

입력 예시

{
  "최종_기분": "평온해요",
  "중간_일기들": [
    { "기분": "최고에요", "장소": "대청호", "시간": "오후 2시" },
    { "기분": "평온해요", "장소": "동네 공원", "시간": "오후 5시" }
  ]
}

프롬프트 (요약)

당신은 65세 이상 노년층이 직접 쓴 듯한 일기를 정리해주는 어시스턴트입니다.
- 반말 일기체 (~했다, ~였다)
- 어려운 표현 X
- 따뜻하고 담담한 톤으로 3~5문장

GPT-4o 응답 (대표 케이스)

오늘은 평온한 하루였다. 오후에 대청호에 다녀왔는데 오랜만에 보는 호수가 참 시원했다. 햇살도 좋고 바람도 부드러웠다. 5시쯤엔 동네 공원을 천천히 한 바퀴 돌았다. 이런 날이 자주 있으면 좋겠다.

Claude 3.5 Sonnet 응답 (대표 케이스)

오늘 오후에 대청호에 다녀왔다. 호수를 보니 마음이 편안해졌다. 저녁때쯤 동네 공원도 한 바퀴 돌았다. 날씨도 좋고 발걸음도 가벼웠다. 평온한 하루였다.

둘 다 잘 쓴다. 미묘한 차이를 짚어보면,

  • GPT-4o: 묘사가 좀 더 풍성함. "햇살도 좋고 바람도 부드러웠다" 같은 디테일이 자연스럽게 들어감. 가끔 길어지는 게 단점.
  • Claude 3.5 Sonnet: 더 담담하고 짧음. 노년층 일기 톤에 더 가까운 것 같기도 함. 근데 가끔 너무 건조하게 끝나는 경우도 있음.

진짜 둘 다 좋아서 결정하기가 어렵다.

비교 결과 — 비용

OpenRouter 기준 (2026년 5월 시점, 1M 토큰):

모델 Input Output

GPT-4o $2.50 $10.00
Claude 3.5 Sonnet $3.00 $15.00

Claude가 좀 더 비싸다. 근데 우리 서비스는 자정에 한 번만 호출하는 구조라 일일 호출 횟수가 적어서, 사용자 수가 폭증하지 않는 한 차이가 크진 않을 듯.

그래서 결론은?

아직 못 정함.

품질이 거의 비슷해서 솔직히 동전 던지기 수준이다. 일단 다음 회차까지 며칠 더 굴려보고 결정할 예정. 그 사이 프롬프트도 좀 더 다듬어보면 둘 중에 하나가 확실히 튀어나오지 않을까 싶음.


4. 자정 스케줄러 — 진행 중

원래는 사용자가 직접 "오늘의 최종 일기" 버튼을 눌러야 그날 일기가 마무리됐는데, 회의 피드백에 따라 자정에 자동으로 합치는 로직으로 바꾸는 중이다.

뼈대는 이런 구조.

@Component
@RequiredArgsConstructor
public class DiaryAutoCloseScheduler {

    private final DiaryRepository diaryRepository;
    private final SegmentRepository segmentRepository;
    private final AiDiaryService aiDiaryService;

    /**
     * 매일 자정에 실행.
     * 어제 작성된 중간기록(Segment)들을 모아서 최종 일기로 자동 생성.
     */
    @Scheduled(cron = "0 0 0 * * *", zone = "Asia/Seoul")
    @Transactional
    public void autoCloseYesterdayDiaries() {
        LocalDate yesterday = LocalDate.now().minusDays(1);

        List<Diary> draftDiaries = diaryRepository.findAllByDateAndStatus(
            yesterday, DiaryStatus.DRAFT
        );

        for (Diary diary : draftDiaries) {
            List<Segment> segments = segmentRepository.findAllByDiaryId(diary.getId());
            if (segments.isEmpty()) continue; // 중간 기록이 없으면 스킵

            String aiDraft = aiDiaryService.generateFinalDraft(segments);
            diary.finalize(aiDraft); // 상태: DRAFT → ANALYZED
        }
    }
}

지금 신경 쓰는 포인트는 두 가지.

  1. 중간기록이 0개인 날 처리 — 그냥 스킵하기로 함. 빈 일기 만들면 사용자가 더 헷갈릴 듯.
  2. 시간대 문제 — 서버 시간이 UTC면 한국 자정에 안 돌아가니까 zone = "Asia/Seoul" 명시.

아직 동시성 이슈 (같은 일기를 여러 번 자동 생성하는 경우)는 안 잡았다. 단일 인스턴스로 돌릴 거라서 일단 큰 문제는 없을 듯한데, 나중에 인스턴스 늘릴 거면 분산 락 같은 거 고민해야 할 것 같다.


5. 이번 주 배운 점

1) "거의 다 됐다"가 제일 위험한 말

지난 주에 "기능은 거의 다 만들어둔 상태"라고 적었는데, 막상 마감 직전에 보니까 디테일에서 손댈 게 한참 남아있었다. 자정 스케줄러도 코드 자체는 한 시간이면 박는데, 시간대 처리, 동시성, 예외 처리 같은 거 신경 쓰면 하루는 그냥 가더라.

기능 90%랑 100%의 거리는 진짜 멀다.

2) AI 모델 선택은 생각보다 어려운 의사결정

처음엔 단순히 "더 좋은 거 고르면 되지" 싶었는데, 막상 두 모델이 비등비등하니까 결정이 어렵다. 응답을 수십 번 비교해도 객관적 지표가 없으니까 결국 감으로 골라야 함.

이게 사실 ML 쪽에서 평가셋이 왜 그렇게 중요한지 체감되는 순간이었다. "노년층스러움"을 점수로 매길 수 있는 평가 기준이 있었으면 훨씬 빨리 결정했을 듯.

3) 마감 앞두고 새 기능 욕심내면 안 됨

"이거 하나만 더 넣자" 싶은 게 자꾸 떠오른다. 근데 알림이랑 배포가 통째로 남아있는 상황이라 욕심 다 접고 마감 모드로 들어가야 함. 지금 손대면 안 되는 거 안 건드리는 것도 능력이라는 걸 실감 중.


6. 남은 4일 계획

마감 5/10까지. 우선순위 다시 정리.

순위 작업 예상 소요

1 OpenRouter 모델 최종 결정 + 프롬프트 확정 1일
2 자정 스케줄러 마무리 + 테스트 1일
3 프론트 연동 최종 점검 1일
4 배포 (아직 확정 중)  1일
5 알림 서비스 (구현 중)   

 


마무리

기능 개발은 1~3주차에 거의 끝났고, 4~5주차는 다듬고 결정하는 시간이었다. 코드 박는 양이 줄었다고 시간이 남는 건 절대 아니라는 걸 매주 새로 배우고 있다.

다음 회차는 마감 직후에 쓰는 회고 글이 될 것 같다. 모델 결정이랑 배포 결과 들고 돌아오겠습니다.


#SpringBoot #OpenRouter #스케줄러 #JWT #백엔드 #테크노트 #개발일지 #abc프로젝트멘토링