From 74a2bffba0185a8cef096e052cd6010a8672213e Mon Sep 17 00:00:00 2001 From: hyein Heo <128613248+hye-inA@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:20:05 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat=20:=20=EC=B5=9C=EC=8B=A0=20develop=20?= =?UTF-8?q?=EB=B8=8C=EB=9E=9C=EC=B9=98=20=20main=20=EB=B3=91=ED=95=A9=20?= =?UTF-8?q?=20(#141)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [FEAT] 메인 레이아웃 구현 - Header: 로고, 네비게이션, 프로필 드롭다운, 알림, 다크모드 토글 - Sidebar: 학습 모드 메뉴, 접기/펼치기, 반응형 - Footer: 저작권, 링크 - MainLayout: Header + Sidebar + Content + Footer 통합 - ThemeContext: 다크모드 지원 - Dashboard: 학습 모드 카드 UI * [FEAT] Sidebar 메뉴 계층 구조 개선 - 영어공부: OPIC 연습, 작문 연습 하위 메뉴 추가 - 프리토킹: 사람들과, AI와 하위 메뉴 추가 - 하위 메뉴 접기/펼치기 기능 (Collapse) - 펼침 상태 localStorage 저장 - Dashboard 학습 모드 카드 업데이트 (3개로 변경) - Dashboard 이모지 제거 * [FEAT] 면접 시뮬레이션 메뉴 제거 * [FEAT] 프리토킹(사람들과) 채팅방 리스트 페이지 구현 - ChatRoomCard 컴포넌트 추가 - FreetalkPeoplePage 페이지 구현 - 레벨 필터링, 검색 기능 추가 - 더미 데이터로 UI 테스트 * [FEAT] Sidebar 메뉴 카테고리 구조 변경 - 영어공부/프리토킹 -> 말하기연습/쓰기연습으로 최상단 카테고리 변경 - 말하기연습: 오픽연습, AI와 말해보기 - 쓰기연습: 사람들과 채팅하기, 작문연습 - localStorage 기본 펼침 상태 키 업데이트 - 관련 아이콘 변경 (Mic, Create) Closes #28 * [FEAT] Dashboard 카드 카테고리 구조 변경 - 영어공부/프리토킹 -> 말하기연습/쓰기연습으로 변경 - 말하기연습: 오픽연습, AI와 말해보기 - 쓰기연습: 사람들과 채팅하기, 작문연습 - 카드 설명 문구 업데이트 * [FEAT] Dashboard 카드 호버 시 하위 카테고리 표시 - 클릭 방식에서 호버 방식으로 변경 - onMouseEnter/onMouseLeave 이벤트 적용 * [FIX] Dashboard 카드 레이아웃 Grid로 변경 - flexbox에서 Grid 레이아웃으로 변경하여 호버 시 레이아웃 깨짐 방지 - 카드 width 고정으로 안정적인 반응형 지원 * [FEAT] ChatRoomCard 높이 일정하게 변경 - height: 100%로 Grid 내 카드 높이 통일 - flexbox 레이아웃 적용으로 내부 콘텐츠 균일 배치 * [FIX] ChatRoomCard 가로/세로 크기 통일 - Grid item에 display: flex, alignItems: stretch 적용 - Card에 width: 100% 추가 * [FIX] ChatRoomCard 고정 높이 적용 - height: 160px로 모든 카드 크기 통일 - 내용 길이에 관계없이 일정한 카드 크기 유지 Closes #31 * [FIX] ChatRoomCard 참여자 프로필 제거 및 너비 고정 - 참여자 아바타 그룹 제거 - 너비 300px, 높이 140px로 고정 * [FIX] ChatRoomCard 레이아웃 개선 - 높이 100px로 축소 - 생성일을 마지막 대화 옆으로 이동 - 생성일 날짜만 표시 (시간 제거) * [FIX] 생성일 라벨 추가 * [FEAT] ChatRoomCard UI 개선 - 입장 버튼 추가 (우측 상단, outlined 스타일) - 비밀방 자물쇠 아이콘 표시 - 간단한 소개 표시 추가 - 생성일자 하단에 표시 - 카드 높이 140px로 조정 - 더미 데이터에 description, createdAt, isPrivate 추가 * [FEAT] 채팅방 입장 모달 및 필터 추가 - 입장 버튼 클릭 시 모달 팝업 - 일반방: 방 정보 확인 후 입장 - 비밀방: 비밀번호 입력 후 입장 - 참여중 필터 추가 (레벨 필터 옆) - 생성일 형식 변경 (연/월/일) - 더미 데이터에 isJoined 필드 추가 * [FEAT] Chat API 연동 기반 구축 - .env.example 추가 (환경변수 템플릿) - VITE_CHAT_API_URL, VITE_TEMP_USER_ID 환경변수 설정 - chatApi axios 인스턴스 생성 - chatRoomService 구현 (create, getList, getDetail, join, leave) - messageService 구현 (send, getList) - voiceService 구현 (synthesize) Closes #38, #39 * [FEAT] 채팅방 목록/생성/입장 API 연동 및 채팅 UI 구현 - FreetalkPeoplePage: mock 데이터 제거, API 연동 (무한스크롤) - CreateRoomModal: 채팅방 생성 모달 컴포넌트 추가 - ChatRoomPage: 카카오톡 스타일 채팅 UI 구현 - 메시지 조회/전송 API 연동 - TTS 재생 버튼 구현 Closes #40, #41, #42, #43, #44, #45 * [FEAT] 전역 채팅 모달 및 TTS 기능 구현 - ChatContext를 통한 전역 채팅 상태 관리 - 드래그 가능한 플로팅 채팅 모달 구현 - 최소화/최대화 기능 추가 - 모든 메시지 TTS 재생 기능 - 페이지 이동 시에도 채팅 유지 - Redux store 초기화 오류 수정 - 스크롤바 hover 시에만 표시 * [FIX] 채팅 모달 최소화 시 우측 하단 이동 - 최소화 시 현재 위치 저장 후 우측 하단으로 자동 이동 - 최대화 시 저장된 위치로 복원 Closes #47 * [FEAT] TTS 음성 선택 기능 구현 - SettingsContext 추가 (localStorage 저장) - 설정 페이지에 음성 선택 UI 추가 (MALE/FEMALE) - voiceService에 voice 파라미터 추가 - ChatRoomModal에서 선택된 음성으로 TTS 재생 Closes #49 * [CR] TTS API 변경 대응 (#53) - voiceService.synthesize: text -> messageId, roomId 파라미터 변경 - ChatRoomPage, ChatRoomModal handlePlayTTS 수정 - 백엔드 API 스펙 변경에 따른 필수 대응 * [FIX] 채팅 모달 최소화 후 펼칠 때 스크롤 맨 아래로 유지 (#55) * [FEAT] Vocab API 서비스 레이어 구축 (#58) (#99) - Vocab axios 인스턴스 설정 (#64) - 단어 관리 API 서비스 구현 (#65) - 일일 학습 API 서비스 구현 (#66) - 사용자 단어 상태 API 서비스 구현 (#67) - 시험 API 서비스 구현 (#68) - 통계 API 서비스 구현 (#69) - TTS API 서비스 구현 (#70) - 상수 정의 (레벨, 카테고리, 상태 등) * [FEAT] 단어 학습 대시보드 구현 (#59) (#100) - VocabDashboard 페이지 컴포넌트 생성 (#71) - 오늘의 학습 진행률 카드 구현 (#72) - 퀵 액션 카드 (통계, 시험, 단어장) 구현 (#73) - 주간 학습 캘린더 컴포넌트 구현 (#74) - 약점 단어 리스트 컴포넌트 구현 (#75) - /vocab 라우팅 및 사이드바/메인 대시보드 메뉴 추가 - 하위 메뉴: 단어 외우기, 시험 보기, 단어장 * [FEAT] 일일 학습 (플래시카드) 구현 (#60) (#101) - DailyLearning 페이지 컴포넌트 생성 (#76) - FlashCard 컴포넌트 구현 - flip 애니메이션 (#77) - 학습 진행률 바 및 상태 관리 (#78) - 정답/오답 버튼 및 API 연동 (#79) - 북마크/난이도 태그 기능 구현 (#80) - 학습 완료 화면 구현 (#81) - /vocab/daily 라우팅 추가 * [FEAT] 단어 시험 기능 구현 (#61) (#102) - TestPage 컴포넌트 생성 - 시험 설정 화면 (#82) - TestQuestion 컴포넌트 구현 - 4지선다 문제 (#83) - 시험 진행 상태 관리 - 타이머, 현재 문제 (#84) - 답안 제출 및 결과 처리 (#85) - 시험 결과 화면 구현 (#86) - /vocab/test 라우팅 추가 * [FEAT] 단어장 (Word List) 기능 구현 (#62) (#104) - WordListPage: 검색, 필터, 무한 스크롤 지원 - WordListItem: 단어 목록 아이템 컴포넌트 - WordDetailModal: 단어 상세 모달 (TTS, 북마크, 난이도 설정) - 검색 입력 디바운스 (300ms) - 레벨/카테고리/상태/북마크 필터 - Intersection Observer 기반 무한 스크롤 - /vocab/words 라우트 추가 * [FEAT] 학습 통계 페이지 구현 (#63) (#105) - StatsPage 메인 컴포넌트 - LearningCalendar 히트맵 (12주) - WeakWordsList 취약 단어 TOP 10 - DifficultyChart 난이도 분포 막대 그래프 - LevelProgressChart 레벨별 진행률 - 일/주/월별 통계 탭 - /vocab/stats 라우트 추가 * [FEAT] 단어장 학습 통계 및 UI/UX 개선 (#57, #63) (#106) * [FEAT] 학습 통계 페이지 구현 (#63) - StatsPage 메인 컴포넌트 - LearningCalendar 히트맵 (12주) - WeakWordsList 취약 단어 TOP 10 - DifficultyChart 난이도 분포 막대 그래프 - LevelProgressChart 레벨별 진행률 - 일/주/월별 통계 탭 - /vocab/stats 라우트 추가 * [FIX] API 응답 구조 수정 - interceptor 중복 .data 접근 제거 - vocabApi interceptor가 response.data 반환하므로 - 각 페이지에서 response?.data 대신 response 직접 접근으로 수정 - 영향: TestPage, DailyLearning, VocabDashboard, WordListPage, StatsPage * [FIX] 누락된 서비스 메서드 추가 - wordService.getWords 추가 - userWordService.getUserWords 추가 - userWordService.updateUserWord 추가 * [FEAT] API 변경사항 반영 (#44, #45) - Daily Study API: level 파라미터 추가 - 레벨 선택 UI 추가 (BEGINNER/INTERMEDIATE/ADVANCED) - 첫 호출 시 레벨 선택 화면 표시 - Test Start API: options 필드 대응 - TestQuestion에서 question.english 사용 - example 문장 표시 추가 * [DOCS] Add issue and branch management guide * feat(grammar): 문법 검사 페이지 UI 구현 (#120) * feat(grammar): 문법 교정 기능 구현 (#113, #114, #115, #116, #117, #118, #119) - Grammar API 서비스 모듈 생성 (grammarApi.js) - Grammar 서비스 레이어 생성 (grammarService.js) - grammarCheckService: 문법 검사 API - conversationService: 대화형 교정 API - sessionService: 세션 관리 API - GrammarErrorType 상수 정의 (grammarConstants.js) - 12종 오류 타입 (VERB_TENSE, ARTICLE 등) - 레벨별 색상 및 라벨 - i18n 번역 키 추가 (한국어/영어) - GrammarInput 컴포넌트 구현 - 레벨 선택 UI (초급/중급/고급) - 텍스트 입력 및 검사 버튼 - GrammarResult 컴포넌트 구현 - 점수 표시 및 등급 - 오류 하이라이팅 - 교정 피드백 표시 - WritingPage 컴포넌트 구현 - /writing 라우트 연결 * feat(grammar): 채팅형 인터페이스로 리디자인 - ChatMessage 컴포넌트 구현 - 사용자/AI 메시지 버블 구분 - 문법 점수 배지 표시 - 오류 상세 정보 접기/펼치기 - SessionSidebar 컴포넌트 구현 - 세션 목록 표시 - 세션 생성/선택/삭제 - 레벨별 색상 태그 - ChatInput 컴포넌트 구현 - 레벨 선택 드롭다운 - 텍스트 입력 및 전송 - WritingPage 채팅형 레이아웃 적용 - 좌측 사이드바 + 채팅 영역 - 반응형 (모바일 드로어) - conversation API 연동 * [FEAT] 배지 시스템 구현 (#121, #122) (#126) * [FEAT] 배지 시스템 구현 (#121, #122, #123, #124, #125) - Badge API 서비스 모듈 구현 (badgeApi.js, badgeService.js) - Badge 상수 정의 (배지 타입, 카테고리, 색상) - BadgeCard 컴포넌트: 획득/미획득 스타일 (그레이스케일+블러) - BadgeGrid 컴포넌트: 반응형 그리드 레이아웃 - BadgeSection 컴포넌트: 리포트 페이지용 섹션 - 통계 페이지에 배지 섹션 통합 - i18n 다국어 지원 (한/영) Features: - 획득 배지: 컬러 표시 - 미획득 배지: 그레이스케일 + 블러 + 잠금 아이콘 - 마우스 호버: 배지 상세 정보 툴팁 - 진행률 표시 (progress/threshold) * [FIX] 배지 더미 이미지 URL 수정 - S3 URL을 Flaticon CDN 이미지로 교체 (실제 이미지 표시) - 각 배지 카테고리별 아이콘 적용 * [FEAT] 리포트 페이지 구현 및 배지 섹션 통합 - ReportsPage placeholder를 실제 구현으로 교체 - 학습 통계 요약 카드 (학습일, 단어, 테스트, 점수) - 연속 학습 기록 섹션 - BadgeSection 통합 - 상세 통계 페이지 링크 - 더미 데이터로 UI 확인 가능 * [FIX] 리포트 페이지에서 상세 통계 버튼 제거 * [FEAT] 문법 교정 채팅 스트리밍 UI 구현 (#128) (#130) - WritingPage에 WebSocket 스트리밍 통합 - ChatMessage에 타이핑 애니메이션 효과 추가 - 실시간 AI 응답 표시 기능 - 커서 깜빡임 애니메이션 적용 * [FEAT] Grammar WebSocket 스트리밍 서비스 구현 (#127) (#129) - grammarStreamService.js: WebSocket 연결/메시지 관리 - 싱글톤 패턴으로 연결 관리 - Mock 스트리밍 모드 (테스트용) - 이벤트 핸들링 (start, token, complete, error) - useGrammarStream.js: React 상태 관리 훅 - 스트리밍 상태 관리 (isStreaming, streamingText) - 연결 상태 관리 (connect, disconnect) - 결과 상태 (grammarCheck, aiResponse, conversationTip) - index.js: 서비스 및 훅 export 추가 * feature : jira issue, PR 연동 workflow 작성 (#131) * refactor : jira issue, pr workflow refactorting (#133) * feature : jira issue, PR 연동 workflow 작성 * refactor : pr, issue 연동 workflow 리펙토링 * [REFACTOR] Adjust code formatting for improved readability and consistent styling - Applied updated formatting rules across `MainLayout`, `chatApi`, `vocabApi`, `axios`, and `App` components - Standardized spacing, indentation, and import organization * feat : issue 수정/병합시 JIra에 반영 workflow 코드 추가 (#134) * feature : jira issue, PR 연동 workflow 작성 * refactor : pr, issue 연동 workflow 리펙토링 * feat : 수정/병합시 Jira 업데이트 workflow 코드 추가 * refactor : Update Jira Issue 단계 환경변수 설정 리팩토링 (#140) * feature : jira issue, PR 연동 workflow 작성 * refactor : pr, issue 연동 workflow 리펙토링 * feat : 수정/병합시 Jira 업데이트 workflow 코드 추가 * refactor : Update Jira Issue 단계 환경변수 설정 리팩토링 --------- Co-authored-by: ddingjoo --- .github/workflows/github-jira-issue-sync.yml | 3 ++- .github/workflows/github-jira-pr-sync.yml | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github-jira-issue-sync.yml b/.github/workflows/github-jira-issue-sync.yml index 21d30e9..46c55a6 100644 --- a/.github/workflows/github-jira-issue-sync.yml +++ b/.github/workflows/github-jira-issue-sync.yml @@ -289,11 +289,12 @@ jobs: JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + DESC_JSON: ${{ steps.parse.outputs.description }} with: script: | const jiraKey = '${{ steps.get-jira-key.outputs.jira_key }}'; const issue = context.payload.issue; - const descContent = ${{ steps.parse.outputs.description }}; + const descContent = JSON.parse(process.env.DESC_JSON); const response = await fetch( `${process.env.JIRA_BASE_URL}/rest/api/3/issue/${jiraKey}`, diff --git a/.github/workflows/github-jira-pr-sync.yml b/.github/workflows/github-jira-pr-sync.yml index f1d3aea..5f7747b 100644 --- a/.github/workflows/github-jira-pr-sync.yml +++ b/.github/workflows/github-jira-pr-sync.yml @@ -204,11 +204,13 @@ jobs: JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + DESC_JSON: ${{ steps.parse.outputs.description }} + with: script: | const jiraKey = '${{ steps.get-jira-key.outputs.jira_key }}'; const pr = context.payload.pull_request; - const descContent = ${{ steps.parse.outputs.description }}; + const descContent = JSON.parse(process.env.DESC_JSON); const response = await fetch( `${process.env.JIRA_BASE_URL}/rest/api/3/issue/${jiraKey}`, From 1d40e6b25c9dcf08cf2972654aae2bc64867c0dd Mon Sep 17 00:00:00 2001 From: ddingjoo Date: Thu, 22 Jan 2026 17:01:44 +0900 Subject: [PATCH 2/2] [FIX] Add fallback to VITE_API_URL for chat and vocab APIs --- src/api/chatApi.js | 2 +- src/api/vocabApi.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/chatApi.js b/src/api/chatApi.js index 0c79422..a41d0fe 100644 --- a/src/api/chatApi.js +++ b/src/api/chatApi.js @@ -1,7 +1,7 @@ import axios from 'axios' const chatApi = axios.create({ - baseURL: import.meta.env.VITE_CHAT_API_URL, + baseURL: import.meta.env.VITE_CHAT_API_URL || import.meta.env.VITE_API_URL, timeout: 10000, headers: { 'Content-Type': 'application/json', diff --git a/src/api/vocabApi.js b/src/api/vocabApi.js index 8ab1c6f..0c78af4 100644 --- a/src/api/vocabApi.js +++ b/src/api/vocabApi.js @@ -1,7 +1,7 @@ import axios from 'axios' const vocabApi = axios.create({ - baseURL: import.meta.env.VITE_VOCAB_API_URL, + baseURL: import.meta.env.VITE_VOCAB_API_URL || import.meta.env.VITE_API_URL, timeout: 10000, headers: { 'Content-Type': 'application/json',