SelfCheck_AI 7.개발 일지 (26.01.22 ~ 26.01.25)

Meustar·2026년 1월 25일

Project

목록 보기
8/15

지난 포스팅에서는 프로젝트 초기 세팅과 트러블슈팅을 다뤘습니다. 이번에는 1월 22일부터 25일까지 진행된 자소서 첨삭 기능의 백엔드 개발 전체 과정을 기록합니다.
Mock API 설계, MyBatis DB 연동, OpenAI(GPT) 실연동, 그리고 Spring AI 리팩토링까지의 여정을 상세히 담았습니다.


📅 주간 개발 타임라인

1월 22일 (수) - 1월 24일 (금): Mock API 구현 & DB 설계

  • Goal: 프론트엔드 팀원이 작업할 수 있도록 API 껍데기(Mock)를 제공하고, 데이터를 저장할 DB 구조를 잡는다.
  • Key Tasks:
    • DTO (ResumeRequest, ResumeResponse) 설계
    • ResumeController 구현 (POST /api/resumes)
    • PostgreSQL resumes 테이블 생성
    • MyBatis 설정 및 ResumeMapper 구현

1월 25일 (토): OpenAI 연동 & 리팩토링

  • Goal: 가짜 데이터 대신 실제 AI를 연동하고, 코드를 깔끔하게 다듬는다.
  • Key Tasks:
    • Spring AI 라이브러리 도입 및 설정
    • 프롬프트 엔지니어링 (시스템 페르소나 부여, JSON 출력 강제)
    • AiClient 모듈 분리 (리팩토링)
    • 각종 예외 처리 및 트러블슈팅 (429 Quota Exceeded, PromptTemplate 오류 등)

🚀 1. 핵심 기능 구현 과정

Step 1. DTO 설계 (데이터 주고받기)

먼저 클라이언트(프론트)와 어떤 데이터를 주고받을지 정의했습니다. Java 17의 record를 사용하여 불변(Immutable) 객체로 간결하게 선언했습니다.

// 요청: 사용자의 질문과 답변
public record ResumeRequest(
    String question,
    String answer
) {}

// 응답: AI가 분석한 점수와 피드백 리스트
public record ResumeResponse(
    Map<String, Integer> score,       // 4가지 평가 항목별 점수
    List<Map<String, String>> feedback // 구체적인 피드백 내용
) {}

Step 2. MyBatis로 DB 연동하기

JPA 대신 SQL을 명시적으로 제어할 수 있는 MyBatis를 선택했습니다. AI 분석 요청이 들어오면, 분석 전에 원본 데이터를 DB에 먼저 저장합니다.

DB 스키마 (PostgreSQL)

CREATE TABLE resumes (
    id              BIGSERIAL PRIMARY KEY,
    user_id         BIGINT,
    question        TEXT,
    original_content TEXT,
    created_at      TIMESTAMP DEFAULT NOW()
);

Mapper XML
(ResumeMapper.xml) 단순한 INSERT 문이지만, useGeneratedKeys="true" 옵션을 사용하여 저장된 직후 생성된 PK(id)를 바로 받아오도록 처리했습니다.


<insert id="saveResume" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO resumes (user_id, question, original_content)
    VALUES (#{userId}, #{question}, #{content})
</insert>

Step 3. Spring AI로 OpenAI 연동하기

가장 중요한 AI 연동 부분입니다. Spring AI의 ChatClient를 사용했습니다.

💡 프롬프트 엔지니어링 (Prompt Engineering)
단순히 "첨삭해줘"라고 하면 AI가 제멋대로 답합니다. 정확한 JSON 포맷으로 응답받기 위해 시스템 메시지를 정교하게 깎았습니다.

  1. 페르소나 부여: "20년 경력의 IT 인사 담당자"
  2. 평가 기준 명시: 직무 적합성, 문제 해결력, 성장 가능성, 의사소통 (4개 항목)
  3. 출력 형식 강제: "반드시 아래 JSON 형식으로만 응답하라"

Step 4. 리팩토링: AiClient 분리

초기에는 ResumeService 안에 DB 저장 로직과 AI 호출 로직이 섞여 있었습니다. 단일 책임 원칙(SRP)을 지키기 위해, AI 관련 로직만 전담하는 AiClient 클래스를 별도로 분리했습니다.

  • ResumeService: 전체 흐름 제어 (DB 저장 호출 → AI 분석 호출)
  • AiClient: 프롬프트 관리, OpenAI API 호출, JSON 파싱, AI 전용 예외 처리
profile
유튜브 기술 영상을 보면서 잘 이해하기 위해... Lilys AI를 활용해 배경지식, 영상 전체 요약 및 핵심 내용 설명들을 블로깅 합니다. 작성한 내용들에 대해서 언제고 다시 "내가" 찾아 볼 수 있도록 기록으로 남깁니다!

0개의 댓글