AI 기반 맞춤형 추천을 통해 전통주를 접할 수 있는 플랫폼
Yesul은 전통주의 가치를 소개하고 소통할 수 있는 AI 기반 커뮤니티 플랫폼입니다. AI 기반 맞춤형 추천을 통해 전통주를 접하고, 사람들과 여러 정보를 공유하고 소통할 수 있는 공간을 만들어갑니다.
- 🎯 개인화된 접근: AI가 사용자 취향을 반영해 전통주와의 첫 만남을 자연스럽게 연결
- 🔒 안전한 환경: 2FA 기반 인증으로 보안성을 강화한 사용자 보호
- 📱 간편한 사용: 직관적인 UI/UX로 모든 연령대가 쉽게 이용 가능
- 🧩 다양한 기능 제공: 커뮤니티, 1:1 문의 등 소통 중심의 종합 서비스 제공
- Naver ClovaX: AI기반 개인 맞춤형 술 추천 제공
- Role Prompting, CoT Prompting기법: Prompting 기법을 이용한 성능 향상
- 여행지 추천: 술 추천과 질문을 기반으로 한 여행지 추천 기능까지 제공
- 3가지 종류의 커뮤니티: 레시피,정보,자유 게시판을 통한 다양한 술 정보 습득 및 소통 가능
- 1:1 문의: 관리자와의 실시간 채팅을 통한 즉각적인 피드백 반영
- 실시간 알림: 실시간 알림을 통한 사용자간 원활한 상호작용 가능
- 실시간 방문자/접속자 통계: Redis를 활용한 실시간 사용자 트래픽 모니터링
- 관리자 로그인 기록 관리: 관리자 활동 이력을 기록하여 보안성과 운영 투명성 강화
- 서비스 운영 모니터링: 사용자 활동과 서비스 흐름을 실시간으로 확인할 수 있는 대시보드 제공
- 1:1 문의 응대: 관리자 페이지 내 실시간 채팅 기능을 통해 빠르고 효율적인 사용자 대응 가능
- Kakao, Naver로그인: 복잡한 회원가입 없이 간편 시작
- 2FA를 이용한 강력한 보안: Google T-OTP를 통한 2차 보안 기능 제공
- 이메일: 실제 가입하려는 유저의 메일 소유여부 확인으로 보안강화
![]() 이승주 Team Lead, Full Stack Developer 📧 GitHub 1:1 문의 채팅 알림 기능 프로젝트 세팅 및 설계 |
![]() 대태호 Full Stack Developer 📧 GitHub 회원가입 및 로그인 소셜로그인 및 메일 발송 erd 설계 |
![]() 이가영 Full Stack Developer 📧 GitHub 어드민 페이지 개발 실시간 모니터링 기능 OTP 보안 인증 |
![]() 정인용 Full Stack Developer 📧 GitHub AI기반 추천 시스템 메인 페이지 개발 인프라 구축 |
![]() 황정연 Full Stack Developer 📧 GitHub 커뮤니티 기능 댓글 및 좋아요 포인트 기능 |
- Agile development
- 매일 Daily Scrum과 Daily Review를 통해 주기적으로 병합하고,
- 진행상황과 에러를 빠르게 공유하고 인지함
|
|
| 타입 (Type) | 설명 | 브랜치 예시 |
|---|---|---|
feat |
새로운 기능 추가 | feature/1-add-login-function |
fix |
버그 수정 | fix/46-correct-typo |
refactor |
코드 리팩토링 | refactor/789-update-naming-convention |
docs |
문서 수정 | docs/125-update-readme |
chore |
기타 변경 사항 | chore/345-cleanup-code |
- 하루 단위로 작업 가능한 수준으로 작성
예: 로그인 UI 구현, 커뮤니티 작성 기능 추가, 오류 메시지 개선 등
- 세부내용이 정리된 이슈 → 브랜치 생성 후 PR
- 미완성 이슈 → 브랜치에서 작업 후 후속 이슈/PR 처리
| 타입 | 설명 |
|---|---|
feat |
새로운 기능 추가 |
fix |
버그 수정 |
refactor |
코드 리팩토링 (기능 변화 없음) |
docs |
문서 수정 (README 등) |
chore |
빌드 업무, 패키지 매니저 설정 등 기타 수정 |
config |
설정 파일 수정 |
✅ 적절한 필드 네이밍 – messageContext, messageType 등 도메인 관점에서 직관적인 이름
✅ Builder 패턴 + protected 생성자 – 불변성 유지 및 객체 생성 제어
✅ BaseTimeEntity 상속 – createdAt, updatedAt 공통 관리에 적절한 선택
@Entity
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Message extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)
@Column(name = "sender_type", nullable = false)
private Type senderType;
@Column(name = "message_context",length = 5000, nullable = false)
private String messageContext;
@Enumerated(EnumType.STRING)
@Column(name = "message_type", nullable = false, columnDefinition = "TEXT")
private MessageType messageType;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "chatRoom_id", nullable = false)
private ChatRoom chatRoom;
}✅ 좋은 예시 – @Tag, @Operation으로 Swagger 문서화를 통한 API 명세 관리
✅ View 기반의 반환 – REST가 아닌 HTML 렌더링에 맞게 Model 사용
✅ 명확한 역할 분리 – ChatRoomService는 채팅방 조회만 책임, View 로직과 분리됨
@Tag(name = "관리자 채팅방", description = "관리자 채팅방 관련 API")
@Controller
@RequestMapping("/admin/chatroom")
@RequiredArgsConstructor
public class AdminChatRoomController {
private final ChatRoomService chatRoomService;
private final MessageService messageService;
@GetMapping
@Operation(summary = "관리자 기준 채팅방 목록 조회", description = "관리자가 참여하고 있는 채팅방 목록을 조회합니다.")
public String getAdminChatRooms(
@RequestParam(required = false) Long cursor,
@RequestParam(defaultValue = "8") int size,
Model model
) {
AdminChatRoomsResponse response = chatRoomService.getAdminChatRooms(cursor, size);
model.addAttribute("chatRooms", response.getChatRooms());
model.addAttribute("totalUnreadCount", response.getTotalUnreadCount());
model.addAttribute("nextCursor", response.getNextCursor());
return "admin/admin-chat";
}✅ 좋은 예시 – 외부 서비스 연동을 전략화(uploadMode)하여 유연성 확보
✅ 단일 책임 원칙 준수 – 업로드 처리만 책임지고, 실제 구현은 ImageUpload에게 위임
✅ 명확한 예외 처리 – UnsupportedOperationException으로 예외 상황 명시
@Service
@RequiredArgsConstructor
public class ChatImageServiceImpl implements ChatImageService {
private final ImageUpload imageUpload;
@Value("${app.image-upload.mode}")
private String uploadMode;
@Override
public String uploadChatImage(MultipartFile image) {
if ("ncp".equalsIgnoreCase(uploadMode)) {
return imageUpload.uploadAndGetUrl("chat", image);
} else {
throw new UnsupportedOperationException("지원하지 않는 동작입니다.");
}
}
}역할에 따른 명확한 클래스 분리
요청(Request DTO)과 응답(Response DTO)을 별도 클래스로 분리함으로써, 각각의 관심사를 분리

- CI 빌드는 성공했지만 배포 단계에서 오류가 발생했음에도 불구하고
dev브랜치에 병합이 완료됨 - 기존 구조는
dev브랜치가 곧바로 배포 환경으로 연결되어 있어 사전 테스트가 어려운 구조
- ✅ 개발 서버와 운영 서버를 분리
dev브랜치 커밋은 개발 서버에서만 테스트- 배포 성공 시에만 운영 서버에 반영되도록 구성
- 배포 실패 시 운영 서버에는 영향 없음
운영 서버의 안정성을 확보하고, CI/CD 파이프라인에서 병합과 배포를 분리하여 유연한 구조로 개선
- 페이지 로딩이 완료되었음에도 로딩 화면에서 멈춘 채 다음 페이지로 전환되지 않음
fragment와html에 동일한 코드가 중복 적용되면서 렌더링 완료 시점을 인식하지 못함
- ✅ 모든 페이지에 공통 레이아웃(
layout) 템플릿 적용- 중복된 코드 제거
- 필요한 영역만 동적으로 렌더링되도록 수정
- 전체 화면이 정확히 출력된 후 로딩 종료
사용자 경험을 저해했던 무한 로딩 문제 해결, 템플릿 구조를 유지보수하기 쉬운 방식으로 리팩토링
- 게시글 조회 시 연관된 이미지들이 LAZY 로딩되어
post.getImages()호출 시마다 쿼리가 반복 발생 - 실제 운영 환경에서 쿼리 수가 급격히 증가, 성능 저하 유발
- ✅
FETCH JOIN적용@Query에서LEFT JOIN FETCH사용- 게시글과 이미지 정보를 한 번의 쿼리로 조회
- 성능 최적화 + Lazy 예외 방지 + 코드 안정성 확보
JPA의 지연 로딩 이슈에 대해 실제 운영 수준에서 문제를 인지하고 해결한 경험으로 이어짐
- 사용자의 **니즈(추천 + 소통 + 알림)**를 반영한 종합 전통주 플랫폼 기획 및 구현
- AI 추천, 채팅, 커뮤니티, 인증 등 다양한 기술 스택을 유기적으로 연결해 완성도 높은 기능을 제공
- 일일 스크럼 및 회의를 통해 병합 이슈를 빠르게 해결하며 협업 능력과 소통 역량 강화
- 다양한 기술 습득과 구현을 병행하다 보니, 일부 기능의 완성도와 디테일이 부족
- 기획 및 설계 단계에서의 우선순위 및 일정 조율이 미흡하여 구현 단계에서 반복적인 수정과 비효율적인 리팩토링 발생
| 구분 | 설명 | 링크 |
|---|---|---|
| 🔗 Notion | 프로젝트 정리 노션 페이지 | 바로가기 |
| 📋 Sprint Board | 칸반 보드 (Sprint 관리) | 바로가기 |
| 🧭 Milestone & Issue | 마일스톤 및 이슈 관리 페이지 | 바로가기 |
| 🗂 WBS 문서 | 작업 분할 구조 (WBS) | 바로가기 |
| 🗺 ERD | 데이터베이스 설계 (ERDCloud) | 바로가기 |











